summary refs log tree commit diff
path: root/src/settings/plugins/keyfile
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2017-05-11 14:55:55 +0200
committerMichael Biebl <biebl@debian.org>2017-05-11 14:55:55 +0200
commitc333f062ddcba9b35330647bf6cbd0a07f2d786e (patch)
tree257c3a0c74c09f4ad2328eab5b932806405f0c1c /src/settings/plugins/keyfile
parenta222e56e103f949b148a6942e385ccca2c26d9f3 (diff)
New upstream version 1.8.0 upstream/1.8.0
Diffstat (limited to 'src/settings/plugins/keyfile')
-rw-r--r--src/settings/plugins/keyfile/nms-keyfile-connection.c16
-rw-r--r--src/settings/plugins/keyfile/nms-keyfile-plugin.c13
-rw-r--r--src/settings/plugins/keyfile/nms-keyfile-reader.c28
-rw-r--r--src/settings/plugins/keyfile/nms-keyfile-reader.h7
-rw-r--r--src/settings/plugins/keyfile/nms-keyfile-writer.c94
-rw-r--r--src/settings/plugins/keyfile/nms-keyfile-writer.h6
-rw-r--r--src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection2
-rw-r--r--src/settings/plugins/keyfile/tests/test-keyfile.c101
8 files changed, 232 insertions, 35 deletions
diff --git a/src/settings/plugins/keyfile/nms-keyfile-connection.c b/src/settings/plugins/keyfile/nms-keyfile-connection.c
index ff654acf..bd07d263 100644
--- a/src/settings/plugins/keyfile/nms-keyfile-connection.c
+++ b/src/settings/plugins/keyfile/nms-keyfile-connection.c
@@ -58,12 +58,16 @@ commit_changes (NMSettingsConnection *connection,
 {
 	char *path = NULL;
 	GError *error = NULL;
+	gs_unref_object NMConnection *reread = NULL;
+	gboolean reread_same = FALSE;
 
 	if (!nms_keyfile_writer_connection (NM_CONNECTION (connection),
 	                                    nm_settings_connection_get_filename (connection),
 	                                    NM_FLAGS_ALL (commit_reason,   NM_SETTINGS_CONNECTION_COMMIT_REASON_USER_ACTION
 	                                                                 | NM_SETTINGS_CONNECTION_COMMIT_REASON_ID_CHANGED),
 	                                    &path,
+	                                    &reread,
+	                                    &reread_same,
 	                                    &error)) {
 		callback (connection, error, user_data);
 		g_clear_error (&error);
@@ -89,6 +93,18 @@ commit_changes (NMSettingsConnection *connection,
 		             NMS_KEYFILE_CONNECTION_LOG_ARG (connection));
 	}
 
+	if (reread && !reread_same) {
+		gs_free_error GError *local = NULL;
+
+		if (!nm_settings_connection_replace_settings (connection, reread, FALSE, "update-during-write", &local)) {
+			nm_log_warn (LOGD_SETTINGS, "keyfile: update "NMS_KEYFILE_CONNECTION_LOG_FMT" after persisting connection failed: %s",
+			             NMS_KEYFILE_CONNECTION_LOG_ARG (connection), local->message);
+		} else {
+			nm_log_info (LOGD_SETTINGS, "keyfile: update "NMS_KEYFILE_CONNECTION_LOG_FMT" after persisting connection",
+			             NMS_KEYFILE_CONNECTION_LOG_ARG (connection));
+		}
+	}
+
 	g_free (path);
 
 	NM_SETTINGS_CONNECTION_CLASS (nms_keyfile_connection_parent_class)->commit_changes (connection,
diff --git a/src/settings/plugins/keyfile/nms-keyfile-plugin.c b/src/settings/plugins/keyfile/nms-keyfile-plugin.c
index 97306d66..4af80142 100644
--- a/src/settings/plugins/keyfile/nms-keyfile-plugin.c
+++ b/src/settings/plugins/keyfile/nms-keyfile-plugin.c
@@ -77,7 +77,7 @@ G_DEFINE_TYPE_EXTENDED (NMSKeyfilePlugin, nms_keyfile_plugin, G_TYPE_OBJECT, 0,
 #define _NMLOG_PREFIX_NAME      "keyfile"
 #define _NMLOG_DOMAIN           LOGD_SETTINGS
 #define _NMLOG(level, ...) \
-    nm_log ((level), _NMLOG_DOMAIN, \
+    nm_log ((level), _NMLOG_DOMAIN, NULL, NULL, \
             "%s" _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
             _NMLOG_PREFIX_NAME": " \
             _NM_UTILS_MACRO_REST (__VA_ARGS__))
@@ -530,12 +530,19 @@ add_connection (NMSettingsPlugin *config,
 {
 	NMSKeyfilePlugin *self = NMS_KEYFILE_PLUGIN (config);
 	gs_free char *path = NULL;
+	gs_unref_object NMConnection *reread = NULL;
 
 	if (save_to_disk) {
-		if (!nms_keyfile_writer_connection (connection, NULL, FALSE, &path, error))
+		if (!nms_keyfile_writer_connection (connection,
+		                                    NULL,
+		                                    FALSE,
+		                                    &path,
+		                                    &reread,
+		                                    NULL,
+		                                    error))
 			return NULL;
 	}
-	return NM_SETTINGS_CONNECTION (update_connection (self, connection, path, NULL, FALSE, NULL, error));
+	return NM_SETTINGS_CONNECTION (update_connection (self, reread ?: connection, path, NULL, FALSE, NULL, error));
 }
 
 static GSList *
diff --git a/src/settings/plugins/keyfile/nms-keyfile-reader.c b/src/settings/plugins/keyfile/nms-keyfile-reader.c
index 39a01480..cb4b8379 100644
--- a/src/settings/plugins/keyfile/nms-keyfile-reader.c
+++ b/src/settings/plugins/keyfile/nms-keyfile-reader.c
@@ -56,6 +56,10 @@ _fmt_warn (const char *group, NMSetting *setting, const char *property_name, con
 		return message;
 }
 
+typedef struct {
+	bool verbose;
+} HandlerReadData;
+
 static gboolean
 _handler_read (GKeyFile *keyfile,
                NMConnection *connection,
@@ -64,11 +68,16 @@ _handler_read (GKeyFile *keyfile,
                void *user_data,
                GError **error)
 {
+	const HandlerReadData *handler_data = user_data;
+
 	if (type == NM_KEYFILE_READ_TYPE_WARN) {
 		NMKeyfileReadTypeDataWarn *warn_data = type_data;
 		NMLogLevel level;
 		char *message_free = NULL;
 
+		if (!handler_data->verbose)
+			return TRUE;
+
 		if (warn_data->severity > NM_KEYFILE_WARN_SEVERITY_WARN)
 			level = LOGL_ERR;
 		else if (warn_data->severity >= NM_KEYFILE_WARN_SEVERITY_WARN)
@@ -78,7 +87,9 @@ _handler_read (GKeyFile *keyfile,
 		else
 			level = LOGL_INFO;
 
-		nm_log (level, LOGD_SETTINGS, "keyfile: %s",
+		nm_log (level, LOGD_SETTINGS, NULL,
+		        nm_connection_get_uuid (connection),
+		        "keyfile: %s",
 		        _fmt_warn (warn_data->group, warn_data->setting,
 		                   warn_data->property_name, warn_data->message,
 		                   &message_free));
@@ -89,6 +100,19 @@ _handler_read (GKeyFile *keyfile,
 }
 
 NMConnection *
+nms_keyfile_reader_from_keyfile (GKeyFile *key_file,
+                                 const char *filename,
+                                 gboolean verbose,
+                                 GError **error)
+{
+	HandlerReadData data = {
+		.verbose = verbose,
+	};
+
+	return nm_keyfile_read (key_file, filename, NULL, _handler_read, &data, error);
+}
+
+NMConnection *
 nms_keyfile_reader_from_file (const char *filename, GError **error)
 {
 	GKeyFile *key_file;
@@ -122,7 +146,7 @@ nms_keyfile_reader_from_file (const char *filename, GError **error)
 	if (!g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, error))
 		goto out;
 
-	connection = nm_keyfile_read (key_file, filename, NULL, _handler_read, NULL, error);
+	connection = nms_keyfile_reader_from_keyfile (key_file, filename, TRUE, error);
 	if (!connection)
 		goto out;
 
diff --git a/src/settings/plugins/keyfile/nms-keyfile-reader.h b/src/settings/plugins/keyfile/nms-keyfile-reader.h
index c52fea31..b60c1e69 100644
--- a/src/settings/plugins/keyfile/nms-keyfile-reader.h
+++ b/src/settings/plugins/keyfile/nms-keyfile-reader.h
@@ -22,7 +22,12 @@
 #ifndef __NMS_KEYFILE_READER_H__
 #define __NMS_KEYFILE_READER_H__
 
-#include <nm-connection.h>
+#include "nm-connection.h"
+
+NMConnection *nms_keyfile_reader_from_keyfile (GKeyFile *key_file,
+                                               const char *filename,
+                                               gboolean verbose,
+                                               GError **error);
 
 NMConnection *nms_keyfile_reader_from_file (const char *filename, GError **error);
 
diff --git a/src/settings/plugins/keyfile/nms-keyfile-writer.c b/src/settings/plugins/keyfile/nms-keyfile-writer.c
index 95897db3..92ed2849 100644
--- a/src/settings/plugins/keyfile/nms-keyfile-writer.c
+++ b/src/settings/plugins/keyfile/nms-keyfile-writer.c
@@ -32,6 +32,7 @@
 #include "nm-keyfile-internal.h"
 
 #include "nms-keyfile-utils.h"
+#include "nms-keyfile-reader.h"
 
 /*****************************************************************************/
 
@@ -51,12 +52,12 @@ cert_writer (NMConnection *connection,
 	NMSetting8021xCKFormat format;
 	const char *path = NULL, *ext = "pem";
 
-	scheme = cert_data->scheme_func (cert_data->setting);
+	scheme = cert_data->vtable->scheme_func (cert_data->setting);
 	if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) {
 		char *tmp = NULL;
 		const char *accepted_path = NULL;
 
-		path = cert_data->path_func (cert_data->setting);
+		path = cert_data->vtable->path_func (cert_data->setting);
 		g_assert (path);
 
 		if (g_str_has_prefix (path, info->keyfile_dir)) {
@@ -92,11 +93,11 @@ cert_writer (NMConnection *connection,
 
 		if (!accepted_path)
 			accepted_path = tmp = g_strconcat (NM_KEYFILE_CERT_SCHEME_PREFIX_PATH, path, NULL);
-		nm_keyfile_plugin_kf_set_string (file, setting_name, cert_data->property_name, accepted_path);
+		nm_keyfile_plugin_kf_set_string (file, setting_name, cert_data->vtable->setting_key, accepted_path);
 		g_free (tmp);
 	} else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11) {
-		nm_keyfile_plugin_kf_set_string (file, setting_name, cert_data->property_name,
-		                                 cert_data->uri_func (cert_data->setting));
+		nm_keyfile_plugin_kf_set_string (file, setting_name, cert_data->vtable->setting_key,
+		                                 cert_data->vtable->uri_func (cert_data->setting));
 	} else if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) {
 		GBytes *blob;
 		const guint8 *blob_data;
@@ -105,13 +106,13 @@ cert_writer (NMConnection *connection,
 		GError *local = NULL;
 		char *new_path;
 
-		blob = cert_data->blob_func (cert_data->setting);
+		blob = cert_data->vtable->blob_func (cert_data->setting);
 		g_assert (blob);
 		blob_data = g_bytes_get_data (blob, &blob_len);
 
-		if (cert_data->format_func) {
+		if (cert_data->vtable->format_func) {
 			/* Get the extension for a private key */
-			format = cert_data->format_func (cert_data->setting);
+			format = cert_data->vtable->format_func (cert_data->setting);
 			if (format == NM_SETTING_802_1X_CK_FORMAT_PKCS12)
 				ext = "p12";
 		} else {
@@ -124,17 +125,17 @@ cert_writer (NMConnection *connection,
 		 * from now on instead of pushing around the certificate data.
 		 */
 		new_path = g_strdup_printf ("%s/%s-%s.%s", info->keyfile_dir, nm_connection_get_uuid (connection),
-		                            cert_data->suffix, ext);
+		                            cert_data->vtable->file_suffix, ext);
 
 		success = nm_utils_file_set_contents (new_path, (const gchar *) blob_data,
 		                                      blob_len, 0600, &local);
 		if (success) {
 			/* Write the path value to the keyfile.
 			 * We know, that basename(new_path) starts with a UUID, hence no conflict with "data:;base64,"  */
-			nm_keyfile_plugin_kf_set_string (file, setting_name, cert_data->property_name, strrchr (new_path, '/') + 1);
+			nm_keyfile_plugin_kf_set_string (file, setting_name, cert_data->vtable->setting_key, strrchr (new_path, '/') + 1);
 		} else {
 			nm_log_warn (LOGD_SETTINGS, "keyfile: %s.%s: failed to write certificate to file %s: %s",
-			             setting_name, cert_data->property_name, new_path, local->message);
+			             setting_name, cert_data->vtable->setting_key, new_path, local->message);
 			g_error_free (local);
 		}
 		g_free (new_path);
@@ -174,9 +175,11 @@ _internal_write_connection (NMConnection *connection,
                             const char *existing_path,
                             gboolean force_rename,
                             char **out_path,
+                            NMConnection **out_reread,
+                            gboolean *out_reread_same,
                             GError **error)
 {
-	GKeyFile *key_file;
+	gs_unref_keyfile GKeyFile *key_file = NULL;
 	gs_free char *data = NULL;
 	gsize len;
 	gs_free char *path = NULL;
@@ -188,8 +191,15 @@ _internal_write_connection (NMConnection *connection,
 	g_return_val_if_fail (!out_path || !*out_path, FALSE);
 	g_return_val_if_fail (keyfile_dir && keyfile_dir[0] == '/', FALSE);
 
-	if (!nm_connection_verify (connection, error))
+	switch (_nm_connection_verify (connection, error)) {
+	case NM_SETTING_VERIFY_NORMALIZABLE:
+		nm_assert_not_reached ();
+		/* fall-through */
+	case NM_SETTING_VERIFY_SUCCESS:
+		break;
+	default:
 		g_return_val_if_reached (FALSE);
+	}
 
 	id = nm_connection_get_id (connection);
 	g_assert (id && *id);
@@ -200,7 +210,6 @@ _internal_write_connection (NMConnection *connection,
 	if (!key_file)
 		return FALSE;
 	data = g_key_file_to_data (key_file, &len, error);
-	g_key_file_unref (key_file);
 	if (!data)
 		return FALSE;
 
@@ -290,15 +299,48 @@ _internal_write_connection (NMConnection *connection,
 		path = NULL;
 	}
 
+	if (out_reread || out_reread_same)
+	{
+		gs_unref_object NMConnection *reread = NULL;
+		gboolean reread_same = FALSE;
+
+		reread = nms_keyfile_reader_from_keyfile (key_file, path, FALSE, NULL);
+
+		nm_assert (NM_IS_CONNECTION (reread));
+
+		if (   reread
+		    && !nm_connection_normalize (reread, NULL, NULL, NULL)) {
+			nm_assert_not_reached ();
+			g_clear_object (&reread);
+		}
+
+		if (reread && out_reread_same) {
+			reread_same = !!nm_connection_compare (reread, connection, NM_SETTING_COMPARE_FLAG_EXACT);
+
+			nm_assert (reread_same == nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT));
+			nm_assert (reread_same == ({
+			                                gs_unref_hashtable GHashTable *_settings = NULL;
+
+			                                (   nm_connection_diff (reread, connection, NM_SETTING_COMPARE_FLAG_EXACT, &_settings)
+			                                 && !_settings);
+			                           }));
+		}
+
+		NM_SET_OUT (out_reread, g_steal_pointer (&reread));
+		NM_SET_OUT (out_reread_same, reread_same);
+	}
+
 	return TRUE;
 }
 
 gboolean
 nms_keyfile_writer_connection (NMConnection *connection,
-                          const char *existing_path,
-                          gboolean force_rename,
-                          char **out_path,
-                          GError **error)
+                               const char *existing_path,
+                               gboolean force_rename,
+                               char **out_path,
+                               NMConnection **out_reread,
+                               gboolean *out_reread_same,
+                               GError **error)
 {
 	return _internal_write_connection (connection,
 	                                   nms_keyfile_utils_get_path (),
@@ -306,16 +348,20 @@ nms_keyfile_writer_connection (NMConnection *connection,
 	                                   existing_path,
 	                                   force_rename,
 	                                   out_path,
+	                                   out_reread,
+	                                   out_reread_same,
 	                                   error);
 }
 
 gboolean
 nms_keyfile_writer_test_connection (NMConnection *connection,
-                               const char *keyfile_dir,
-                               uid_t owner_uid,
-                               pid_t owner_grp,
-                               char **out_path,
-                               GError **error)
+                                    const char *keyfile_dir,
+                                    uid_t owner_uid,
+                                    pid_t owner_grp,
+                                    char **out_path,
+                                    NMConnection **out_reread,
+                                    gboolean *out_reread_same,
+                                    GError **error)
 {
 	return _internal_write_connection (connection,
 	                                   keyfile_dir,
@@ -323,6 +369,8 @@ nms_keyfile_writer_test_connection (NMConnection *connection,
 	                                   NULL,
 	                                   FALSE,
 	                                   out_path,
+	                                   out_reread,
+	                                   out_reread_same,
 	                                   error);
 }
 
diff --git a/src/settings/plugins/keyfile/nms-keyfile-writer.h b/src/settings/plugins/keyfile/nms-keyfile-writer.h
index 4f43455d..ac41dfa2 100644
--- a/src/settings/plugins/keyfile/nms-keyfile-writer.h
+++ b/src/settings/plugins/keyfile/nms-keyfile-writer.h
@@ -22,12 +22,14 @@
 #ifndef __NMS_KEYFILE_WRITER_H__
 #define __NMS_KEYFILE_WRITER_H__
 
-#include <nm-connection.h>
+#include "nm-connection.h"
 
 gboolean nms_keyfile_writer_connection (NMConnection *connection,
                                         const char *existing_path,
                                         gboolean force_rename,
                                         char **out_path,
+                                        NMConnection **out_reread,
+                                        gboolean *out_reread_same,
                                         GError **error);
 
 gboolean nms_keyfile_writer_test_connection (NMConnection *connection,
@@ -35,6 +37,8 @@ gboolean nms_keyfile_writer_test_connection (NMConnection *connection,
                                              uid_t owner_uid,
                                              pid_t owner_grp,
                                              char **out_path,
+                                             NMConnection **out_reread,
+                                             gboolean *out_reread_same,
                                              GError **error);
 
 #endif /* __NMS_KEYFILE_WRITER_H__ */
diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection b/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection
index de8373be..5cb4d726 100644
--- a/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection
+++ b/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection
@@ -34,6 +34,7 @@ routes8=1.1.1.8/18,0.0.0.0,
 routes9=1.1.1.9/19,0.0.0.0,0
 routes10=1.1.1.10/20,,0
 routes11=1.1.1.11/21,,21
+routes11_options=cwnd=10,lock-cwnd=true,mtu=1430,src=7.7.7.7
 ignore-auto-routes=false
 ignore-auto-dns=false
 
@@ -58,5 +59,6 @@ route3=6:7:8:9:0:1:2:3/126,,1
 route4=7:8:9:0:1:2:3:4/125/::,5
 route5=8:9:0:1:2:3:4:5/124,6
 route6=8:9:0:1:2:3:4:6/123,,
+route6_options=from=abce::/63
 ignore-auto-routes=false
 ignore-auto-dns=false
diff --git a/src/settings/plugins/keyfile/tests/test-keyfile.c b/src/settings/plugins/keyfile/tests/test-keyfile.c
index f1102bd3..d9da5317 100644
--- a/src/settings/plugins/keyfile/tests/test-keyfile.c
+++ b/src/settings/plugins/keyfile/tests/test-keyfile.c
@@ -113,13 +113,25 @@ assert_reread_and_unlink (NMConnection *connection, gboolean normalize_connectio
 }
 
 static void
-write_test_connection (NMConnection *connection, char **testfile)
+assert_reread_same (NMConnection *connection,
+                    NMConnection *reread)
+{
+	nmtst_assert_connection_verifies_without_normalization (reread);
+	nmtst_assert_connection_equals (connection, TRUE, reread, FALSE);
+}
+
+static void
+write_test_connection_reread (NMConnection *connection,
+                              char **testfile,
+                              NMConnection **out_reread,
+                              gboolean *out_reread_same)
 {
 	uid_t owner_uid;
 	gid_t owner_grp;
 	gboolean success;
 	GError *error = NULL;
 	GError **p_error = (nmtst_get_rand_int () % 2) ? &error : NULL;
+	gs_unref_object NMConnection *connection_normalized = NULL;
 
 	g_assert (NM_IS_CONNECTION (connection));
 	g_assert (testfile && !*testfile);
@@ -127,13 +139,33 @@ write_test_connection (NMConnection *connection, char **testfile)
 	owner_uid = geteuid ();
 	owner_grp = getegid ();
 
-	success = nms_keyfile_writer_test_connection (connection, TEST_SCRATCH_DIR, owner_uid, owner_grp, testfile, p_error);
+	connection_normalized = nmtst_connection_duplicate_and_normalize (connection);
+
+	success = nms_keyfile_writer_test_connection (connection_normalized,
+	                                              TEST_SCRATCH_DIR,
+	                                              owner_uid,
+	                                              owner_grp,
+	                                              testfile,
+	                                              out_reread,
+	                                              out_reread_same,
+	                                              p_error);
 	g_assert_no_error (error);
 	g_assert (success);
 	g_assert (*testfile && (*testfile)[0]);
 }
 
 static void
+write_test_connection (NMConnection *connection, char **testfile)
+{
+	gs_unref_object NMConnection *reread = NULL;
+	gboolean reread_same = FALSE;
+
+	write_test_connection_reread (connection, testfile, &reread, &reread_same);
+	assert_reread_same (connection, reread);
+	g_assert (reread_same);
+}
+
+static void
 write_test_connection_and_reread (NMConnection *connection, gboolean normalize_connection)
 {
 	gs_free char *testfile = NULL;
@@ -161,6 +193,27 @@ keyfile_load_from_file (const char *testfile)
 	return keyfile;
 }
 
+static void
+_setting_copy_property_gbytes (NMConnection *src, NMConnection *dst, const char *setting_name, const char *property_name)
+{
+	gs_unref_bytes GBytes *blob = NULL;
+	NMSetting *s_src;
+	NMSetting *s_dst;
+
+	g_assert (NM_IS_CONNECTION (src));
+	g_assert (NM_IS_CONNECTION (dst));
+	g_assert (setting_name);
+	g_assert (property_name);
+
+	s_src = nm_connection_get_setting_by_name (src, setting_name);
+	g_assert (NM_IS_SETTING (s_src));
+	s_dst = nm_connection_get_setting_by_name (dst, setting_name);
+	g_assert (NM_IS_SETTING (s_dst));
+
+	g_object_get (s_src, property_name, &blob, NULL);
+	g_object_set (s_dst, property_name, blob, NULL);
+}
+
 /*****************************************************************************/
 
 static void
@@ -171,6 +224,7 @@ test_read_valid_wired_connection (void)
 	NMSettingWired *s_wired;
 	NMSettingIPConfig *s_ip4;
 	NMSettingIPConfig *s_ip6;
+	NMIPRoute *route;
 	gs_free_error GError *error = NULL;
 	const char *mac;
 	char expected_mac_address[ETH_ALEN] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 };
@@ -265,6 +319,15 @@ test_read_valid_wired_connection (void)
 	check_ip_route (s_ip4, 10, "1.1.1.10", 20, NULL, -1);
 	check_ip_route (s_ip4, 11, "1.1.1.11", 21, NULL, 21);
 
+	/* Route attributes */
+	route = nm_setting_ip_config_get_route (s_ip4, 11);
+	g_assert (route);
+
+	nmtst_assert_route_attribute_uint32  (route, NM_IP_ROUTE_ATTRIBUTE_CWND, 10);
+	nmtst_assert_route_attribute_uint32  (route, NM_IP_ROUTE_ATTRIBUTE_MTU, 1430);
+	nmtst_assert_route_attribute_boolean (route, NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, TRUE);
+	nmtst_assert_route_attribute_string  (route, NM_IP_ROUTE_ATTRIBUTE_SRC, "7.7.7.7");
+
 	/* ===== IPv6 SETTING ===== */
 	s_ip6 = nm_connection_get_setting_ip6_config (connection);
 	g_assert (s_ip6);
@@ -304,6 +367,11 @@ test_read_valid_wired_connection (void)
 	check_ip_route (s_ip6, 4, "7:8:9:0:1:2:3:4", 125, NULL, 5);
 	check_ip_route (s_ip6, 5, "8:9:0:1:2:3:4:5", 124, NULL, 6);
 	check_ip_route (s_ip6, 6, "8:9:0:1:2:3:4:6", 123, NULL, -1);
+
+	/* Route attributes */
+	route = nm_setting_ip_config_get_route (s_ip6, 6);
+	g_assert (route);
+	nmtst_assert_route_attribute_string (route, NM_IP_ROUTE_ATTRIBUTE_FROM, "abce::/63");
 }
 
 static void
@@ -349,6 +417,7 @@ test_write_wired_connection (void)
 	NMSettingWired *s_wired;
 	NMSettingIPConfig *s_ip4;
 	NMSettingIPConfig *s_ip6;
+	NMIPRoute *rt;
 	const char *mac = "99:88:77:66:55:44";
 	const char *dns1 = "4.2.2.1";
 	const char *dns2 = "4.2.2.2";
@@ -376,6 +445,7 @@ test_write_wired_connection (void)
 	const char *route6_4 = "5:6:7:8:9:0:1:2";
 	const char *route6_4_nh = "::";
 	guint64 timestamp = 0x12345678L;
+	GError *error = NULL;
 
 	connection = nm_simple_connection_new ();
 
@@ -420,7 +490,14 @@ test_write_wired_connection (void)
 	add_one_ip_route (s_ip4, route1, route1_nh, 24, 3);
 	add_one_ip_route (s_ip4, route2, route2_nh, 8, 1);
 	add_one_ip_route (s_ip4, route3, route3_nh, 7, -1);
-	add_one_ip_route (s_ip4, route4, route4_nh, 6, 4);
+
+	rt = nm_ip_route_new (AF_INET, route4, 6, route4_nh, 4, &error);
+	g_assert_no_error (error);
+	nm_ip_route_set_attribute (rt, NM_IP_ROUTE_ATTRIBUTE_CWND, g_variant_new_uint32 (10));
+	nm_ip_route_set_attribute (rt, NM_IP_ROUTE_ATTRIBUTE_MTU, g_variant_new_uint32 (1492));
+	nm_ip_route_set_attribute (rt, NM_IP_ROUTE_ATTRIBUTE_SRC, g_variant_new_string ("1.2.3.4"));
+	g_assert (nm_setting_ip_config_add_route (s_ip4, rt));
+	nm_ip_route_unref (rt);
 
 	/* DNS servers */
 	nm_setting_ip_config_add_dns (s_ip4, dns1);
@@ -1639,11 +1716,18 @@ test_write_wired_8021x_tls_connection_path (void)
 	gs_free_error GError *error = NULL;
 	gs_unref_keyfile GKeyFile *keyfile = NULL;
 	gboolean relative = FALSE;
+	gboolean reread_same = FALSE;
 
 	connection = create_wired_tls_connection (NM_SETTING_802_1X_CK_SCHEME_PATH);
 	g_assert (connection != NULL);
 
-	write_test_connection (connection, &testfile);
+	write_test_connection_reread (connection, &testfile, &reread, &reread_same);
+	nmtst_assert_connection_verifies_without_normalization (reread);
+	_setting_copy_property_gbytes (connection, reread, NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_CA_CERT);
+	_setting_copy_property_gbytes (connection, reread, NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_CLIENT_CERT);
+	_setting_copy_property_gbytes (connection, reread, NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PRIVATE_KEY);
+	assert_reread_same (connection, reread);
+	g_clear_object (&reread);
 
 	/* Read the connection back in and compare it to the one we just wrote out */
 	reread = nms_keyfile_reader_from_file (testfile, &error);
@@ -1716,6 +1800,7 @@ test_write_wired_8021x_tls_connection_blob (void)
 	char *new_client_cert;
 	char *new_priv_key;
 	const char *uuid;
+	gboolean reread_same = FALSE;
 	gs_free_error GError *error = NULL;
 	GBytes *password_raw = NULL;
 #define PASSWORD_RAW "password-raw\0test"
@@ -1733,7 +1818,13 @@ test_write_wired_8021x_tls_connection_blob (void)
 	              NULL);
 	g_bytes_unref (password_raw);
 
-	write_test_connection (connection, &testfile);
+	write_test_connection_reread (connection, &testfile, &reread, &reread_same);
+	nmtst_assert_connection_verifies_without_normalization (reread);
+	_setting_copy_property_gbytes (connection, reread, NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_CA_CERT);
+	_setting_copy_property_gbytes (connection, reread, NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_CLIENT_CERT);
+	_setting_copy_property_gbytes (connection, reread, NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PRIVATE_KEY);
+	assert_reread_same (connection, reread);
+	g_clear_object (&reread);
 
 	/* Check that the new certs got written out */
 	s_con = nm_connection_get_setting_connection (connection);