about summary refs log tree commit diff
path: root/src/core/settings/plugins
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2021-10-01 23:05:04 +0200
committerMichael Biebl <biebl@debian.org>2021-10-01 23:05:04 +0200
commite74c568b07b50b97873fb4ee1d776dedefbd54d6 (patch)
tree3469f17ea9af91f7ff169b890633bda68b0cf76e /src/core/settings/plugins
parentbfe522304da217296e2a61040f58e35ec5d6f3f2 (diff)
New upstream version 1.32.12 upstream/1.32.12
Diffstat (limited to 'src/core/settings/plugins')
-rw-r--r--src/core/settings/plugins/ifcfg-rh/meson.build2
-rwxr-xr-x[-rw-r--r--]src/core/settings/plugins/ifcfg-rh/nm-ifdown47
-rwxr-xr-x[-rw-r--r--]src/core/settings/plugins/ifcfg-rh/nm-ifup47
-rw-r--r--src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c10
-rw-r--r--src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c93
-rw-r--r--src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-storage.c5
-rw-r--r--src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c20
-rw-r--r--src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h4
-rw-r--r--src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c184
-rw-r--r--src/core/settings/plugins/ifcfg-rh/shvar.c261
-rw-r--r--src/core/settings/plugins/ifcfg-rh/shvar.h3
-rw-r--r--src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-bridge-component-a.cexpected2
-rw-r--r--src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-bridge-component-b.cexpected2
-rw-r--r--src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-wired-802-1X-subj-matches.cexpected2
-rw-r--r--src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bridge_Component.cexpected2
-rw-r--r--src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected2
-rw-r--r--src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-static-routes-legacy.cexpected2
-rw-r--r--src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-vlanid-use4
-rw-r--r--src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-vlanid-use.cexpected15
-rw-r--r--src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-wpa-eap-suite-b-192-tls1
-rw-r--r--src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-wpa-eap-ttls-tls1
-rw-r--r--src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-write-unknown-4.expected6
-rw-r--r--src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-1.cexpected14
-rw-r--r--src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-2.cexpected15
-rw-r--r--src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-3.cexpected15
-rw-r--r--src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-4.cexpected15
-rw-r--r--src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-5.cexpected15
-rw-r--r--src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c325
-rw-r--r--src/core/settings/plugins/ifupdown/meson.build2
-rw-r--r--src/core/settings/plugins/ifupdown/nms-ifupdown-parser.c26
-rw-r--r--src/core/settings/plugins/ifupdown/nms-ifupdown-plugin.c2
-rw-r--r--src/core/settings/plugins/ifupdown/tests/test-ifupdown.c2
-rw-r--r--src/core/settings/plugins/keyfile/nms-keyfile-plugin.c28
-rw-r--r--src/core/settings/plugins/keyfile/nms-keyfile-reader.c2
-rw-r--r--src/core/settings/plugins/keyfile/nms-keyfile-storage.c7
-rw-r--r--src/core/settings/plugins/keyfile/nms-keyfile-utils.c32
-rw-r--r--src/core/settings/plugins/keyfile/nms-keyfile-writer.c9
-rw-r--r--src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c5
38 files changed, 893 insertions, 336 deletions
diff --git a/src/core/settings/plugins/ifcfg-rh/meson.build b/src/core/settings/plugins/ifcfg-rh/meson.build
index a2f11a92..c62fa89d 100644
--- a/src/core/settings/plugins/ifcfg-rh/meson.build
+++ b/src/core/settings/plugins/ifcfg-rh/meson.build
@@ -28,7 +28,6 @@ libnms_ifcfg_rh_core = static_library(
     'shvar.c',
   ),
   dependencies: core_default_dep,
-  c_args: daemon_c_flags,
 )
 
 libnm_settings_plugin_ifcfg_rh = shared_module(
@@ -38,7 +37,6 @@ libnm_settings_plugin_ifcfg_rh = shared_module(
     'nms-ifcfg-rh-plugin.c',
   ),
   dependencies: core_plugin_dep,
-  c_args: daemon_c_flags,
   link_with: libnms_ifcfg_rh_core,
   link_args: ldflags_linker_script_settings,
   link_depends: linker_script_settings,
diff --git a/src/core/settings/plugins/ifcfg-rh/nm-ifdown b/src/core/settings/plugins/ifcfg-rh/nm-ifdown
index e7bd73ae..3b05ef1c 100644..100755
--- a/src/core/settings/plugins/ifcfg-rh/nm-ifdown
+++ b/src/core/settings/plugins/ifcfg-rh/nm-ifdown
@@ -1,3 +1,44 @@
-#!/bin/sh
-nmcli connection load "/etc/sysconfig/network-scripts/ifcfg-$1" &&
-exec nmcli connection down filename "/etc/sysconfig/network-scripts/ifcfg-$1"
+#!/bin/bash
+
+CONFIG="$1"
+
+if [ -z "${CONFIG}" ] ; then
+    echo $"Usage: ifdown <device name>" >&2
+    exit 1
+fi
+
+usage_and_fail() {
+    cat <<EOF >&2
+$1!
+
+See all profiles with \`nmcli connection\`.
+Reload files from disk with \`nmcli connection reload\`
+Deactivate the desired profile with \`nmcli connection down \"\$NAME\"\`
+EOF
+    exit 1
+}
+
+OLD_IFS="$IFS"
+
+re='^/etc/sysconfig/network-scripts/ifcfg-[^/]+$'
+for f in "/etc/sysconfig/network-scripts/ifcfg-$CONFIG" "/etc/sysconfig/network-scripts/$CONFIG" ; do
+    [[ "$f" =~ $re ]] || continue
+    [ -f "$f" ] || continue
+
+    nmcli connection load "$f" \
+    && nmcli connection down filename "$f" \
+    && exit 0
+
+    usage_and_fail "Failure to deactivate file \"$CONFIG\""
+done
+
+IFS=$'\n '
+APATHS=( $(nmcli -g GENERAL.DBUS-PATH connection show --active "$CONFIG" 2>/dev/null) )
+IFS="$OLD_IFS"
+if [ "${#APATHS[@]}" -eq 1 ] ; then
+    nmcli connection down apath "${APATHS[0]}" \
+    && exit 0
+    usage_and_fail "Failure to deactivate profile \"$CONFIG\" (apath ${APATHS[@]})"
+fi
+
+usage_and_fail "No suitable profile \"$CONFIG\" found"
diff --git a/src/core/settings/plugins/ifcfg-rh/nm-ifup b/src/core/settings/plugins/ifcfg-rh/nm-ifup
index 96637a92..6b32fe1b 100644..100755
--- a/src/core/settings/plugins/ifcfg-rh/nm-ifup
+++ b/src/core/settings/plugins/ifcfg-rh/nm-ifup
@@ -1,3 +1,44 @@
-#!/bin/sh
-nmcli connection load "/etc/sysconfig/network-scripts/ifcfg-$1" &&
-exec nmcli connection up filename "/etc/sysconfig/network-scripts/ifcfg-$1"
+#!/bin/bash
+
+CONFIG="$1"
+
+if [ -z "${CONFIG}" ] ; then
+    echo $"Usage: ifup <device name>" >&2
+    exit 1
+fi
+
+usage_and_fail() {
+    cat <<EOF >&2
+$1!
+
+See all profiles with \`nmcli connection\`.
+Reload files from disk with \`nmcli connection reload\`
+Activate the desired profile with \`nmcli connection up \"\$NAME\"\`
+EOF
+    exit 1
+}
+
+OLD_IFS="$IFS"
+
+re='^/etc/sysconfig/network-scripts/ifcfg-[^/]+$'
+for f in "/etc/sysconfig/network-scripts/ifcfg-$CONFIG" "/etc/sysconfig/network-scripts/$CONFIG" ; do
+    [[ "$f" =~ $re ]] || continue
+    [ -f "$f" ] || continue
+
+    nmcli connection load "$f" \
+    && nmcli connection up filename "$f" \
+    && exit 0
+
+    usage_and_fail "Failure to activate file \"$CONFIG\""
+done
+
+IFS=$'\n '
+UUIDS=( $(nmcli -g connection.uuid connection show "$CONFIG" 2>/dev/null) )
+IFS="$OLD_IFS"
+if [ "${#UUIDS[@]}" -eq 1 ] ; then
+    nmcli connection up uuid "${UUIDS[0]}" \
+    && exit 0
+    usage_and_fail "Failure to activate profile \"$CONFIG\" (uuid ${UUIDS[0]})"
+fi
+
+usage_and_fail "No suitable profile \"$CONFIG\" found"
diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c
index d114db0f..5038ac6a 100644
--- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c
+++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c
@@ -13,12 +13,12 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
-#include "nm-std-aux/c-list-util.h"
-#include "nm-glib-aux/nm-c-list.h"
-#include "nm-glib-aux/nm-io-utils.h"
-#include "nm-std-aux/nm-dbus-compat.h"
+#include "libnm-std-aux/c-list-util.h"
+#include "libnm-glib-aux/nm-c-list.h"
+#include "libnm-glib-aux/nm-io-utils.h"
+#include "libnm-std-aux/nm-dbus-compat.h"
 #include "nm-utils.h"
-#include "nm-core-internal.h"
+#include "libnm-core-intern/nm-core-internal.h"
 #include "nm-config.h"
 #include "nm-dbus-manager.h"
 #include "settings/nm-settings-plugin.h"
diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c
index a42c4188..03b347f9 100644
--- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c
+++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c
@@ -18,7 +18,8 @@
 #include <linux/rtnetlink.h>
 #include <linux/if_ether.h>
 
-#include "nm-glib-aux/nm-secret-utils.h"
+#include "libnm-glib-aux/nm-uuid.h"
+#include "libnm-glib-aux/nm-secret-utils.h"
 #include "nm-connection.h"
 #include "nm-dbus-interface.h"
 #include "nm-setting-connection.h"
@@ -38,11 +39,11 @@
 #include "nm-setting-user.h"
 #include "nm-setting-proxy.h"
 #include "nm-setting-generic.h"
-#include "nm-core-internal.h"
+#include "libnm-core-intern/nm-core-internal.h"
 #include "nm-utils.h"
-#include "nm-base/nm-ethtool-base.h"
+#include "libnm-base/nm-ethtool-base.h"
 
-#include "platform/nm-platform.h"
+#include "libnm-platform/nm-platform.h"
 #include "NetworkManagerUtils.h"
 
 #include "nms-ifcfg-rh-common.h"
@@ -405,11 +406,9 @@ make_connection_setting(const char *file,
     /* Try for a UUID key before falling back to hashing the file name */
     uuid = svGetValueStr(ifcfg, "UUID", &uuid_free);
     if (!uuid) {
-        uuid_free = nm_utils_uuid_generate_from_string(svFileGetName(ifcfg),
-                                                       -1,
-                                                       NM_UTILS_UUID_TYPE_LEGACY,
-                                                       NULL);
-        uuid      = uuid_free;
+        uuid_free =
+            nm_uuid_generate_from_string_str(svFileGetName(ifcfg), -1, NM_UUID_TYPE_LEGACY, NULL);
+        uuid = uuid_free;
     }
 
     g_object_set(s_con,
@@ -1896,6 +1895,8 @@ make_ip4_setting(shvarFile *ifcfg,
                  svGetValueBoolean(ifcfg, "DHCP_SEND_HOSTNAME", TRUE),
                  NM_SETTING_IP_CONFIG_DHCP_TIMEOUT,
                  (int) svGetValueInt64(ifcfg, "IPV4_DHCP_TIMEOUT", 10, 0, G_MAXINT32, 0),
+                 NM_SETTING_IP_CONFIG_REQUIRED_TIMEOUT,
+                 (int) svGetValueInt64(ifcfg, "IPV4_REQUIRED_TIMEOUT", 10, 0, G_MAXINT32, -1),
                  NULL);
 
     nm_clear_g_free(&value);
@@ -1986,7 +1987,11 @@ make_ip4_setting(shvarFile *ifcfg,
                 } else if (nm_utils_ipaddr_is_valid(AF_INET6, v)) {
                     /* Ignore IPv6 addresses */
                 } else {
-                    PARSE_WARNING("invalid DNS server address %s", v);
+                    g_set_error(error,
+                                NM_SETTINGS_ERROR,
+                                NM_SETTINGS_ERROR_INVALID_CONNECTION,
+                                "Invalid DNS server address '%s'",
+                                v);
                     return NULL;
                 }
             }
@@ -2153,6 +2158,8 @@ read_aliases(NMSettingIPConfig *s_ip4, gboolean read_defroute, const char *filen
                 continue;
             }
 
+            svWarnInvalid(parsed, "alias", _NMLOG_DOMAIN);
+
             device = svGetValueStr(parsed, "DEVICE", &device_value);
             if (!device) {
                 PARSE_WARNING("alias file '%s' has no DEVICE", full_path);
@@ -2404,6 +2411,8 @@ make_ip6_setting(shvarFile *ifcfg, shvarFile *network_ifcfg, gboolean routes_rea
                  svGetValueBoolean(ifcfg, "DHCPV6_SEND_HOSTNAME", TRUE),
                  NM_SETTING_IP_CONFIG_DHCP_TIMEOUT,
                  (int) svGetValueInt64(ifcfg, "IPV6_DHCP_TIMEOUT", 10, 0, G_MAXINT32, 0),
+                 NM_SETTING_IP_CONFIG_REQUIRED_TIMEOUT,
+                 (int) svGetValueInt64(ifcfg, "IPV6_REQUIRED_TIMEOUT", 10, 0, G_MAXINT32, -1),
                  NM_SETTING_IP6_CONFIG_RA_TIMEOUT,
                  (int) svGetValueInt64(ifcfg, "IPV6_RA_TIMEOUT", 10, 0, G_MAXINT32, 0),
                  NULL);
@@ -2505,7 +2514,11 @@ make_ip6_setting(shvarFile *ifcfg, shvarFile *network_ifcfg, gboolean routes_rea
         } else if (nm_utils_ipaddr_is_valid(AF_INET, v)) {
             /* Ignore IPv4 addresses */
         } else {
-            PARSE_WARNING("invalid DNS server address %s", v);
+            g_set_error(error,
+                        NM_SETTINGS_ERROR,
+                        NM_SETTINGS_ERROR_INVALID_CONNECTION,
+                        "Invalid DNS server address '%s'",
+                        v);
             return NULL;
         }
     }
@@ -4303,7 +4316,7 @@ make_wireless_setting(shvarFile *ifcfg, GError **error)
             bytes = g_bytes_new(value, value_len);
 
         ssid_len = g_bytes_get_size(bytes);
-        if (ssid_len > 32 || ssid_len == 0) {
+        if (ssid_len == 0 || ssid_len > NM_IW_ESSID_MAX_SIZE) {
             g_set_error(error,
                         NM_SETTINGS_ERROR,
                         NM_SETTINGS_ERROR_INVALID_CONNECTION,
@@ -4679,7 +4692,9 @@ static NM_UTILS_STRING_TABLE_LOOKUP_DEFINE(
     {"--coalesce", NM_ETHTOOL_TYPE_COALESCE},
     {"--features", NM_ETHTOOL_TYPE_FEATURE},
     {"--offload", NM_ETHTOOL_TYPE_FEATURE},
+    {"--pause", NM_ETHTOOL_TYPE_PAUSE},
     {"--set-ring", NM_ETHTOOL_TYPE_RING},
+    {"-A", NM_ETHTOOL_TYPE_PAUSE},
     {"-C", NM_ETHTOOL_TYPE_COALESCE},
     {"-G", NM_ETHTOOL_TYPE_RING},
     {"-K", NM_ETHTOOL_TYPE_FEATURE}, );
@@ -4719,7 +4734,7 @@ parse_ethtool_option(const char *             value,
         w_iter = &words[2];
 
         while (w_iter && *w_iter) {
-            if (ethtool_type == NM_ETHTOOL_TYPE_FEATURE) {
+            if (NM_IN_SET(ethtool_type, NM_ETHTOOL_TYPE_FEATURE, NM_ETHTOOL_TYPE_PAUSE)) {
                 w_iter = _next_ethtool_options_nmternary(w_iter, ethtool_type, &ifcfg_option);
 
                 if (ifcfg_option.has_value) {
@@ -5022,6 +5037,7 @@ make_wired_setting(shvarFile *ifcfg, const char *file, NMSetting8021x **s_8021x,
     const char *                    cvalue;
     gs_free char *                  value = NULL;
     gboolean                        found = FALSE;
+    NMTernary                       accept_all_mac_addresses;
 
     s_wired = NM_SETTING_WIRED(nm_setting_wired_new());
 
@@ -5119,15 +5135,15 @@ make_wired_setting(shvarFile *ifcfg, const char *file, NMSetting8021x **s_8021x,
         for (i = 0; options && options[i]; i++) {
             const char *line = options[i];
             const char *equals;
-            gboolean    valid = FALSE;
 
             equals = strchr(line, '=');
-            if (equals) {
-                ((char *) equals)[0] = '\0';
-                valid                = nm_setting_wired_add_s390_option(s_wired, line, equals + 1);
-            }
-            if (!valid)
-                PARSE_WARNING("invalid s390 OPTION '%s'", line);
+            if (!equals)
+                continue;
+
+            /* Here we don't verify the key/value further. If the file contains invalid keys,
+             * we will later reject the connection as invalid. */
+            ((char *) equals)[0] = '\0';
+            nm_setting_wired_add_s390_option(s_wired, line, equals + 1);
         }
         found = TRUE;
     }
@@ -5180,6 +5196,15 @@ make_wired_setting(shvarFile *ifcfg, const char *file, NMSetting8021x **s_8021x,
     }
     nm_clear_g_free(&value);
 
+    accept_all_mac_addresses = svGetValueTernary(ifcfg, "ACCEPT_ALL_MAC_ADDRESSES");
+    if (accept_all_mac_addresses != NM_TERNARY_DEFAULT) {
+        g_object_set(s_wired,
+                     NM_SETTING_WIRED_ACCEPT_ALL_MAC_ADDRESSES,
+                     accept_all_mac_addresses,
+                     NULL);
+        found = TRUE;
+    }
+
     if (!found) {
         g_set_error(error,
                     NM_UTILS_ERROR,
@@ -6072,15 +6097,14 @@ make_vlan_setting(shvarFile *ifcfg, const char *file, GError **error)
                 v = iface_name + 4;
         }
 
-        if (v) {
-            int device_vlan_id;
-
-            /* Grab VLAN ID from interface name; this takes precedence over the
-             * separate VLAN_ID property for backwards compat.
+        if (vlan_id == -1 && v) {
+            /* Grab VLAN ID from interface name; The explicit VLAN_ID option takes precedence
+             * over detecting the ID based on PHYSDEV.
+             *
+             * Note that older versions of NetworkManager had a bug and this would overwrite the
+             * VLAN_ID in this case.
              */
-            device_vlan_id = _nm_utils_ascii_str_to_int64(v, 10, 0, 4095, -1);
-            if (device_vlan_id != -1)
-                vlan_id = device_vlan_id;
+            vlan_id = _nm_utils_ascii_str_to_int64(v, 10, 0, 4095, -1);
         }
     }
 
@@ -6288,6 +6312,7 @@ connection_from_file_full(const char *filename,
     NMSetting *                   s_ip4;
     NMSetting *                   s_ip6;
     const char *                  ifcfg_name       = NULL;
+    gs_free char *                s_tmp            = NULL;
     gboolean                      has_ip4_defroute = FALSE;
     gboolean                      has_complex_routes_v4;
     gboolean                      has_complex_routes_v6;
@@ -6315,8 +6340,6 @@ connection_from_file_full(const char *filename,
     if (!main_ifcfg)
         return NULL;
 
-    network_ifcfg = svOpenFile(network_file, NULL);
-
     if (!svGetValueBoolean(main_ifcfg, "NM_CONTROLLED", TRUE)) {
         connection = create_unhandled_connection(filename, main_ifcfg, "unmanaged", out_unhandled);
         if (!connection) {
@@ -6330,6 +6353,16 @@ connection_from_file_full(const char *filename,
         return g_steal_pointer(&connection);
     }
 
+    if (NM_IN_STRSET(svGetValueStr(main_ifcfg, "DEVICE", &s_tmp), "lo")) {
+        /* "lo" is not handled by NetworkManager and we ignore it. */
+    } else
+        svWarnInvalid(main_ifcfg, "ifcfg", _NMLOG_DOMAIN);
+    nm_clear_g_free(&s_tmp);
+
+    network_ifcfg = svOpenFile(network_file, NULL);
+    /* we don't call svWarnInvalid(network_ifcfg), because we will load this file for
+     * every profile. So we would get a large number of duplicate warnings. */
+
     /* iBFT is handled by nm-initrd-generator during boot. */
     bootproto = svGetValueStr_cp(main_ifcfg, "BOOTPROTO");
     if (bootproto && !g_ascii_strcasecmp(bootproto, "ibft")) {
diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-storage.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-storage.c
index 3f674dea..134bdf68 100644
--- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-storage.c
+++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-storage.c
@@ -7,8 +7,9 @@
 
 #include "nms-ifcfg-rh-storage.h"
 
+#include "libnm-glib-aux/nm-uuid.h"
 #include "nm-utils.h"
-#include "nm-core-internal.h"
+#include "libnm-core-intern/nm-core-internal.h"
 #include "nm-connection.h"
 #include "nms-ifcfg-rh-plugin.h"
 
@@ -88,7 +89,7 @@ static NMSIfcfgRHStorage *
 _storage_new(NMSIfcfgRHPlugin *plugin, const char *uuid, const char *filename)
 {
     nm_assert(NMS_IS_IFCFG_RH_PLUGIN(plugin));
-    nm_assert(!uuid || nm_utils_is_uuid(uuid));
+    nm_assert(!uuid || nm_uuid_is_normalized(uuid));
     nm_assert(filename && filename[0] == '/');
 
     return g_object_new(NMS_TYPE_IFCFG_RH_STORAGE,
diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c
index ada1942a..febfc120 100644
--- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c
+++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c
@@ -9,7 +9,7 @@
 
 #include <stdlib.h>
 
-#include "nm-core-internal.h"
+#include "libnm-core-intern/nm-core-internal.h"
 #include "NetworkManagerUtils.h"
 
 #include "nms-ifcfg-rh-common.h"
@@ -593,6 +593,9 @@ const char *const _nm_ethtool_ifcfg_names[] = {
     ETHT_NAME(NM_ETHTOOL_ID_FEATURE_TX_UDP_TNL_CSUM_SEGMENTATION, "tx-udp_tnl-csum-segmentation"),
     ETHT_NAME(NM_ETHTOOL_ID_FEATURE_TX_UDP_TNL_SEGMENTATION, "tx-udp_tnl-segmentation"),
     ETHT_NAME(NM_ETHTOOL_ID_FEATURE_TX_VLAN_STAG_HW_INSERT, "tx-vlan-stag-hw-insert"),
+    ETHT_NAME(NM_ETHTOOL_ID_PAUSE_AUTONEG, "pause-autoneg"),
+    ETHT_NAME(NM_ETHTOOL_ID_PAUSE_RX, "pause-rx"),
+    ETHT_NAME(NM_ETHTOOL_ID_PAUSE_TX, "pause-tx"),
     ETHT_NAME(NM_ETHTOOL_ID_RING_RX, "rx"),
     ETHT_NAME(NM_ETHTOOL_ID_RING_RX_JUMBO, "rx-jumbo"),
     ETHT_NAME(NM_ETHTOOL_ID_RING_RX_MINI, "rx-mini"),
@@ -722,6 +725,15 @@ static NM_UTILS_STRING_TABLE_LOOKUP_DEFINE(
     {"rx-mini", NM_ETHTOOL_ID_RING_RX_MINI},
     {"tx", NM_ETHTOOL_ID_RING_TX}, );
 
+static NM_UTILS_STRING_TABLE_LOOKUP_DEFINE(
+    _get_ethtoolid_pause_by_name,
+    NMEthtoolID,
+    { nm_assert(name); },
+    { return NM_ETHTOOL_ID_UNKNOWN; },
+    {"pause-autoneg", NM_ETHTOOL_ID_PAUSE_AUTONEG},
+    {"pause-rx", NM_ETHTOOL_ID_PAUSE_RX},
+    {"pause-tx", NM_ETHTOOL_ID_PAUSE_TX}, );
+
 const NMEthtoolData *
 nms_ifcfg_rh_utils_get_ethtool_by_name(const char *name, NMEthtoolType ethtool_type)
 {
@@ -737,6 +749,9 @@ nms_ifcfg_rh_utils_get_ethtool_by_name(const char *name, NMEthtoolType ethtool_t
     case NM_ETHTOOL_TYPE_RING:
         id = _get_ethtoolid_ring_by_name(name);
         break;
+    case NM_ETHTOOL_TYPE_PAUSE:
+        id = _get_ethtoolid_pause_by_name(name);
+        break;
     default:
         nm_assert_not_reached();
         return NULL;
@@ -800,6 +815,7 @@ nms_ifcfg_rh_utils_is_numbered_tag_impl(const char *key,
     }
 
 const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[] = {
+    _KEY_TYPE("ACCEPT_ALL_MAC_ADDRESSES", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
     _KEY_TYPE("ACD_TIMEOUT", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
     _KEY_TYPE("ADDRESS", NMS_IFCFG_KEY_TYPE_IS_NUMBERED),
     _KEY_TYPE("AP_ISOLATION", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
@@ -942,6 +958,7 @@ const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[] = {
     _KEY_TYPE("IPV4_DHCP_TIMEOUT", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
     _KEY_TYPE("IPV4_DNS_PRIORITY", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
     _KEY_TYPE("IPV4_FAILURE_FATAL", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
+    _KEY_TYPE("IPV4_REQUIRED_TIMEOUT", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
     _KEY_TYPE("IPV4_ROUTE_METRIC", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
     _KEY_TYPE("IPV4_ROUTE_TABLE", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
     _KEY_TYPE("IPV6ADDR", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
@@ -964,6 +981,7 @@ const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[] = {
     _KEY_TYPE("IPV6_PRIVACY", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
     _KEY_TYPE("IPV6_PRIVACY_PREFER_PUBLIC_IP", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
     _KEY_TYPE("IPV6_RA_TIMEOUT", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
+    _KEY_TYPE("IPV6_REQUIRED_TIMEOUT", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
     _KEY_TYPE("IPV6_RES_OPTIONS", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
     _KEY_TYPE("IPV6_ROUTE_METRIC", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
     _KEY_TYPE("IPV6_ROUTE_TABLE", NMS_IFCFG_KEY_TYPE_IS_PLAIN),
diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h
index 04a1b63d..b7751ec9 100644
--- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h
+++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h
@@ -7,7 +7,7 @@
 #define _UTILS_H_
 
 #include "nm-connection.h"
-#include "nm-base/nm-ethtool-base.h"
+#include "libnm-base/nm-ethtool-base.h"
 
 #include "shvar.h"
 
@@ -33,7 +33,7 @@ typedef struct {
     NMSIfcfgKeyTypeFlags key_flags;
 } NMSIfcfgKeyTypeInfo;
 
-extern const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[248];
+extern const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[251];
 
 const NMSIfcfgKeyTypeInfo *nms_ifcfg_well_known_key_find_info(const char *key, gssize *out_idx);
 
diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
index 45b76456..ef85b6bf 100644
--- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
+++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
@@ -15,8 +15,9 @@
 #include <unistd.h>
 #include <stdio.h>
 
-#include "nm-glib-aux/nm-enum-utils.h"
-#include "nm-glib-aux/nm-io-utils.h"
+#include "libnm-glib-aux/nm-enum-utils.h"
+#include "libnm-glib-aux/nm-str-buf.h"
+#include "libnm-glib-aux/nm-io-utils.h"
 #include "nm-manager.h"
 #include "nm-setting-connection.h"
 #include "nm-setting-wired.h"
@@ -32,9 +33,9 @@
 #include "nm-setting-team.h"
 #include "nm-setting-team-port.h"
 #include "nm-utils.h"
-#include "nm-core-internal.h"
+#include "libnm-core-intern/nm-core-internal.h"
 #include "NetworkManagerUtils.h"
-#include "nm-base/nm-ethtool-base.h"
+#include "libnm-base/nm-ethtool-base.h"
 
 #include "nms-ifcfg-rh-common.h"
 #include "nms-ifcfg-rh-reader.h"
@@ -203,18 +204,18 @@ write_object(NMSetting8021x *                s_8021x,
     g_return_val_if_fail(ifcfg != NULL, FALSE);
     g_return_val_if_fail(objtype != NULL, FALSE);
 
-    scheme = (*(objtype->vtable->scheme_func))(s_8021x);
+    scheme = (*(objtype->vtable->scheme_func)) (s_8021x);
     switch (scheme) {
     case NM_SETTING_802_1X_CK_SCHEME_UNKNOWN:
         break;
     case NM_SETTING_802_1X_CK_SCHEME_BLOB:
-        blob = (*(objtype->vtable->blob_func))(s_8021x);
+        blob = (*(objtype->vtable->blob_func)) (s_8021x);
         break;
     case NM_SETTING_802_1X_CK_SCHEME_PATH:
-        value = (*(objtype->vtable->path_func))(s_8021x);
+        value = (*(objtype->vtable->path_func)) (s_8021x);
         break;
     case NM_SETTING_802_1X_CK_SCHEME_PKCS11:
-        value = (*(objtype->vtable->uri_func))(s_8021x);
+        value = (*(objtype->vtable->uri_func)) (s_8021x);
         break;
     default:
         g_set_error(error,
@@ -227,8 +228,8 @@ write_object(NMSetting8021x *                s_8021x,
     /* Set the password for certificate/private key. */
     nm_sprintf_buf(secret_name, "%s_PASSWORD", objtype->ifcfg_rh_key);
     nm_sprintf_buf(secret_flags, "%s_PASSWORD_FLAGS", objtype->ifcfg_rh_key);
-    password = (*(objtype->vtable->passwd_func))(s_8021x);
-    flags    = (*(objtype->vtable->pwflag_func))(s_8021x);
+    password = (*(objtype->vtable->passwd_func)) (s_8021x);
+    flags    = (*(objtype->vtable->pwflag_func)) (s_8021x);
     set_secret(ifcfg, secrets, secret_name, password, secret_flags, flags);
 
     if (!objtype->vtable->format_func)
@@ -299,6 +300,7 @@ write_blobs(GHashTable *blobs, GError **error)
                                         g_bytes_get_size(blob),
                                         0600,
                                         NULL,
+                                        NULL,
                                         &write_error)) {
             g_set_error(error,
                         NM_SETTINGS_ERROR,
@@ -862,7 +864,7 @@ write_wireless_setting(NMConnection *connection,
         return FALSE;
     }
     ssid_data = g_bytes_get_data(ssid, &ssid_len);
-    if (!ssid_len || ssid_len > 32) {
+    if (ssid_len == 0 || ssid_len > NM_IW_ESSID_MAX_SIZE) {
         g_set_error(error,
                     NM_SETTINGS_ERROR,
                     NM_SETTINGS_ERROR_FAILED,
@@ -903,9 +905,9 @@ write_wireless_setting(NMConnection *connection,
         svSetValueStr(ifcfg, "ESSID", str->str);
         g_string_free(str, TRUE);
     } else {
-        char buf[33];
+        char buf[NM_IW_ESSID_MAX_SIZE + 1];
 
-        nm_assert(ssid_len <= 32);
+        nm_assert(ssid_len <= NM_IW_ESSID_MAX_SIZE);
         memcpy(buf, ssid_data, ssid_len);
         buf[ssid_len] = '\0';
         svSetValueStr(ifcfg, "ESSID", buf);
@@ -1075,25 +1077,18 @@ write_hostname_setting(NMConnection *connection, shvarFile *ifcfg)
     svSetValueInt64_cond(ifcfg, "HOSTNAME_ONLY_FROM_DEFAULT", t != NM_TERNARY_DEFAULT, t);
 }
 
-static gboolean
-write_wired_setting(NMConnection *connection, shvarFile *ifcfg, GError **error)
+static void
+write_wired_setting_impl(NMSettingWired *s_wired, shvarFile *ifcfg, gboolean is_virtual)
 {
-    NMSettingWired *   s_wired;
     const char *const *s390_subchannels;
-    guint32            mtu, num_opts, i;
+    guint32            mtu;
+    guint32            num_opts;
+    guint32            i;
     const char *const *macaddr_blacklist;
 
-    s_wired = nm_connection_get_setting_wired(connection);
-    if (!s_wired) {
-        g_set_error(error,
-                    NM_SETTINGS_ERROR,
-                    NM_SETTINGS_ERROR_FAILED,
-                    "Missing '%s' setting",
-                    NM_SETTING_WIRED_SETTING_NAME);
-        return FALSE;
-    }
-
-    svSetValueStr(ifcfg, "HWADDR", nm_setting_wired_get_mac_address(s_wired));
+    svSetValue(ifcfg,
+               "HWADDR",
+               nm_setting_wired_get_mac_address(s_wired) ?: (is_virtual ? "" : NULL));
 
     svSetValueStr(ifcfg, "MACADDR", nm_setting_wired_get_cloned_mac_address(s_wired));
 
@@ -1167,8 +1162,42 @@ write_wired_setting(NMConnection *connection, shvarFile *ifcfg, GError **error)
             svSetValueStr(ifcfg, "OPTIONS", tmp->str);
     }
 
+    svSetValueTernary(ifcfg,
+                      "ACCEPT_ALL_MAC_ADDRESSES",
+                      nm_setting_wired_get_accept_all_mac_addresses(s_wired));
+}
+
+static gboolean
+write_wired_setting(NMConnection *connection, shvarFile *ifcfg, GError **error)
+{
+    NMSettingWired *s_wired;
+
+    s_wired = nm_connection_get_setting_wired(connection);
+    if (!s_wired) {
+        g_set_error(error,
+                    NM_SETTINGS_ERROR,
+                    NM_SETTINGS_ERROR_FAILED,
+                    "Missing '%s' setting",
+                    NM_SETTING_WIRED_SETTING_NAME);
+        return FALSE;
+    }
+
     svSetValueStr(ifcfg, "TYPE", TYPE_ETHERNET);
 
+    write_wired_setting_impl(s_wired, ifcfg, FALSE);
+    return TRUE;
+}
+
+static gboolean
+write_wired_for_virtual(NMConnection *connection, shvarFile *ifcfg)
+{
+    NMSettingWired *s_wired;
+
+    s_wired = nm_connection_get_setting_wired(connection);
+    if (!s_wired)
+        return FALSE;
+
+    write_wired_setting_impl(s_wired, ifcfg, TRUE);
     return TRUE;
 }
 
@@ -1334,6 +1363,26 @@ write_ethtool_setting(NMConnection *connection, shvarFile *ifcfg, GError **error
             g_string_append(str, nms_ifcfg_rh_utils_get_ethtool_name(ethtool_id));
             g_string_append_printf(str, " %" G_GUINT32_FORMAT, u32);
         }
+        for (ethtool_id = _NM_ETHTOOL_ID_PAUSE_FIRST; ethtool_id <= _NM_ETHTOOL_ID_PAUSE_LAST;
+             ethtool_id++) {
+            nm_assert(nms_ifcfg_rh_utils_get_ethtool_name(ethtool_id));
+            if (!nm_setting_option_get_boolean(NM_SETTING(s_ethtool),
+                                               nm_ethtool_data[ethtool_id]->optname,
+                                               &b))
+                continue;
+
+            _ethtool_gstring_prepare(&str, &is_first, 'A', iface);
+            g_string_append_c(str, ' ');
+            g_string_append(str, nms_ifcfg_rh_utils_get_ethtool_name(ethtool_id));
+            g_string_append(str, b ? " on" : " off");
+        }
+
+        if (!str) {
+            /* Write an empty dummy "-A" option without arguments. This is to
+             * ensure that the reader will create an (all default) NMSettingEthtool.
+             * Also, it seems that `ethtool -A "$IFACE"` is silently accepted. */
+            _ethtool_gstring_prepare(&str, &is_first, 'A', iface);
+        }
     }
 
     if (str) {
@@ -1367,35 +1416,6 @@ vlan_priority_maplist_to_stringlist(NMSettingVlan *s_vlan, NMVlanPriorityMap map
 }
 
 static gboolean
-write_wired_for_virtual(NMConnection *connection, shvarFile *ifcfg)
-{
-    NMSettingWired *s_wired;
-    gboolean        has_wired = FALSE;
-
-    s_wired = nm_connection_get_setting_wired(connection);
-    if (s_wired) {
-        const char *device_mac, *cloned_mac;
-        guint32     mtu;
-
-        has_wired = TRUE;
-
-        device_mac = nm_setting_wired_get_mac_address(s_wired);
-        svSetValue(ifcfg, "HWADDR", device_mac ?: "");
-
-        cloned_mac = nm_setting_wired_get_cloned_mac_address(s_wired);
-        svSetValueStr(ifcfg, "MACADDR", cloned_mac);
-
-        svSetValueStr(ifcfg,
-                      "GENERATE_MAC_ADDRESS_MASK",
-                      nm_setting_wired_get_generate_mac_address_mask(s_wired));
-
-        mtu = nm_setting_wired_get_mtu(s_wired);
-        svSetValueInt64_cond(ifcfg, "MTU", mtu != 0, mtu);
-    }
-    return has_wired;
-}
-
-static gboolean
 write_vlan_setting(NMConnection *connection, shvarFile *ifcfg, gboolean *wired, GError **error)
 {
     NMSettingVlan *s_vlan;
@@ -1542,36 +1562,40 @@ write_team_setting(NMConnection *connection, shvarFile *ifcfg, gboolean *wired,
 
 static gboolean
 write_bridge_vlans(NMSetting * setting,
-                   const char *property_name,
+                   gboolean    is_port,
                    shvarFile * ifcfg,
                    const char *key,
                    GError **   error)
 {
-    gs_unref_ptrarray GPtrArray *vlans = NULL;
-    NMBridgeVlan *               vlan;
-    GString *                    string;
-    guint                        i;
+    GPtrArray *              vlans;
+    NMBridgeVlan *           vlan;
+    nm_auto_str_buf NMStrBuf strbuf = NM_STR_BUF_INIT(0, FALSE);
+    guint                    i;
 
-    g_object_get(setting, property_name, &vlans, NULL);
+    if (is_port)
+        vlans = _nm_setting_bridge_port_get_vlans(NM_SETTING_BRIDGE_PORT(setting));
+    else
+        vlans = _nm_setting_bridge_get_vlans(NM_SETTING_BRIDGE(setting));
 
     if (!vlans || !vlans->len)
         return TRUE;
 
-    string = g_string_new("");
     for (i = 0; i < vlans->len; i++) {
         gs_free char *vlan_str = NULL;
 
         vlan     = vlans->pdata[i];
         vlan_str = nm_bridge_vlan_to_str(vlan, error);
-        if (!vlan_str)
-            return FALSE;
-        if (string->len > 0)
-            g_string_append(string, ",");
-        nm_utils_escaped_tokens_escape_gstr_assert(vlan_str, ",", string);
+        if (!vlan_str) {
+            /* nm_bridge_vlan_to_str() cannot fail (for now). */
+            nm_assert_not_reached();
+            continue;
+        }
+        if (strbuf.len > 0)
+            nm_str_buf_append_c(&strbuf, ',');
+        nm_str_buf_append(&strbuf, nm_utils_escaped_tokens_escape_unnecessary(vlan_str, ","));
     }
 
-    svSetValueStr(ifcfg, key, string->str);
-    g_string_free(string, TRUE);
+    svSetValueStr(ifcfg, key, nm_str_buf_get_str(&strbuf));
     return TRUE;
 }
 
@@ -1807,11 +1831,7 @@ write_bridge_setting(NMConnection *connection, shvarFile *ifcfg, gboolean *wired
         svSetValueStr(ifcfg, "BRIDGING_OPTS", opts->str);
     g_string_free(opts, TRUE);
 
-    if (!write_bridge_vlans((NMSetting *) s_bridge,
-                            NM_SETTING_BRIDGE_VLANS,
-                            ifcfg,
-                            "BRIDGE_VLANS",
-                            error))
+    if (!write_bridge_vlans((NMSetting *) s_bridge, FALSE, ifcfg, "BRIDGE_VLANS", error))
         return FALSE;
 
     svSetValueStr(ifcfg, "TYPE", TYPE_BRIDGE);
@@ -1862,11 +1882,7 @@ write_bridge_port_setting(NMConnection *connection, shvarFile *ifcfg, GError **e
         svSetValueStr(ifcfg, "BRIDGING_OPTS", string->str);
     g_string_free(string, TRUE);
 
-    if (!write_bridge_vlans((NMSetting *) s_port,
-                            NM_SETTING_BRIDGE_PORT_VLANS,
-                            ifcfg,
-                            "BRIDGE_PORT_VLANS",
-                            error))
+    if (!write_bridge_vlans((NMSetting *) s_port, TRUE, ifcfg, "BRIDGE_PORT_VLANS", error))
         return FALSE;
 
     return TRUE;
@@ -2824,6 +2840,9 @@ write_ip4_setting(NMConnection *connection,
     timeout = nm_setting_ip_config_get_dhcp_timeout(s_ip4);
     svSetValueInt64_cond(ifcfg, "IPV4_DHCP_TIMEOUT", timeout != 0, timeout);
 
+    timeout = nm_setting_ip_config_get_required_timeout(s_ip4);
+    svSetValueInt64_cond(ifcfg, "IPV4_REQUIRED_TIMEOUT", timeout != -1, timeout);
+
     svSetValueBoolean(ifcfg, "IPV4_FAILURE_FATAL", !nm_setting_ip_config_get_may_fail(s_ip4));
 
     route_metric = nm_setting_ip_config_get_route_metric(s_ip4);
@@ -3021,6 +3040,9 @@ write_ip6_setting(NMConnection *connection,
     timeout = nm_setting_ip_config_get_dhcp_timeout(s_ip6);
     svSetValueInt64_cond(ifcfg, "IPV6_DHCP_TIMEOUT", timeout != 0, timeout);
 
+    timeout = nm_setting_ip_config_get_required_timeout(s_ip6);
+    svSetValueInt64_cond(ifcfg, "IPV6_REQUIRED_TIMEOUT", timeout != -1, timeout);
+
     flags = nm_setting_ip_config_get_dhcp_hostname_flags(s_ip6);
     svSetValueInt64_cond(ifcfg,
                          "DHCPV6_HOSTNAME_FLAGS",
diff --git a/src/core/settings/plugins/ifcfg-rh/shvar.c b/src/core/settings/plugins/ifcfg-rh/shvar.c
index 386bcac7..d82efb3c 100644
--- a/src/core/settings/plugins/ifcfg-rh/shvar.c
+++ b/src/core/settings/plugins/ifcfg-rh/shvar.c
@@ -14,10 +14,11 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
-#include "nm-core-internal.h"
+#include "libnm-glib-aux/nm-str-buf.h"
+#include "libnm-core-intern/nm-core-internal.h"
 #include "nm-core-utils.h"
-#include "nm-glib-aux/nm-enum-utils.h"
-#include "nm-glib-aux/nm-io-utils.h"
+#include "libnm-glib-aux/nm-enum-utils.h"
+#include "libnm-glib-aux/nm-io-utils.h"
 #include "c-list/src/c-list.h"
 #include "nms-ifcfg-rh-utils.h"
 
@@ -152,17 +153,42 @@ _escape_ansic(const char *source)
     const char *p;
     char *      dest;
     char *      q;
+    gsize       n_alloc;
 
     nm_assert(source);
 
-    p = (const char *) source;
-    /* Each source byte needs maximally four destination chars (\777) */
-    q = dest = g_malloc(strlen(source) * 4 + 1 + 3);
+    n_alloc = 4;
+    for (p = source; p[0]; p++) {
+        switch (*p) {
+        case '\b':
+        case '\f':
+        case '\n':
+        case '\r':
+        case '\t':
+        case '\v':
+        case '\\':
+        case '"':
+        case '\'':
+            n_alloc += 2;
+            break;
+        default:
+            if (!nm_ascii_is_regular(*p))
+                n_alloc += 4;
+            else
+                n_alloc += 1;
+            break;
+        }
+    }
+
+    dest = g_malloc(n_alloc);
+
+    q = dest;
 
     *q++ = '$';
     *q++ = '\'';
 
-    while (*p) {
+    for (p = source; p[0]; p++) {
+        nm_assert(q < &dest[n_alloc]);
         switch (*p) {
         case '\b':
             *q++ = '\\';
@@ -195,7 +221,7 @@ _escape_ansic(const char *source)
             *q++ = *p;
             break;
         default:
-            if ((*p < ' ') || (*p >= 0177)) {
+            if (!nm_ascii_is_regular(*p)) {
                 *q++ = '\\';
                 *q++ = '0' + (((*p) >> 6) & 07);
                 *q++ = '0' + (((*p) >> 3) & 07);
@@ -204,12 +230,11 @@ _escape_ansic(const char *source)
                 *q++ = *p;
             break;
         }
-        p++;
     }
     *q++ = '\'';
     *q++ = '\0';
 
-    nm_assert(q - dest <= strlen(source) * 4 + 1 + 3);
+    nm_assert(q - dest == n_alloc);
 
     return dest;
 }
@@ -217,7 +242,7 @@ _escape_ansic(const char *source)
 /*****************************************************************************/
 
 #define _char_req_escape(ch)     NM_IN_SET(ch, '"', '\\', '$', '`')
-#define _char_req_escape_old(ch) NM_IN_SET(ch, '"', '\\', '\'', '$', '`', '~')
+#define _char_req_escape_old(ch) NM_IN_SET(ch, '"', '\\', '$', '`', '\'', '~')
 #define _char_req_quotes(ch)     NM_IN_SET(ch, ' ', '\'', '~', '\t', '|', '&', ';', '(', ')', '<', '>')
 
 const char *
@@ -226,29 +251,48 @@ svEscape(const char *s, char **to_free)
     char *new;
     gsize    mangle          = 0;
     gboolean requires_quotes = FALSE;
-    int      newlen;
-    size_t   i, j, slen;
+    gsize    n_alloc;
+    gsize    slen;
+    gsize    i;
+    gsize    j;
+    gboolean all_ascii = TRUE;
 
     for (slen = 0; s[slen]; slen++) {
         if (_char_req_escape(s[slen]))
             mangle++;
         else if (_char_req_quotes(s[slen]))
             requires_quotes = TRUE;
-        else if (s[slen] < ' ') {
-            /* if the string contains newline we can only express it using ANSI C quotation
-             * (as we don't support line continuation).
-             * Additionally, ANSI control characters look odd with regular quotation, so handle
-             * them too. */
-            return (*to_free = _escape_ansic(s));
+        else if (!nm_ascii_is_regular(s[slen])) {
+            if (nm_ascii_is_ctrl_or_del(s[slen])) {
+                /* if the string contains newline we can only express it using ANSI C quotation
+                 * (as we don't support line continuation).
+                 * Additionally, ANSI control characters look odd with regular quotation, so handle
+                 * them too. */
+                return (*to_free = _escape_ansic(s));
+            }
+            all_ascii       = FALSE;
+            requires_quotes = TRUE;
         }
     }
+
+    if (!all_ascii && !g_utf8_validate(s, -1, NULL)) {
+        /* The string is not valid ASCII/UTF-8. We can escape that via
+         * _escape_ansic(), however the reader might have a problem to
+         * do something sensible with the blob later.
+         *
+         * This is really a bug of the caller, which should not present us with
+         * non-text in the first place. But at this place, we cannot handle the
+         * error better, so just escape it. */
+        return (*to_free = _escape_ansic(s));
+    }
+
     if (!mangle && !requires_quotes) {
         *to_free = NULL;
         return s;
     }
 
-    newlen = slen + mangle + 3; /* 3 is extra ""\0 */
-    new    = g_malloc(newlen);
+    n_alloc = slen + mangle + 3; /* 3 is extra ""\0 */
+    new     = g_malloc(n_alloc);
 
     j        = 0;
     new[j++] = '"';
@@ -260,7 +304,7 @@ svEscape(const char *s, char **to_free)
     new[j++] = '"';
     new[j++] = '\0';
 
-    nm_assert(j == slen + mangle + 3);
+    nm_assert(j == n_alloc);
 
     *to_free = new;
     return new;
@@ -318,14 +362,14 @@ _ch_hex_get(char ch)
 }
 
 static void
-_gstr_init(GString **str, const char *value, gsize i)
+_strbuf_init(NMStrBuf *str, const char *value, gsize i)
 {
     nm_assert(str);
     nm_assert(value);
 
-    if (!(*str)) {
-        /* if @str is not yet initialized, it allocates
-         * a new GString and copies @i characters from
+    if (str->allocated == 0) {
+        /* if @str is not yet initialized, it initializes
+         * a new NMStrBuf and copies @i characters from
          * @value over.
          *
          * Unescaping usually does not extend the length of a string,
@@ -335,20 +379,26 @@ _gstr_init(GString **str, const char *value, gsize i)
          * (FACTOR*strlen(value) + CONST), which is non trivial to get
          * right in all cases. Also, we would have to provision for the
          * very unlikely extreme case.
-         * Instead, use a GString buffer which can grow as needed. But for an
+         * Instead, use a NMStrBuf buffer which can grow as needed. But for an
          * initial guess, strlen(value) is a good start */
-        *str = g_string_new_len(NULL, strlen(value) + 3);
-        if (i)
-            g_string_append_len(*str, value, i);
+        nm_str_buf_maybe_expand(str, strlen(value) + 3u, FALSE);
+        nm_str_buf_append_len(str, value, i);
     }
 }
 
 const char *
 svUnescape(const char *value, char **to_free)
 {
-    gsize    i, j;
-    GString *str                      = NULL;
+    return svUnescape_full(value, to_free, TRUE);
+}
+
+const char *
+svUnescape_full(const char *value, char **to_free, gboolean check_utf8)
+{
+    NMStrBuf str                      = NM_STR_BUF_INIT(0, FALSE);
     int      looks_like_old_svescaped = -1;
+    gsize    i;
+    gsize    j;
 
     /* we handle bash syntax here (note that ifup has #!/bin/bash.
      * Thus, see https://www.gnu.org/software/bash/manual/html_node/Quoting.html#Quoting */
@@ -395,20 +445,20 @@ svUnescape(const char *value, char **to_free)
 
         if (value[i] == '\\') {
             /* backslash escape */
-            _gstr_init(&str, value, i);
+            _strbuf_init(&str, value, i);
             i++;
             if (G_UNLIKELY(value[i] == '\0')) {
                 /* we don't support line continuation */
                 goto out_error;
             }
-            g_string_append_c(str, value[i]);
+            nm_str_buf_append_c(&str, value[i]);
             i++;
             goto loop1_next;
         }
 
         if (value[i] == '\'') {
             /* single quotes */
-            _gstr_init(&str, value, i);
+            _strbuf_init(&str, value, i);
             i++;
             j = i;
             while (TRUE) {
@@ -420,14 +470,14 @@ svUnescape(const char *value, char **to_free)
                     break;
                 j++;
             }
-            g_string_append_len(str, &value[i], j - i);
+            nm_str_buf_append_len(&str, &value[i], j - i);
             i = j + 1;
             goto loop1_next;
         }
 
         if (value[i] == '"') {
             /* double quotes */
-            _gstr_init(&str, value, i);
+            _strbuf_init(&str, value, i);
             i++;
             while (TRUE) {
                 if (value[i] == '"') {
@@ -466,11 +516,11 @@ svUnescape(const char *value, char **to_free)
                         if (looks_like_old_svescaped < 0)
                             looks_like_old_svescaped = _looks_like_old_svescaped(value);
                         if (!looks_like_old_svescaped)
-                            g_string_append_c(str, '\\');
+                            nm_str_buf_append_c(&str, '\\');
                     } else
-                        g_string_append_c(str, '\\');
+                        nm_str_buf_append_c(&str, '\\');
                 }
-                g_string_append_c(str, value[i]);
+                nm_str_buf_append_c(&str, value[i]);
                 i++;
             }
             goto loop1_next;
@@ -478,7 +528,7 @@ svUnescape(const char *value, char **to_free)
 
         if (value[i] == '$' && value[i + 1] == '\'') {
             /* ANSI-C Quoting */
-            _gstr_init(&str, value, i);
+            _strbuf_init(&str, value, i);
             i += 2;
             while (TRUE) {
                 char ch;
@@ -552,7 +602,7 @@ svUnescape(const char *value, char **to_free)
                                 }
                             }
                             /* like bash, we cut too large numbers off. E.g. A=$'\772' becomes 0xfa  */
-                            g_string_append_c(str, (guint8) v);
+                            nm_str_buf_append_c(&str, (guint8) v);
                         } else if (NM_IN_SET(value[i], 'x', 'u', 'U')) {
                             const char escape_type = value[i];
                             int max_digits = escape_type == 'x' ? 2 : escape_type == 'u' ? 4 : 8;
@@ -561,8 +611,7 @@ svUnescape(const char *value, char **to_free)
                             i++;
                             if (!_ch_hex_is(value[i])) {
                                 /* missing hex value after "\x" escape. This is treated like no escaping. */
-                                g_string_append_c(str, '\\');
-                                g_string_append_c(str, escape_type);
+                                nm_str_buf_append_c(&str, '\\', escape_type);
                             } else {
                                 v = _ch_hex_get(value[i]);
                                 i++;
@@ -574,22 +623,21 @@ svUnescape(const char *value, char **to_free)
                                     i++;
                                 }
                                 if (escape_type == 'x')
-                                    g_string_append_c(str, v);
+                                    nm_str_buf_append_c(&str, v);
                                 else {
                                     /* we treat the unicode escapes as utf-8 encoded values. */
-                                    g_string_append_unichar(str, v);
+                                    nm_str_buf_append_unichar(&str, v);
                                 }
                             }
                         } else {
-                            g_string_append_c(str, '\\');
-                            g_string_append_c(str, value[i]);
+                            nm_str_buf_append_c(&str, '\\', value[i]);
                             i++;
                         }
                         goto loop_ansic_next;
                     }
                 } else
                     ch = value[i];
-                g_string_append_c(str, ch);
+                nm_str_buf_append_c(&str, ch);
                 i++;
 loop_ansic_next:;
             }
@@ -603,8 +651,8 @@ loop_ansic_next:;
         }
 
         /* an unquoted, regular character. Just consume it directly. */
-        if (str)
-            g_string_append_c(str, value[i]);
+        if (str.allocated > 0)
+            nm_str_buf_append_c(&str, value[i]);
         i++;
 
 loop1_next:;
@@ -614,22 +662,30 @@ loop1_next:;
 
 out_value:
     if (i == 0) {
-        nm_assert(!str);
+        nm_assert(str.allocated == 0);
+        nm_assert(!str._priv_str);
         *to_free = NULL;
         return "";
     }
 
-    if (str) {
-        if (str->len == 0 || str->str[0] == '\0') {
-            g_string_free(str, TRUE);
+    if (str.allocated > 0) {
+        if (check_utf8 && !nm_str_buf_utf8_validate(&str))
+            goto out_error;
+        if (str.len == 0 || nm_str_buf_get_str_unsafe(&str)[0] == '\0') {
+            nm_str_buf_destroy(&str);
             *to_free = NULL;
             return "";
         } else {
-            *to_free = g_string_free(str, FALSE);
+            *to_free = nm_str_buf_finalize(&str, NULL);
             return *to_free;
         }
     }
 
+    if (check_utf8 && !g_utf8_validate(value, i, NULL)) {
+        *to_free = NULL;
+        return NULL;
+    }
+
     if (value[i] != '\0') {
         *to_free = g_strndup(value, i);
         return *to_free;
@@ -639,8 +695,7 @@ out_value:
     return value;
 
 out_error:
-    if (str)
-        g_string_free(str, TRUE);
+    nm_str_buf_destroy(&str);
     *to_free = NULL;
     return NULL;
 }
@@ -1095,9 +1150,8 @@ _svGetValue(shvarFile *s, const char *key, char **to_free)
     if (line && line->line) {
         v = svUnescape(line->line, to_free);
         if (!v) {
-            /* a wrongly quoted value is treated like the empty string.
-             * See also svWriteFile(), which handles unparsable values
-             * that way. */
+            /* a wrongly quoted value or non-UTF-8 is treated like the empty string.
+             * See also svWriteFile(), which handles unparsable values that way. */
             nm_assert(!*to_free);
             return "";
         }
@@ -1470,6 +1524,91 @@ svUnsetValue(shvarFile *s, const char *key)
 
 /*****************************************************************************/
 
+void
+svWarnInvalid(shvarFile *s, const char *file_type, NMLogDomain log_domain)
+{
+    shvarLine *line;
+    gsize      n;
+
+    if (!nm_logging_enabled(LOGL_WARN, log_domain))
+        return;
+
+    n = 0;
+    c_list_for_each_entry (line, &s->lst_head, lst) {
+        gs_free char *s_tmp = NULL;
+
+        n++;
+
+        if (!line->key) {
+            const char *str;
+
+            nm_assert(line->line);
+            str = nm_str_skip_leading_spaces(line->line);
+            if (!NM_IN_SET(str[0], '\0', '#')) {
+                nm_log_warn(log_domain,
+                            "ifcfg-rh: %s,%s:%zu: invalid line ignored",
+                            file_type,
+                            s->fileName,
+                            n);
+            }
+            continue;
+        }
+
+        if (g_hash_table_lookup(s->lst_idx, line) != line) {
+            nm_log_warn(
+                log_domain,
+                "ifcfg-rh: %s,%s:%zu: key %s is duplicated and the early occurrence ignored",
+                file_type,
+                s->fileName,
+                n,
+                line->key);
+            continue;
+        }
+
+        if (!line->line) {
+            /* the line is deleted via svUnsetValue(). Ignore. */
+            continue;
+        }
+
+        if (!svUnescape(line->line, &s_tmp)) {
+            if (!svUnescape_full(line->line, &s_tmp, FALSE)) {
+                nm_log_warn(log_domain,
+                            "ifcfg-rh: %s,%s:%zu: key %s is badly quoted and is treated as \"\"",
+                            file_type,
+                            s->fileName,
+                            n,
+                            line->key);
+            } else {
+                nm_log_warn(log_domain,
+                            "ifcfg-rh: %s,%s:%zu: key %s does not contain valid UTF-8 and is "
+                            "treated as \"\"",
+                            file_type,
+                            s->fileName,
+                            n,
+                            line->key);
+            }
+            continue;
+        }
+
+        /* TODO: we read different shell scripts, and whether a key is recognized
+         * depends on the type. For example, alias files only accept a subset of
+         * known keys.
+         *
+         * Basically, depending on the @file_type, different keys are valid. */
+        if (!nms_ifcfg_rh_utils_is_well_known_key(line->key)) {
+            nm_log_dbg(log_domain,
+                       "ifcfg-rh: %s,%s:%zu: key %s is unknown and ignored",
+                       file_type,
+                       s->fileName,
+                       n,
+                       line->key);
+            continue;
+        }
+    }
+}
+
+/*****************************************************************************/
+
 /* Write the current contents iff modified.  Returns FALSE on error
  * and TRUE on success.  Do not write if no values have been modified.
  * The mode argument is only used if creating the file, not if
diff --git a/src/core/settings/plugins/ifcfg-rh/shvar.h b/src/core/settings/plugins/ifcfg-rh/shvar.h
index 6965d873..cf91642f 100644
--- a/src/core/settings/plugins/ifcfg-rh/shvar.h
+++ b/src/core/settings/plugins/ifcfg-rh/shvar.h
@@ -107,6 +107,7 @@ void svCloseFile(shvarFile *s);
 
 const char *svEscape(const char *s, char **to_free);
 const char *svUnescape(const char *s, char **to_free);
+const char *svUnescape_full(const char *value, char **to_free, gboolean check_utf8);
 
 static inline void
 _nm_auto_shvar_file_close(shvarFile **p_s)
@@ -120,4 +121,6 @@ _nm_auto_shvar_file_close(shvarFile **p_s)
 }
 #define nm_auto_shvar_file_close nm_auto(_nm_auto_shvar_file_close)
 
+void svWarnInvalid(shvarFile *s, const char *file_type, NMLogDomain log_domain);
+
 #endif /* _SHVAR_H */
diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-bridge-component-a.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-bridge-component-a.cexpected
index d81d9187..aebcd2b8 100644
--- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-bridge-component-a.cexpected
+++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-bridge-component-a.cexpected
@@ -1,5 +1,5 @@
-HWADDR=00:22:15:59:62:97
 TYPE=Ethernet
+HWADDR=00:22:15:59:62:97
 BRIDGING_OPTS="priority=28 hairpin_mode=1"
 NAME="System test-bridge-component"
 UUID=${UUID}
diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-bridge-component-b.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-bridge-component-b.cexpected
index 2e69c5e7..71d2cda8 100644
--- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-bridge-component-b.cexpected
+++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-bridge-component-b.cexpected
@@ -1,5 +1,5 @@
-HWADDR=00:22:15:59:62:97
 TYPE=Ethernet
+HWADDR=00:22:15:59:62:97
 NAME="System test-bridge-component"
 UUID=${UUID}
 DEVICE=eth0
diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-wired-802-1X-subj-matches.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-wired-802-1X-subj-matches.cexpected
index 59a6f79b..240cd5c1 100644
--- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-wired-802-1X-subj-matches.cexpected
+++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-wired-802-1X-subj-matches.cexpected
@@ -1,5 +1,5 @@
-HWADDR=00:11:22:33:44:EE
 TYPE=Ethernet
+HWADDR=00:11:22:33:44:EE
 KEY_MGMT=IEEE8021X
 IEEE_8021X_EAP_METHODS=PEAP
 IEEE_8021X_IDENTITY="Jara Cimrman"
diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bridge_Component.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bridge_Component.cexpected
index a8ff8df3..d31d8ff5 100644
--- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bridge_Component.cexpected
+++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bridge_Component.cexpected
@@ -1,6 +1,6 @@
+TYPE=Ethernet
 HWADDR=31:33:33:37:BE:CD
 MTU=1492
-TYPE=Ethernet
 BRIDGING_OPTS="priority=50 path_cost=33"
 BRIDGE_PORT_VLANS="1 untagged,2 pvid,4-4094 untagged"
 NAME="Test Write Bridge Component"
diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected
index cd8fc96f..cc29a2cc 100644
--- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected
+++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected
@@ -1,6 +1,6 @@
+TYPE=Ethernet
 HWADDR=31:33:33:37:BE:CD
 MTU=1492
-TYPE=Ethernet
 PROXY_METHOD=none
 BROWSER_ONLY=no
 BOOTPROTO=none
diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-static-routes-legacy.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-static-routes-legacy.cexpected
index a28c5c1c..8197f320 100644
--- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-static-routes-legacy.cexpected
+++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-static-routes-legacy.cexpected
@@ -1,5 +1,5 @@
-HWADDR=00:16:41:11:22:33
 TYPE=Ethernet
+HWADDR=00:16:41:11:22:33
 PROXY_METHOD=none
 BROWSER_ONLY=no
 BOOTPROTO=dhcp
diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-vlanid-use b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-vlanid-use
new file mode 100644
index 00000000..fc9c8a45
--- /dev/null
+++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-vlanid-use
@@ -0,0 +1,4 @@
+VLAN=yes
+TYPE=Vlan
+DEVICE=eth0.9
+VLAN_ID=10
diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-vlanid-use.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-vlanid-use.cexpected
new file mode 100644
index 00000000..a7be14ce
--- /dev/null
+++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-vlanid-use.cexpected
@@ -0,0 +1,15 @@
+VLAN=yes
+TYPE=Vlan
+PHYSDEV=eth0
+VLAN_ID=10
+REORDER_HDR=yes
+GVRP=no
+MVRP=no
+HWADDR=
+PROXY_METHOD=none
+BROWSER_ONLY=no
+IPV6INIT=no
+NAME="Vlan test-vlan-vlanid-use"
+UUID=${UUID}
+DEVICE=eth0.9
+ONBOOT=yes
diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-wpa-eap-suite-b-192-tls b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-wpa-eap-suite-b-192-tls
index 9a74bb4d..a21c301c 100644
--- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-wpa-eap-suite-b-192-tls
+++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-wpa-eap-suite-b-192-tls
@@ -3,7 +3,6 @@ DEVICE=eth2
 HWADDR=00:16:41:11:22:33
 BOOTPROTO=dhcp
 ONBOOT=yes
-ONBOOT=yes
 USERCTL=yes
 IPV6INIT=no
 NM_CONTROLLED=yes
diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-wpa-eap-ttls-tls b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-wpa-eap-ttls-tls
index 42ed1d68..bb63d5e8 100644
--- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-wpa-eap-ttls-tls
+++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-wpa-eap-ttls-tls
@@ -4,7 +4,6 @@ DEVICE=eth2
 HWADDR=00:16:41:11:22:33
 BOOTPROTO=dhcp
 ONBOOT=yes
-ONBOOT=yes
 USERCTL=yes
 IPV6INIT=no
 NM_CONTROLLED=yes
diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-write-unknown-4.expected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-write-unknown-4.expected
index 040ddc9d..92c03b12 100644
--- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-write-unknown-4.expected
+++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-write-unknown-4.expected
@@ -13,8 +13,10 @@
 #L2
 
 METRIC1=''
-METRIC2=$'\U0x'
-METRIC3=$'x\U0'
+METRIC2=
+#NM: METRIC2=$'\U0x'
+METRIC3=
+#NM: METRIC3=$'x\U0'
 
 #L4
 IPADDR=set-by-test1
diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-1.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-1.cexpected
new file mode 100644
index 00000000..5186f90c
--- /dev/null
+++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-1.cexpected
@@ -0,0 +1,14 @@
+TYPE=Ethernet
+PROXY_METHOD=none
+BROWSER_ONLY=no
+BOOTPROTO=dhcp
+DEFROUTE=yes
+IPV4_FAILURE_FATAL=no
+IPV6INIT=yes
+IPV6_AUTOCONF=yes
+IPV6_DEFROUTE=yes
+IPV6_FAILURE_FATAL=no
+IPV6_ADDR_GEN_MODE=stable-privacy
+NAME=test_roundtrip_ethtool
+UUID=${UUID}
+ONBOOT=yes
diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-2.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-2.cexpected
new file mode 100644
index 00000000..5632ebec
--- /dev/null
+++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-2.cexpected
@@ -0,0 +1,15 @@
+TYPE=Ethernet
+PROXY_METHOD=none
+BROWSER_ONLY=no
+ETHTOOL_OPTS="-A net0"
+BOOTPROTO=dhcp
+DEFROUTE=yes
+IPV4_FAILURE_FATAL=no
+IPV6INIT=yes
+IPV6_AUTOCONF=yes
+IPV6_DEFROUTE=yes
+IPV6_FAILURE_FATAL=no
+IPV6_ADDR_GEN_MODE=stable-privacy
+NAME=test_roundtrip_ethtool
+UUID=${UUID}
+ONBOOT=yes
diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-3.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-3.cexpected
new file mode 100644
index 00000000..96eec43b
--- /dev/null
+++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-3.cexpected
@@ -0,0 +1,15 @@
+TYPE=Ethernet
+PROXY_METHOD=none
+BROWSER_ONLY=no
+ETHTOOL_OPTS="autoneg on"
+BOOTPROTO=dhcp
+DEFROUTE=yes
+IPV4_FAILURE_FATAL=no
+IPV6INIT=yes
+IPV6_AUTOCONF=yes
+IPV6_DEFROUTE=yes
+IPV6_FAILURE_FATAL=no
+IPV6_ADDR_GEN_MODE=stable-privacy
+NAME=test_roundtrip_ethtool
+UUID=${UUID}
+ONBOOT=yes
diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-4.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-4.cexpected
new file mode 100644
index 00000000..90250a30
--- /dev/null
+++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-4.cexpected
@@ -0,0 +1,15 @@
+TYPE=Ethernet
+PROXY_METHOD=none
+BROWSER_ONLY=no
+ETHTOOL_OPTS="-K net0 rx on"
+BOOTPROTO=dhcp
+DEFROUTE=yes
+IPV4_FAILURE_FATAL=no
+IPV6INIT=yes
+IPV6_AUTOCONF=yes
+IPV6_DEFROUTE=yes
+IPV6_FAILURE_FATAL=no
+IPV6_ADDR_GEN_MODE=stable-privacy
+NAME=test_roundtrip_ethtool
+UUID=${UUID}
+ONBOOT=yes
diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-5.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-5.cexpected
new file mode 100644
index 00000000..721eacb2
--- /dev/null
+++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-5.cexpected
@@ -0,0 +1,15 @@
+TYPE=Ethernet
+PROXY_METHOD=none
+BROWSER_ONLY=no
+ETHTOOL_OPTS="autoneg on ; -K net0 rx on"
+BOOTPROTO=dhcp
+DEFROUTE=yes
+IPV4_FAILURE_FATAL=no
+IPV6INIT=yes
+IPV6_AUTOCONF=yes
+IPV6_DEFROUTE=yes
+IPV6_FAILURE_FATAL=no
+IPV6_ADDR_GEN_MODE=stable-privacy
+NAME=test_roundtrip_ethtool
+UUID=${UUID}
+ONBOOT=yes
diff --git a/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
index 9d9ed626..d9829f84 100644
--- a/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
+++ b/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
@@ -17,7 +17,8 @@
 #include <linux/if_ether.h>
 #include <linux/if_infiniband.h>
 
-#include "nm-glib-aux/nm-json-aux.h"
+#include "libnm-glib-aux/nm-uuid.h"
+#include "libnm-glib-aux/nm-json-aux.h"
 #include "nm-utils.h"
 #include "nm-setting-connection.h"
 #include "nm-setting-wired.h"
@@ -36,9 +37,9 @@
 #include "nm-setting-serial.h"
 #include "nm-setting-vlan.h"
 #include "nm-setting-dcb.h"
-#include "nm-core-internal.h"
-#include "nm-base/nm-ethtool-base.h"
-#include "nm-base/nm-ethtool-utils-base.h"
+#include "libnm-core-intern/nm-core-internal.h"
+#include "libnm-base/nm-ethtool-base.h"
+#include "libnm-base/nm-ethtool-utils-base.h"
 
 #include "NetworkManagerUtils.h"
 
@@ -180,8 +181,20 @@ _assert_expected_content(NMConnection *connection, const char *filename, const c
     }
 
     if (len_expectd != len_written || memcmp(content_expectd, content_written, len_expectd) != 0) {
-        if (g_getenv("NMTST_IFCFG_RH_UPDATE_EXPECTED")
-            || nm_streq0(g_getenv("NM_TEST_REGENERATE"), "1")) {
+        static int rewrite_static = 0;
+        int        rewrite;
+
+        rewrite = g_atomic_int_get(&rewrite_static);
+        if (G_UNLIKELY(rewrite == 0)) {
+            rewrite = (g_getenv("NMTST_IFCFG_RH_UPDATE_EXPECTED")
+                       || nm_streq0(g_getenv("NM_TEST_REGENERATE"), "1"))
+                          ? 1
+                          : -1;
+            if (!g_atomic_int_compare_and_exchange(&rewrite_static, 0, rewrite))
+                g_assert_not_reached();
+        }
+
+        if (rewrite > 0) {
             if (uuid) {
                 gs_free char *search = g_strdup_printf("UUID=%s\n", uuid);
                 const char *  s;
@@ -209,15 +222,16 @@ _assert_expected_content(NMConnection *connection, const char *filename, const c
             success = g_file_set_contents(expected, content_written, len_written, &error);
             nmtst_assert_success(success, error);
         } else {
-            g_error("The content of \"%s\" (%zu) differs from \"%s\" (%zu). Set "
-                    "NMTST_IFCFG_RH_UPDATE_EXPECTED=yes to update the files "
-                    "inplace\n\n>>>%s<<<\n\n>>>%s<<<\n",
-                    filename,
-                    len_written,
-                    expected,
-                    len_expectd,
-                    content_written,
-                    content_expectd);
+            g_error(
+                "The content of \"%s\" (%zu) differs from \"%s\" (%zu). Set "
+                "NMTST_IFCFG_RH_UPDATE_EXPECTED=yes (or NM_TEST_REGENERATE=1) to update the files "
+                "inplace\n\n>>>%s<<<\n\n>>>%s<<<\n",
+                filename,
+                len_written,
+                expected,
+                len_expectd,
+                content_written,
+                content_expectd);
         }
     }
 }
@@ -359,8 +373,10 @@ _writer_new_connection_reread(NMConnection * connection,
 
     if (out_filename)
         *out_filename = filename;
-    else
+    else {
+        nmtst_file_unlink(filename);
         g_free(filename);
+    }
 }
 
 static void
@@ -722,10 +738,13 @@ test_read_variables_corner_cases(void)
     const char *         mac;
     char                 expected_mac_address[ETH_ALEN] = {0x00, 0x16, 0x41, 0x11, 0x22, 0x33};
 
+    NMTST_EXPECT_NM_WARN("*key NAME is badly quoted and is treated as \"\"*");
+    NMTST_EXPECT_NM_WARN("*key ZONE is badly quoted and is treated as \"\"*");
     connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-variables-corner-cases-1",
                                        NULL,
                                        TYPE_ETHERNET,
                                        NULL);
+    g_test_assert_expected_messages();
 
     /* ===== CONNECTION SETTING ===== */
     s_con = nm_connection_get_setting_connection(connection);
@@ -814,10 +833,12 @@ test_read_unrecognized(void)
     gs_free char *       unhandled_spec     = NULL;
     guint64              expected_timestamp = 0;
 
+    NMTST_EXPECT_NM_WARN("*key NAME is badly quoted and is treated as \"\"*");
     connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-unrecognized",
                                        NULL,
                                        NULL,
                                        &unhandled_spec);
+    g_test_assert_expected_messages();
     g_assert_cmpstr(unhandled_spec, ==, "unrecognized:mac:00:11:22:33");
 
     /* ===== CONNECTION SETTING ===== */
@@ -988,10 +1009,12 @@ test_read_wired_dhcp(void)
     char                 expected_mac_address[ETH_ALEN] = {0x00, 0x11, 0x22, 0x33, 0x44, 0xee};
     const char *         mac;
 
+    NMTST_EXPECT_NM_WARN("*key IPV6INIT is duplicated and the early occurrence ignored*");
     connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wired-dhcp",
                                        NULL,
                                        TYPE_ETHERNET,
                                        &unmanaged);
+    g_test_assert_expected_messages();
     g_assert(unmanaged == NULL);
 
     /* ===== CONNECTION SETTING ===== */
@@ -2519,7 +2542,7 @@ test_write_dns_options(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test DNS options",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -3567,10 +3590,12 @@ test_read_wifi_wpa_eap_tls(void)
     char *             unmanaged                 = NULL;
     const char *       expected_privkey_password = "test1";
 
+    NMTST_EXPECT_NM_WARN("*key ONBOOT is duplicated and the early occurrence ignored*");
     connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wifi-wpa-eap-tls",
                                        NULL,
                                        TYPE_ETHERNET,
                                        &unmanaged);
+    g_test_assert_expected_messages();
     g_assert(!unmanaged);
 
     /* ===== WIRELESS SETTING ===== */
@@ -3775,10 +3800,12 @@ test_read_wifi_wep_eap_ttls_chap(void)
     NMSetting8021x *           s_8021x;
     char *                     unmanaged = NULL;
 
+    NMTST_EXPECT_NM_WARN("*key ONBOOT is duplicated and the early occurrence ignored*");
     connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wifi-wep-eap-ttls-chap",
                                        NULL,
                                        TYPE_WIRELESS,
                                        &unmanaged);
+    g_test_assert_expected_messages();
     g_assert(!unmanaged);
 
     /* ===== WIRELESS SETTING ===== */
@@ -3933,6 +3960,76 @@ test_read_wired_unknown_ethtool_opt(void)
 }
 
 static void
+test_roundtrip_ethtool(void)
+{
+    gs_unref_object NMConnection *connection = NULL;
+    NMSetting *                   s_ethtool;
+    NMSetting *                   s_wired;
+
+    connection = nmtst_create_minimal_connection("test_roundtrip_ethtool",
+                                                 NULL,
+                                                 NM_SETTING_WIRED_SETTING_NAME,
+                                                 NULL);
+    _writer_new_connec_exp(connection,
+                           TEST_SCRATCH_DIR,
+                           TEST_IFCFG_DIR "/ifcfg-test_roundtrip_ethtool-1.cexpected",
+                           NULL);
+    g_clear_object(&connection);
+
+    connection = nmtst_create_minimal_connection("test_roundtrip_ethtool",
+                                                 NULL,
+                                                 NM_SETTING_WIRED_SETTING_NAME,
+                                                 NULL);
+    s_ethtool  = nm_setting_ethtool_new();
+    nm_connection_add_setting(connection, s_ethtool);
+    _writer_new_connec_exp(connection,
+                           TEST_SCRATCH_DIR,
+                           TEST_IFCFG_DIR "/ifcfg-test_roundtrip_ethtool-2.cexpected",
+                           NULL);
+    g_clear_object(&connection);
+
+    connection = nmtst_create_minimal_connection("test_roundtrip_ethtool",
+                                                 NULL,
+                                                 NM_SETTING_WIRED_SETTING_NAME,
+                                                 NULL);
+    s_wired    = nm_connection_get_setting(connection, NM_TYPE_SETTING_WIRED);
+    g_object_set(s_wired, NM_SETTING_WIRED_AUTO_NEGOTIATE, TRUE, NULL);
+    _writer_new_connec_exp(connection,
+                           TEST_SCRATCH_DIR,
+                           TEST_IFCFG_DIR "/ifcfg-test_roundtrip_ethtool-3.cexpected",
+                           NULL);
+    g_clear_object(&connection);
+
+    connection = nmtst_create_minimal_connection("test_roundtrip_ethtool",
+                                                 NULL,
+                                                 NM_SETTING_WIRED_SETTING_NAME,
+                                                 NULL);
+    s_ethtool  = nm_setting_ethtool_new();
+    nm_connection_add_setting(connection, s_ethtool);
+    nm_setting_option_set_boolean(s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_RX, TRUE);
+    _writer_new_connec_exp(connection,
+                           TEST_SCRATCH_DIR,
+                           TEST_IFCFG_DIR "/ifcfg-test_roundtrip_ethtool-4.cexpected",
+                           NULL);
+    g_clear_object(&connection);
+
+    connection = nmtst_create_minimal_connection("test_roundtrip_ethtool",
+                                                 NULL,
+                                                 NM_SETTING_WIRED_SETTING_NAME,
+                                                 NULL);
+    s_wired    = nm_connection_get_setting(connection, NM_TYPE_SETTING_WIRED);
+    g_object_set(s_wired, NM_SETTING_WIRED_AUTO_NEGOTIATE, TRUE, NULL);
+    s_ethtool = nm_setting_ethtool_new();
+    nm_connection_add_setting(connection, s_ethtool);
+    nm_setting_option_set_boolean(s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_RX, TRUE);
+    _writer_new_connec_exp(connection,
+                           TEST_SCRATCH_DIR,
+                           TEST_IFCFG_DIR "/ifcfg-test_roundtrip_ethtool-5.cexpected",
+                           NULL);
+    g_clear_object(&connection);
+}
+
+static void
 test_read_wifi_hidden(void)
 {
     NMConnection *       connection;
@@ -3977,7 +4074,7 @@ test_write_wifi_hidden(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Wi-Fi Hidden",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_TYPE,
                  NM_SETTING_WIRELESS_SETTING_NAME,
                  NULL);
@@ -4062,7 +4159,7 @@ test_write_wifi_mac_random(gconstpointer user_data)
                  NM_SETTING_CONNECTION_ID,
                  val,
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_TYPE,
                  NM_SETTING_WIRELESS_SETTING_NAME,
                  NULL);
@@ -4122,7 +4219,7 @@ test_write_wired_wake_on_lan(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Wired Wake-on-LAN",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_TYPE,
                  NM_SETTING_WIRED_SETTING_NAME,
                  NULL);
@@ -4305,7 +4402,7 @@ test_write_wifi_band_a(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Wi-Fi Band A",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_TYPE,
                  NM_SETTING_WIRELESS_SETTING_NAME,
                  NULL);
@@ -4363,7 +4460,7 @@ test_write_wifi_ap_mode(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Wi-Fi AP Mode",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_TYPE,
                  NM_SETTING_WIRELESS_SETTING_NAME,
                  NULL);
@@ -4676,7 +4773,7 @@ test_write_wired_static(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Wired Static",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_AUTOCONNECT_RETRIES,
@@ -4831,7 +4928,7 @@ test_write_wired_static_with_generic(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Wired Static",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_AUTOCONNECT_RETRIES,
@@ -4999,7 +5096,7 @@ test_write_wired_dhcp(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Wired DHCP",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -5111,7 +5208,7 @@ test_write_routing_rules(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Routing Rules",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -5169,7 +5266,7 @@ test_write_wired_match(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Wired with Match setting",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -5315,7 +5412,7 @@ test_write_wired_static_ip6_only(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Wired Static IP6 Only",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -5432,7 +5529,7 @@ test_write_wired_static_ip6_only_gw(gconstpointer user_data)
                  NM_SETTING_CONNECTION_ID,
                  id,
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -5587,7 +5684,7 @@ test_write_wired_static_routes(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Wired Static Routes",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -5711,7 +5808,7 @@ test_write_wired_dhcp_8021x_peap_mschapv2(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Wired DHCP 802.1x PEAP MSCHAPv2",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -5813,7 +5910,7 @@ test_write_wired_8021x_tls(gconstpointer test_data)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Wired 802.1x TLS Blobs",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -5983,7 +6080,7 @@ test_write_wired_aliases(void)
                  NM_SETTING_CONNECTION_ID,
                  "alias0",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_TYPE,
                  NM_SETTING_WIRED_SETTING_NAME,
                  NULL);
@@ -6110,7 +6207,7 @@ test_write_gateway(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Static Addresses Gateway",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_TYPE,
                  NM_SETTING_WIRED_SETTING_NAME,
                  NULL);
@@ -6187,7 +6284,7 @@ test_write_wifi_open(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Wifi Open",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -6273,7 +6370,7 @@ test_write_wifi_open_hex_ssid(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Wifi Open Hex SSID",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -6347,7 +6444,7 @@ test_write_wifi_wep(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Wifi WEP",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -6445,7 +6542,7 @@ test_write_wifi_wep_adhoc(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Wifi WEP AdHoc",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -6539,7 +6636,7 @@ test_write_wifi_wep_passphrase(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Wifi WEP Passphrase",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -6634,7 +6731,7 @@ test_write_wifi_wep_40_ascii(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Wifi WEP 40 ASCII",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -6732,7 +6829,7 @@ test_write_wifi_wep_104_ascii(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Wifi WEP 104 ASCII",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -6833,7 +6930,7 @@ test_write_wifi_leap(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Wifi LEAP",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -6931,7 +7028,7 @@ test_write_wifi_leap_secret_flags(gconstpointer data)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Wifi LEAP Secret Flags",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_TYPE,
                  NM_SETTING_WIRELESS_SETTING_NAME,
                  NULL);
@@ -7037,7 +7134,7 @@ test_write_wifi_wpa_psk(gconstpointer test_data)
                  NM_SETTING_CONNECTION_ID,
                  args.name,
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -7142,7 +7239,7 @@ test_write_wifi_wpa_psk_adhoc(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Wifi WPA PSK",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -7252,7 +7349,7 @@ test_write_wifi_wpa_eap_tls(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Wifi WPA EAP-TLS",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -7295,8 +7392,8 @@ test_write_wifi_wpa_eap_tls(void)
     g_object_set(s_8021x, NM_SETTING_802_1X_IDENTITY, "Bill Smith", NULL);
     g_object_set(s_8021x,
                  NM_SETTING_802_1X_PHASE1_AUTH_FLAGS,
-                 (guint)(NM_SETTING_802_1X_AUTH_FLAGS_TLS_1_0_DISABLE
-                         | NM_SETTING_802_1X_AUTH_FLAGS_TLS_1_1_DISABLE),
+                 (guint) (NM_SETTING_802_1X_AUTH_FLAGS_TLS_1_0_DISABLE
+                          | NM_SETTING_802_1X_AUTH_FLAGS_TLS_1_1_DISABLE),
                  NULL);
 
     nm_setting_802_1x_add_eap_method(s_8021x, "tls");
@@ -7379,7 +7476,7 @@ test_write_wifi_wpa_eap_ttls_tls(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Wifi WPA EAP-TTLS (TLS)",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -7515,7 +7612,7 @@ test_write_wifi_wpa_eap_ttls_mschapv2(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Wifi WPA EAP-TTLS (MSCHAPv2)",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -7630,7 +7727,7 @@ test_write_wifi_wpa_then_open(void)
                  NM_SETTING_CONNECTION_ID,
                  "random wifi connection",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -7747,7 +7844,7 @@ test_write_wifi_wpa_then_wep_with_perms(void)
                  NM_SETTING_CONNECTION_ID,
                  "random wifi connection 2",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_PERMISSIONS,
@@ -7872,7 +7969,7 @@ test_write_wifi_dynamic_wep_leap(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Wifi Dynamic WEP LEAP",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_TYPE,
                  NM_SETTING_WIRELESS_SETTING_NAME,
                  NULL);
@@ -7969,7 +8066,7 @@ test_write_wired_qeth_dhcp(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Wired qeth Static",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -8043,7 +8140,7 @@ test_write_wired_ctc_dhcp(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Wired ctc Static",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_TYPE,
                  NM_SETTING_WIRED_SETTING_NAME,
                  NULL);
@@ -8118,7 +8215,7 @@ test_write_permissions(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Permissions",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -8187,7 +8284,7 @@ test_write_wifi_wep_agent_keys(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Wifi WEP Agent Owned",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_TYPE,
                  NM_SETTING_WIRELESS_SETTING_NAME,
                  NULL);
@@ -8273,7 +8370,7 @@ test_write_wired_pppoe(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Wired PPPoE",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -8334,7 +8431,7 @@ test_write_vpn(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write VPN",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -8392,7 +8489,7 @@ test_write_mobile_broadband(gconstpointer data)
                  NM_SETTING_CONNECTION_ID,
                  gsm ? "Test Write GSM" : "Test Write CDMA",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -8510,7 +8607,7 @@ test_write_bridge_main(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Bridge Main",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_INTERFACE_NAME,
@@ -8639,7 +8736,7 @@ test_write_bridge_component(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Bridge Component",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -8787,6 +8884,38 @@ test_read_vlan_only_vlan_id(void)
 }
 
 static void
+test_read_vlan_vlanid_use(void)
+{
+    nmtst_auto_unlinkfile char *testfile     = NULL;
+    gs_unref_object NMConnection *connection = NULL;
+    gs_unref_object NMConnection *reread     = NULL;
+    NMSettingVlan *               s_vlan;
+
+    connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-vlan-vlanid-use",
+                                       NULL,
+                                       TYPE_ETHERNET,
+                                       NULL);
+
+    g_assert_cmpstr(nm_connection_get_interface_name(connection), ==, "eth0.9");
+
+    s_vlan = nm_connection_get_setting_vlan(connection);
+    g_assert(s_vlan);
+
+    g_assert_cmpstr(nm_setting_vlan_get_parent(s_vlan), ==, "eth0");
+    g_assert_cmpint(nm_setting_vlan_get_id(s_vlan), ==, 10);
+    g_assert_cmpint(nm_setting_vlan_get_flags(s_vlan), ==, NM_VLAN_FLAG_REORDER_HEADERS);
+
+    _writer_new_connec_exp(connection,
+                           TEST_SCRATCH_DIR,
+                           TEST_IFCFG_DIR "/ifcfg-test-vlan-vlanid-use.cexpected",
+                           &testfile);
+
+    reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL);
+
+    nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
+}
+
+static void
 test_read_vlan_only_device(void)
 {
     NMConnection * connection;
@@ -8991,7 +9120,7 @@ test_write_vlan_reorder_hdr(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write VLAN reorder_hdr",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  FALSE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -9046,7 +9175,7 @@ test_write_ethernet_missing_ipv6(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Ethernet Without IPv6 Setting",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -9170,7 +9299,7 @@ test_write_bond_main(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Bond Main",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_INTERFACE_NAME,
@@ -9270,7 +9399,7 @@ test_write_bond_slave(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Bond Slave",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -9357,7 +9486,7 @@ test_write_infiniband(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write InfiniBand",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -9446,7 +9575,7 @@ test_write_bond_slave_ib(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Bond Slave InfiniBand",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_TYPE,
@@ -9604,7 +9733,7 @@ test_write_dcb_basic(void)
                  NM_SETTING_CONNECTION_ID,
                  "dcb-test",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_TYPE,
                  NM_SETTING_WIRED_SETTING_NAME,
                  NM_SETTING_CONNECTION_INTERFACE_NAME,
@@ -9850,7 +9979,7 @@ test_write_fcoe_mode(gconstpointer user_data)
                  NM_SETTING_CONNECTION_ID,
                  "fcoe-test",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_TYPE,
                  NM_SETTING_WIRED_SETTING_NAME,
                  NM_SETTING_CONNECTION_INTERFACE_NAME,
@@ -9968,7 +10097,7 @@ test_write_team_master(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Team Master",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_INTERFACE_NAME,
                  "team0",
                  NM_SETTING_CONNECTION_TYPE,
@@ -10060,7 +10189,7 @@ test_write_team_port(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Team Port",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_TYPE,
                  NM_SETTING_WIRED_SETTING_NAME,
                  NM_SETTING_CONNECTION_MASTER,
@@ -10119,7 +10248,7 @@ test_write_team_infiniband_port(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Team Infiniband Port",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_TYPE,
                  NM_SETTING_INFINIBAND_SETTING_NAME,
                  NM_SETTING_CONNECTION_MASTER,
@@ -10309,7 +10438,7 @@ test_write_proxy_basic(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write Proxy Basic",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_TYPE,
                  NM_SETTING_WIRED_SETTING_NAME,
                  NULL);
@@ -10358,7 +10487,7 @@ _svUnescape(const char *str, char **to_free)
         str = (str_free = g_strdup(str));
     }
 
-    s = svUnescape(str, to_free);
+    s = svUnescape_full(str, to_free, FALSE);
     if (*to_free) {
         g_assert(s == *to_free);
         g_assert(s[0]);
@@ -10366,6 +10495,37 @@ _svUnescape(const char *str, char **to_free)
         g_assert(s == NULL || (!s[0] && (s < str || s > strchr(str, '\0')))
                  || (s[0] && s >= str && s <= strchr(str, '\0')));
     }
+
+    {
+        const char *  s2;
+        gs_free char *to_free2 = NULL;
+
+        gboolean is_utf8 = s && g_utf8_validate(s, -1, NULL);
+
+        s2 = svUnescape_full(str, &to_free2, TRUE);
+        if (NM_IN_STRSET(str, "$'\\U0x'", "$'\\x0'", "$'\\008'", "$'\\08'")) {
+            g_assert_cmpstr(s2, ==, NULL);
+            g_assert(!to_free2);
+            g_assert_cmpstr(s, ==, "");
+            g_assert(!*to_free);
+        } else if (NM_IN_STRSET(str, "$'x\\U0'")) {
+            g_assert_cmpstr(s2, ==, NULL);
+            g_assert(!to_free2);
+            g_assert_cmpstr(s, ==, "x");
+            g_assert(*to_free == s);
+        } else if (!is_utf8) {
+            g_assert(!s2);
+            g_assert(!to_free2);
+        } else if (!to_free2) {
+            g_assert_cmpstr(s, ==, s2);
+            g_assert(s == s2);
+        } else {
+            g_assert_cmpstr(s, ==, s2);
+            g_assert(s != s2);
+            g_assert(s2 == to_free2);
+        }
+    }
+
     return s;
 }
 
@@ -10547,6 +10707,9 @@ test_svUnescape(void)
         V1("\"\\'\"''", "\\'"),
         V0("\"b\\~b\" ", "b\\~b"),
         V1("\"b\\~b\"x", "b\\~bx"),
+
+        V0("$'x\\U0'", "x"),
+        V0("$'\\U0x'", ""),
     };
     const UnescapeTestData data_ansi[] = {
         /* strings inside $''. They cannot be compared directly, but must
@@ -10733,7 +10896,7 @@ test_write_unknown(gconstpointer test_data)
         _svGetValue_check(sv, "METRIC", NULL);
         _svGetValue_check(sv, "METRIC1", "");
         _svGetValue_check(sv, "METRIC2", "");
-        _svGetValue_check(sv, "METRIC3", "x");
+        _svGetValue_check(sv, "METRIC3", "");
 
         _svGetValue_check(sv, "IPADDR", "set-by-test1");
         _svGetValue_check(sv, "IPADDR2", "set-by-test2");
@@ -10999,7 +11162,7 @@ test_sriov_write(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write SR-IOV config",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_INTERFACE_NAME,
@@ -11132,7 +11295,7 @@ test_tc_write_empty(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write TC config",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_INTERFACE_NAME,
@@ -11213,7 +11376,7 @@ test_tc_write(void)
                  NM_SETTING_CONNECTION_ID,
                  "Test Write TC config",
                  NM_SETTING_CONNECTION_UUID,
-                 nm_utils_uuid_generate_a(),
+                 nm_uuid_generate_random_str_a(),
                  NM_SETTING_CONNECTION_AUTOCONNECT,
                  TRUE,
                  NM_SETTING_CONNECTION_INTERFACE_NAME,
@@ -11405,6 +11568,7 @@ test_ethtool_names(void)
     } s_idxs[] = {
         {_NM_ETHTOOL_ID_FEATURE_FIRST, _NM_ETHTOOL_ID_FEATURE_LAST},
         {_NM_ETHTOOL_ID_COALESCE_FIRST, _NM_ETHTOOL_ID_COALESCE_LAST},
+        {_NM_ETHTOOL_ID_PAUSE_FIRST, _NM_ETHTOOL_ID_PAUSE_LAST},
         {_NM_ETHTOOL_ID_RING_FIRST, _NM_ETHTOOL_ID_RING_LAST},
     };
     const NMEthtoolData *data;
@@ -11599,6 +11763,8 @@ main(int argc, char **argv)
     g_test_add_func(TPATH "802-1x/password_raw", test_read_write_802_1x_password_raw);
     g_test_add_func(TPATH "802-1x/tls-p12-no-client-cert", test_read_802_1x_tls_p12_no_client_cert);
 
+    g_test_add_func(TPATH "wired/roundtrip/ethtool", test_roundtrip_ethtool);
+
     g_test_add_data_func(TPATH "wired/read/aliases/good/0",
                          GINT_TO_POINTER(0),
                          test_read_wired_aliases_good);
@@ -11705,6 +11871,7 @@ main(int argc, char **argv)
     g_test_add_func(TPATH "vlan/read/physdev", test_read_vlan_physdev);
     g_test_add_func(TPATH "vlan/read/reorder-hdr-1", test_read_vlan_reorder_hdr_1);
     g_test_add_func(TPATH "vlan/read/reorder-hdr-2", test_read_vlan_reorder_hdr_2);
+    g_test_add_func(TPATH "vlan/read/vlanid-use", test_read_vlan_vlanid_use);
     g_test_add_func(TPATH "wired/read/read-wake-on-lan", test_read_wired_wake_on_lan);
     g_test_add_func(TPATH "wired/read/read-auto-negotiate-off", test_read_wired_auto_negotiate_off);
     g_test_add_func(TPATH "wired/read/read-auto-negotiate-on", test_read_wired_auto_negotiate_on);
diff --git a/src/core/settings/plugins/ifupdown/meson.build b/src/core/settings/plugins/ifupdown/meson.build
index dd252783..1bff8155 100644
--- a/src/core/settings/plugins/ifupdown/meson.build
+++ b/src/core/settings/plugins/ifupdown/meson.build
@@ -7,14 +7,12 @@ libnms_ifupdown_core = static_library(
     'nms-ifupdown-parser.c',
   ),
   dependencies: core_default_dep,
-  c_args: daemon_c_flags,
 )
 
 libnm_settings_plugin_ifupdown = shared_module(
   'nm-settings-plugin-ifupdown',
   sources: 'nms-ifupdown-plugin.c',
   dependencies: core_plugin_dep,
-  c_args: daemon_c_flags,
   link_with: libnms_ifupdown_core,
   link_args: ldflags_linker_script_settings,
   link_depends: linker_script_settings,
diff --git a/src/core/settings/plugins/ifupdown/nms-ifupdown-parser.c b/src/core/settings/plugins/ifupdown/nms-ifupdown-parser.c
index a4974a96..db6b1aef 100644
--- a/src/core/settings/plugins/ifupdown/nms-ifupdown-parser.c
+++ b/src/core/settings/plugins/ifupdown/nms-ifupdown-parser.c
@@ -12,7 +12,8 @@
 #include <stdlib.h>
 #include <ctype.h>
 
-#include "nm-core-internal.h"
+#include "libnm-glib-aux/nm-uuid.h"
+#include "libnm-core-intern/nm-core-internal.h"
 #include "settings/nm-settings-plugin.h"
 
 #include "nms-ifupdown-plugin.h"
@@ -32,14 +33,6 @@
 
 /*****************************************************************************/
 
-#define _str_has_prefix(val, prefix, require_suffix)                   \
-    ({                                                                 \
-        const char *_val = (val);                                      \
-                                                                       \
-        (strncmp(_val, "" prefix "", NM_STRLEN(prefix)) == 0)          \
-            && (!(require_suffix) || _val[NM_STRLEN(prefix)] != '\0'); \
-    })
-
 static const char *
 _ifupdownplugin_guess_connection_type(if_block *block)
 {
@@ -51,8 +44,7 @@ _ifupdownplugin_guess_connection_type(if_block *block)
         if_data *ifb;
 
         c_list_for_each_entry (ifb, &block->data_lst_head, data_lst) {
-            if (_str_has_prefix(ifb->key, "wireless-", FALSE)
-                || _str_has_prefix(ifb->key, "wpa-", FALSE)) {
+            if (NM_STR_HAS_PREFIX(ifb->key, "wireless-") || NM_STR_HAS_PREFIX(ifb->key, "wpa-")) {
                 ret_type = NM_SETTING_WIRELESS_SETTING_NAME;
                 break;
             }
@@ -102,7 +94,7 @@ update_wireless_setting_from_if_block(NMConnection *connection, if_block *block)
     wireless_setting = NM_SETTING_WIRELESS(nm_setting_wireless_new());
 
     c_list_for_each_entry (curr, &block->data_lst_head, data_lst) {
-        if (_str_has_prefix(curr->key, "wireless-", TRUE)) {
+        if (NM_STR_HAS_PREFIX_WITH_MORE(curr->key, "wireless-")) {
             const char *newkey = map_by_mapping(mapping, curr->key + NM_STRLEN("wireless-"));
 
             _LOGI("wireless setting key: %s='%s'", newkey, curr->data);
@@ -137,7 +129,7 @@ update_wireless_setting_from_if_block(NMConnection *connection, if_block *block)
             } else {
                 g_object_set(wireless_setting, newkey, curr->data, NULL);
             }
-        } else if (_str_has_prefix(curr->key, "wpa-", TRUE)) {
+        } else if (NM_STR_HAS_PREFIX_WITH_MORE(curr->key, "wpa-")) {
             const char *newkey = map_by_mapping(mapping, curr->key + NM_STRLEN("wpa-"));
 
             if (nm_streq0(newkey, "ssid")) {
@@ -304,7 +296,7 @@ update_wireless_security_setting_from_if_block(NMConnection *connection, if_bloc
     wireless_security_setting = NM_SETTING_WIRELESS_SECURITY(nm_setting_wireless_security_new());
 
     c_list_for_each_entry (curr, &block->data_lst_head, data_lst) {
-        if (_str_has_prefix(curr->key, "wireless-", TRUE)) {
+        if (NM_STR_HAS_PREFIX_WITH_MORE(curr->key, "wireless-")) {
             const char *          key                  = curr->key + NM_STRLEN("wireless-");
             char *                property_value       = NULL;
             gpointer              typed_property_value = NULL;
@@ -336,7 +328,7 @@ wireless_next:
             if (typed_property_value && free_func)
                 (*free_func)(typed_property_value);
 
-        } else if (_str_has_prefix(curr->key, "wpa-", TRUE)) {
+        } else if (NM_STR_HAS_PREFIX_WITH_MORE(curr->key, "wpa-")) {
             const char *          key                  = curr->key + NM_STRLEN("wpa-");
             char *                property_value       = NULL;
             gpointer              typed_property_value = NULL;
@@ -644,7 +636,7 @@ ifupdown_new_connection_from_if_block(if_block *block, gboolean autoconnect, GEr
     type  = _ifupdownplugin_guess_connection_type(block);
     idstr = g_strconcat("Ifupdown (", block->name, ")", NULL);
 
-    uuid = nm_utils_uuid_generate_from_string(idstr, -1, NM_UTILS_UUID_TYPE_LEGACY, NULL);
+    uuid = nm_uuid_generate_from_string_str(idstr, -1, NM_UUID_TYPE_LEGACY, NULL);
     g_object_set(s_con,
                  NM_SETTING_CONNECTION_TYPE,
                  type,
@@ -655,7 +647,7 @@ ifupdown_new_connection_from_if_block(if_block *block, gboolean autoconnect, GEr
                  NM_SETTING_CONNECTION_UUID,
                  uuid,
                  NM_SETTING_CONNECTION_AUTOCONNECT,
-                 (gboolean)(!!autoconnect),
+                 (gboolean) (!!autoconnect),
                  NULL);
 
     _LOGD("update_connection_setting_from_if_block: name:%s, type:%s, id:%s, uuid: %s",
diff --git a/src/core/settings/plugins/ifupdown/nms-ifupdown-plugin.c b/src/core/settings/plugins/ifupdown/nms-ifupdown-plugin.c
index 34523f8d..80a5638a 100644
--- a/src/core/settings/plugins/ifupdown/nms-ifupdown-plugin.c
+++ b/src/core/settings/plugins/ifupdown/nms-ifupdown-plugin.c
@@ -9,7 +9,7 @@
 
 #include "nms-ifupdown-plugin.h"
 
-#include "nm-core-internal.h"
+#include "libnm-core-intern/nm-core-internal.h"
 #include "nm-core-utils.h"
 #include "nm-config.h"
 #include "settings/nm-settings-plugin.h"
diff --git a/src/core/settings/plugins/ifupdown/tests/test-ifupdown.c b/src/core/settings/plugins/ifupdown/tests/test-ifupdown.c
index 6e3eb0e7..0e8db733 100644
--- a/src/core/settings/plugins/ifupdown/tests/test-ifupdown.c
+++ b/src/core/settings/plugins/ifupdown/tests/test-ifupdown.c
@@ -5,7 +5,7 @@
 
 #include "src/core/nm-default-daemon.h"
 
-#include "nm-core-internal.h"
+#include "libnm-core-intern/nm-core-internal.h"
 
 #include "settings/plugins/ifupdown/nms-ifupdown-interface-parser.h"
 #include "settings/plugins/ifupdown/nms-ifupdown-parser.h"
diff --git a/src/core/settings/plugins/keyfile/nms-keyfile-plugin.c b/src/core/settings/plugins/keyfile/nms-keyfile-plugin.c
index 789bfc1a..e8ae1814 100644
--- a/src/core/settings/plugins/keyfile/nms-keyfile-plugin.c
+++ b/src/core/settings/plugins/keyfile/nms-keyfile-plugin.c
@@ -13,19 +13,20 @@
 #include <sys/types.h>
 #include <sys/time.h>
 
-#include "nm-std-aux/c-list-util.h"
-#include "nm-glib-aux/nm-c-list.h"
-#include "nm-glib-aux/nm-io-utils.h"
+#include "libnm-std-aux/c-list-util.h"
+#include "libnm-glib-aux/nm-c-list.h"
+#include "libnm-glib-aux/nm-uuid.h"
+#include "libnm-glib-aux/nm-io-utils.h"
 
 #include "nm-connection.h"
 #include "nm-setting.h"
 #include "nm-setting-connection.h"
 #include "nm-utils.h"
 #include "nm-config.h"
-#include "nm-core-internal.h"
-#include "nm-keyfile-internal.h"
+#include "libnm-core-intern/nm-core-internal.h"
+#include "libnm-core-intern/nm-keyfile-internal.h"
 
-#include "systemd/nm-sd-utils-shared.h"
+#include "libnm-systemd-shared/nm-sd-utils-shared.h"
 
 #include "settings/nm-settings-plugin.h"
 #include "settings/nm-settings-storage.h"
@@ -233,7 +234,7 @@ _read_from_file(const char * full_filename,
 
     nm_assert(!connection
               || (_nm_connection_verify(connection, NULL) == NM_SETTING_VERIFY_SUCCESS));
-    nm_assert(!connection || nm_utils_is_uuid(nm_connection_get_uuid(connection)));
+    nm_assert(!connection || nm_uuid_is_normalized(nm_connection_get_uuid(connection)));
 
     return connection;
 }
@@ -260,7 +261,7 @@ _nm_assert_storage(gpointer plugin /* NMSKeyfilePlugin  */,
 
     uuid = nms_keyfile_storage_get_uuid(storage);
 
-    nm_assert(nm_utils_is_uuid(uuid));
+    nm_assert(nm_uuid_is_normalized(uuid));
 
     nm_assert(((NMSKeyfileStorage *) storage)->is_meta_data
               || !(((NMSKeyfileStorage *) storage)->u.conn_data.connection)
@@ -1106,7 +1107,7 @@ nms_keyfile_plugin_set_nmmeta_tombstone(NMSKeyfilePlugin *  self,
     const char *                       dirname;
 
     nm_assert(NMS_IS_KEYFILE_PLUGIN(self));
-    nm_assert(nm_utils_is_uuid(uuid));
+    nm_assert(nm_uuid_is_normalized(uuid));
     nm_assert(!out_storage || !*out_storage);
     nm_assert(!shadowed_storage || (set && in_memory));
 
@@ -1246,9 +1247,9 @@ nms_keyfile_plugin_init(NMSKeyfilePlugin *plugin)
     /* dirname_libs are a set of read-only directories with lower priority than /etc or /run.
      * There is nothing complicated about having multiple of such directories, so dirname_libs
      * is a list (which currently only has at most one directory). */
-    priv->dirname_libs[0] = nm_sd_utils_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_LIB), FALSE);
+    priv->dirname_libs[0] = nm_sd_utils_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_LIB));
     priv->dirname_libs[1] = NULL;
-    priv->dirname_run     = nm_sd_utils_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_RUN), FALSE);
+    priv->dirname_run     = nm_sd_utils_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_RUN));
     priv->dirname_etc     = nm_config_data_get_value(NM_CONFIG_GET_DATA_ORIG,
                                                  NM_CONFIG_KEYFILE_GROUP_KEYFILE,
                                                  NM_CONFIG_KEYFILE_KEY_KEYFILE_PATH,
@@ -1261,10 +1262,9 @@ nms_keyfile_plugin_init(NMSKeyfilePlugin *plugin)
     } else if (!priv->dirname_etc || priv->dirname_etc[0] != '/') {
         /* either invalid path or unspecified. Use the default. */
         g_free(priv->dirname_etc);
-        priv->dirname_etc =
-            nm_sd_utils_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_ETC_DEFAULT), FALSE);
+        priv->dirname_etc = nm_sd_utils_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_ETC_DEFAULT));
     } else
-        nm_sd_utils_path_simplify(priv->dirname_etc, FALSE);
+        nm_sd_utils_path_simplify(priv->dirname_etc);
 
     /* no duplicates */
     if (NM_IN_STRSET(priv->dirname_libs[0], priv->dirname_etc, priv->dirname_run))
diff --git a/src/core/settings/plugins/keyfile/nms-keyfile-reader.c b/src/core/settings/plugins/keyfile/nms-keyfile-reader.c
index 70b047f3..8b9d982f 100644
--- a/src/core/settings/plugins/keyfile/nms-keyfile-reader.c
+++ b/src/core/settings/plugins/keyfile/nms-keyfile-reader.c
@@ -9,7 +9,7 @@
 
 #include <sys/stat.h>
 
-#include "nm-keyfile-internal.h"
+#include "libnm-core-intern/nm-keyfile-internal.h"
 
 #include "NetworkManagerUtils.h"
 #include "nms-keyfile-utils.h"
diff --git a/src/core/settings/plugins/keyfile/nms-keyfile-storage.c b/src/core/settings/plugins/keyfile/nms-keyfile-storage.c
index 89be817a..8c526c81 100644
--- a/src/core/settings/plugins/keyfile/nms-keyfile-storage.c
+++ b/src/core/settings/plugins/keyfile/nms-keyfile-storage.c
@@ -7,8 +7,9 @@
 
 #include "nms-keyfile-storage.h"
 
+#include "libnm-glib-aux/nm-uuid.h"
 #include "nm-utils.h"
-#include "nm-core-internal.h"
+#include "libnm-core-intern/nm-core-internal.h"
 #include "nms-keyfile-plugin.h"
 
 /*****************************************************************************/
@@ -108,7 +109,7 @@ _storage_new(NMSKeyfilePlugin *    plugin,
     NMSKeyfileStorage *self;
 
     nm_assert(NMS_IS_KEYFILE_PLUGIN(plugin));
-    nm_assert(nm_utils_is_uuid(uuid));
+    nm_assert(nm_uuid_is_normalized(uuid));
     nm_assert(filename && filename[0] == '/');
 
     self = g_object_new(NMS_TYPE_KEYFILE_STORAGE,
@@ -135,7 +136,7 @@ nms_keyfile_storage_new_tombstone(NMSKeyfilePlugin *    plugin,
 {
     NMSKeyfileStorage *self;
 
-    nm_assert(nm_utils_is_uuid(uuid));
+    nm_assert(nm_uuid_is_normalized(uuid));
     nm_assert(filename && filename[0] == '/');
     nm_assert(nms_keyfile_nmmeta_check_filename(filename, NULL));
     nm_assert(NM_IN_SET(storage_type, NMS_KEYFILE_STORAGE_TYPE_ETC, NMS_KEYFILE_STORAGE_TYPE_RUN));
diff --git a/src/core/settings/plugins/keyfile/nms-keyfile-utils.c b/src/core/settings/plugins/keyfile/nms-keyfile-utils.c
index ca1233f5..e2c68bbe 100644
--- a/src/core/settings/plugins/keyfile/nms-keyfile-utils.c
+++ b/src/core/settings/plugins/keyfile/nms-keyfile-utils.c
@@ -10,8 +10,9 @@
 #include <stdlib.h>
 #include <sys/stat.h>
 
-#include "nm-glib-aux/nm-io-utils.h"
-#include "nm-keyfile-internal.h"
+#include "libnm-glib-aux/nm-uuid.h"
+#include "libnm-glib-aux/nm-io-utils.h"
+#include "libnm-core-intern/nm-keyfile-internal.h"
 #include "nm-utils.h"
 #include "nm-setting-wired.h"
 #include "nm-setting-wireless.h"
@@ -30,9 +31,9 @@
 const char *
 nms_keyfile_nmmeta_check_filename(const char *filename, guint *out_uuid_len)
 {
-    const char *uuid;
     const char *s;
     gsize       len;
+    char        uuid[37];
 
     s = strrchr(filename, '/');
     if (s)
@@ -50,17 +51,18 @@ nms_keyfile_nmmeta_check_filename(const char *filename, guint *out_uuid_len)
 
     len -= NM_STRLEN(NM_KEYFILE_PATH_SUFFIX_NMMETA);
 
-    if (!NM_IN_SET(len, 36, 40)) {
+    if (len != 36) {
         /* the remaining part of the filename has not the right length to
-         * contain a UUID (according to nm_utils_is_uuid()). */
+         * contain a UUID (according to nm_uuid_is_normalized()). */
         return NULL;
     }
 
-    uuid = nm_strndup_a(100, filename, len, NULL);
-    if (!nm_utils_is_uuid(uuid))
+    memcpy(uuid, filename, 36);
+    uuid[36] = '\0';
+    if (!nm_uuid_is_normalized(uuid))
         return NULL;
 
-    NM_SET_OUT(out_uuid_len, len);
+    NM_SET_OUT(out_uuid_len, 36);
     return filename;
 }
 
@@ -71,7 +73,7 @@ nms_keyfile_nmmeta_filename(const char *dirname, const char *uuid, gboolean temp
     char *s;
 
     nm_assert(dirname && dirname[0] == '/');
-    nm_assert(nm_utils_is_uuid(uuid) && !strchr(uuid, '/'));
+    nm_assert(nm_uuid_is_normalized(uuid) && !strchr(uuid, '/'));
 
     if (g_snprintf(filename,
                    sizeof(filename),
@@ -80,7 +82,7 @@ nms_keyfile_nmmeta_filename(const char *dirname, const char *uuid, gboolean temp
                    NM_KEYFILE_PATH_SUFFIX_NMMETA,
                    temporary ? "~" : "")
         >= sizeof(filename)) {
-        /* valid uuids are limited in length (nm_utils_is_uuid). The buffer should always
+        /* valid uuids are limited in length (nm_uuid_is_normalized). The buffer should always
          * be large enough. */
         nm_assert_not_reached();
     }
@@ -215,7 +217,7 @@ nms_keyfile_nmmeta_write(const char *dirname,
     int           errsv;
 
     nm_assert(dirname && dirname[0] == '/');
-    nm_assert(nm_utils_is_uuid(uuid) && !strchr(uuid, '/'));
+    nm_assert(nm_uuid_is_normalized(uuid) && !strchr(uuid, '/'));
     nm_assert(!loaded_path || loaded_path[0] == '/');
     nm_assert(!shadowed_storage || loaded_path);
 
@@ -273,7 +275,13 @@ nms_keyfile_nmmeta_write(const char *dirname,
 
         contents = g_key_file_to_data(kf, &length, NULL);
 
-        if (!nm_utils_file_set_contents(full_filename, contents, length, 0600, &errsv, NULL)) {
+        if (!nm_utils_file_set_contents(full_filename,
+                                        contents,
+                                        length,
+                                        0600,
+                                        NULL,
+                                        &errsv,
+                                        NULL)) {
             NM_SET_OUT(out_full_filename, g_steal_pointer(&full_filename_tmp));
             return -NM_ERRNO_NATIVE(errsv);
         }
diff --git a/src/core/settings/plugins/keyfile/nms-keyfile-writer.c b/src/core/settings/plugins/keyfile/nms-keyfile-writer.c
index 0e2c94b5..70afdc23 100644
--- a/src/core/settings/plugins/keyfile/nms-keyfile-writer.c
+++ b/src/core/settings/plugins/keyfile/nms-keyfile-writer.c
@@ -12,12 +12,12 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
-#include "nm-keyfile-internal.h"
+#include "libnm-core-intern/nm-keyfile-internal.h"
 
 #include "nms-keyfile-utils.h"
 #include "nms-keyfile-reader.h"
 
-#include "nm-glib-aux/nm-io-utils.h"
+#include "libnm-glib-aux/nm-io-utils.h"
 
 /*****************************************************************************/
 
@@ -125,13 +125,14 @@ cert_writer(NMConnection *                    connection,
 
         /* FIXME(keyfile-parse-in-memory): writer must not access/write to the file system before
          * being sure that the entire profile can be written and all circumstances are good to
-         * proceed. That means, while writing we must only collect the blogs in-memory, and write
+         * proceed. That means, while writing we must only collect the blobs in-memory, and write
          * them all in the end together (or not at all). */
         success = nm_utils_file_set_contents(new_path,
                                              (const char *) blob_data,
                                              blob_len,
                                              0600,
                                              NULL,
+                                             NULL,
                                              &local);
         if (success) {
             /* Write the path value to the keyfile.
@@ -378,7 +379,7 @@ _internal_write_connection(NMConnection *                  connection,
         }
     }
 
-    nm_utils_file_set_contents(path, kf_content_buf, kf_content_len, 0600, NULL, &local_err);
+    nm_utils_file_set_contents(path, kf_content_buf, kf_content_len, 0600, NULL, NULL, &local_err);
     if (local_err) {
         g_set_error(error,
                     NM_SETTINGS_ERROR,
diff --git a/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c b/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c
index 348b0ed6..a13c2586 100644
--- a/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c
+++ b/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c
@@ -15,7 +15,8 @@
 #include <linux/if_ether.h>
 #include <linux/if_infiniband.h>
 
-#include "nm-core-internal.h"
+#include "libnm-glib-aux/nm-uuid.h"
+#include "libnm-core-intern/nm-core-internal.h"
 
 #include "settings/plugins/keyfile/nms-keyfile-reader.h"
 #include "settings/plugins/keyfile/nms-keyfile-writer.h"
@@ -2289,7 +2290,7 @@ test_read_missing_id_uuid(void)
     gs_free char *                expected_uuid = NULL;
     const char *                  FILENAME      = TEST_KEYFILES_DIR "/Test_Missing_ID_UUID";
 
-    expected_uuid = _nm_utils_uuid_generate_from_strings("keyfile", FILENAME, NULL);
+    expected_uuid = nm_uuid_generate_from_strings("keyfile", FILENAME, NULL);
 
     connection = keyfile_read_connection_from_file(FILENAME);