diff --git a/.gitignore b/.gitignore
index b9b42fc78a..494ff707ba 100644
--- a/.gitignore
+++ b/.gitignore
@@ -252,6 +252,7 @@ test-*.trs
/src/dhcp/tests/test-dhcp-options
/src/dhcp/tests/test-dhcp-utils
/src/dnsmasq/tests/test-dnsmasq-utils
+/src/initrd/nm-initrd-generator
/src/initrd/tests/test-cmdline-reader
/src/initrd/tests/test-ibft-reader
/src/nm-iface-helper
diff --git a/Makefile.am b/Makefile.am
index 830d83d00a..3f81c38925 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1936,6 +1936,24 @@ src_initrd_libnmi_core_la_SOURCES = \
src/initrd/nmi-ibft-reader.c \
$(NULL)
+libexec_PROGRAMS += src/initrd/nm-initrd-generator
+
+src_initrd_nm_initrd_generator_CPPFLAGS = \
+ $(src_cppflags)
+
+src_initrd_nm_initrd_generator_SOURCES = \
+ src/initrd/nm-initrd-generator.c
+
+src_initrd_nm_initrd_generator_LDADD = \
+ libnm-core/libnm-core.la \
+ src/initrd/libnmi-core.la \
+ src/libNetworkManagerBase.la \
+ $(GLIB_LIBS)
+
+src_initrd_nm_initrd_generator_LDFLAGS = \
+ -Wl,--version-script="$(srcdir)/linker-script-binary.ver" \
+ $(SANITIZER_EXEC_LDFLAGS)
+
check_programs += src/initrd/tests/test-ibft-reader
src_initrd_tests_test_ibft_reader_CPPFLAGS = \
@@ -2166,6 +2184,7 @@ src_initrd_tests_test_cmdline_reader_LDADD = \
$(GLIB_LIBS)
$(src_initrd_libnmi_core_la_OBJECTS): $(libnm_core_lib_h_pub_mkenums)
+$(src_initrd_nm_initrd_generator_OBJECTS): $(libnm_core_lib_h_pub_mkenums)
$(src_initrd_tests_test_cmdline_reader_OBJECTS): $(libnm_core_lib_h_pub_mkenums)
$(src_initrd_tests_test_ibft_reader_OBJECTS): $(libnm_core_lib_h_pub_mkenums)
@@ -4861,6 +4880,7 @@ man_pages += \
man/NetworkManager.8 \
man/NetworkManager.conf.5 \
man/nm-online.1 \
+ man/nm-initrd-generator.8 \
man/nmcli-examples.7 \
man/nmcli.1 \
man/nmtui.1
diff --git a/contrib/fedora/rpm/NetworkManager.spec b/contrib/fedora/rpm/NetworkManager.spec
index 753ff08fc2..644cd705fa 100644
--- a/contrib/fedora/rpm/NetworkManager.spec
+++ b/contrib/fedora/rpm/NetworkManager.spec
@@ -687,6 +687,7 @@ fi
%{_libexecdir}/nm-dhcp-helper
%{_libexecdir}/nm-dispatcher
%{_libexecdir}/nm-iface-helper
+%{_libexecdir}/nm-initrd-generator
%dir %{_libdir}/%{name}
%dir %{nmplugindir}
%{nmplugindir}/libnm-settings-plugin*.so
diff --git a/docs/api/Makefile.am b/docs/api/Makefile.am
index 859aa20bc2..1f388b99ec 100644
--- a/docs/api/Makefile.am
+++ b/docs/api/Makefile.am
@@ -83,6 +83,7 @@ content_files = \
$(top_builddir)/man/nmcli.xml \
$(top_builddir)/man/nmtui.xml \
$(top_builddir)/man/nm-online.xml \
+ $(top_builddir)/man/nm-initrd-generator.xml \
$(top_builddir)/man/NetworkManager.xml \
$(top_builddir)/man/NetworkManager.conf.xml \
$(top_builddir)/man/nmcli-examples.xml \
diff --git a/docs/api/network-manager-docs.xml b/docs/api/network-manager-docs.xml
index 047c3086e3..457ec0ac29 100644
--- a/docs/api/network-manager-docs.xml
+++ b/docs/api/network-manager-docs.xml
@@ -77,6 +77,7 @@
+
diff --git a/man/nm-initrd-generator.xml b/man/nm-initrd-generator.xml
new file mode 100644
index 0000000000..df2cf12a4b
--- /dev/null
+++ b/man/nm-initrd-generator.xml
@@ -0,0 +1,140 @@
+
+
+
+%entities;
+]>
+
+
+
+
+
+
+ nm-initrd-generator
+ NetworkManager developers
+
+
+
+ nm-initrd-generator
+ 8
+ NetworkManager
+ System Administration
+ &NM_VERSION;
+
+
+
+ nm-initrd-generator
+ early boot NetworkManager configuration generator
+
+
+
+
+ nm-initrd-generator
+ OPTIONS
+ --
+ CMDLINE
+
+
+
+ Description
+ nm-initrd-generator scans the command line for options
+ relevant to network configuration and creates configuration files for an early
+ instance of NetworkManager run from the initial ramdisk during early boot.
+
+
+ Options
+
+
+
+
+
+
+
+ path
+
+
+
+ Output connection directory.
+
+
+
+
+
+
+
+
+
+ path
+
+
+
+ The sysfs mount point.
+
+
+
+
+
+
+
+
+
+
+
+
+ Dump connections to standard output. Useful for debugging.
+
+
+
+
+ CMDLINE
+
+
+ The options that appear on the kernel command line. The following options are recognized:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Please consult the dracut.cmdline7
+ manual for the documentation of the precise format of the values supported.
+
+
+
+
+
+ Exit Status
+ nm-initrd-generator exits with status 0. It ignores unrecognized
+ options and prints an error message if it encounters a malformed option.
+
+
+ See Also
+ dracut.cmdline7,
+ NetworkManager8.
+
+
diff --git a/src/initrd/nm-initrd-generator.c b/src/initrd/nm-initrd-generator.c
new file mode 100644
index 0000000000..5947aef075
--- /dev/null
+++ b/src/initrd/nm-initrd-generator.c
@@ -0,0 +1,138 @@
+/* NetworkManager initrd configuration generator
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2018 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+#include "nm-core-utils.h"
+#include "nm-core-internal.h"
+#include "nm-keyfile-internal.h"
+
+#include "nm-initrd-generator.h"
+
+/*****************************************************************************/
+
+#define _NMLOG(level, domain, ...) \
+ nm_log ((level), (domain), NULL, NULL, \
+ "initrd-generator: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__) \
+ _NM_UTILS_MACRO_REST (__VA_ARGS__))
+
+/*****************************************************************************/
+
+static void
+output_conn (gpointer key, gpointer value, gpointer user_data)
+{
+ const char *basename = key;
+ NMConnection *connection = value;
+ char *connections_dir = user_data;
+ GKeyFile *file;
+ gs_free char *data = NULL;
+ GError *error = NULL;
+ gsize len;
+
+ if (!nm_connection_normalize (connection, NULL, NULL, &error)) {
+ g_print ("%s\n", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ file = nm_keyfile_write (connection, NULL, NULL, &error);
+ if (file == NULL) {
+ g_print ("%s\n", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ data = g_key_file_to_data (file, &len, &error);
+ if (!data) {
+ g_print ("%s\n", error->message);
+ g_error_free (error);
+ } else if (connections_dir) {
+ char *filename = g_build_filename (connections_dir, basename, NULL);
+
+ if (!nm_utils_file_set_contents (filename, data, len, 0600, &error)) {
+ g_print ("%s\n", error->message);
+ g_error_free (error);
+ }
+ g_free (filename);
+ } else {
+ g_print ("\n*** Connection '%s' ***\n\n%s\n", basename, data);
+ }
+
+ g_key_file_free (file);
+}
+
+#define DEFAULT_CONNECTIONS_DIR NMRUNDIR "/system-connections"
+#define DEFAULT_SYSFS_DIR "/sys"
+
+int
+main (int argc, char *argv[])
+{
+ GHashTable *connections;
+ gs_free char *connections_dir = NULL;
+ gs_free char *sysfs_dir = NULL;
+ gboolean dump_to_stdout = FALSE;
+ gs_strfreev char **remaining = NULL;
+ GOptionEntry option_entries[] = {
+ { "connections-dir", 'c', 0, G_OPTION_ARG_FILENAME, &connections_dir, "Output connection directory", DEFAULT_CONNECTIONS_DIR },
+ { "sysfs-dir", 'd', 0, G_OPTION_ARG_FILENAME, &sysfs_dir, "The sysfs mount point", DEFAULT_SYSFS_DIR },
+ { "stdout", 's', 0, G_OPTION_ARG_NONE, &dump_to_stdout, "Dump connections to standard output", NULL },
+ { G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_STRING_ARRAY, &remaining, NULL, NULL },
+ { NULL }
+ };
+ GOptionContext *option_context;
+ GError *error = NULL;
+
+ option_context = g_option_context_new ("-- [ip=...] [rd.route=...] [bridge=...] [bond=...] [team=...] [vlan=...] "
+ "[bootdev=...] [nameserver=...] [rd.peerdns=...] [rd.bootif=...] [BOOTIF=...] ... ");
+
+ g_option_context_set_summary (option_context, "Generate early NetworkManager configuration.");
+ g_option_context_set_description (option_context,
+ "This tool scans the command line for options relevant to network\n"
+ "configuration and creates configuration files for an early instance\n"
+ "of NetworkManager run from the initial ramdisk during early boot.");
+ g_option_context_add_main_entries (option_context, option_entries, GETTEXT_PACKAGE);
+
+ if (!g_option_context_parse (option_context, &argc, &argv, &error)) {
+ _LOGW (LOGD_CORE, "%s\n", error->message);
+ return 1;
+ }
+
+ if (!remaining) {
+ /* No arguments, no networking. Don't bother. */
+ return 0;
+ }
+
+ if (!connections_dir)
+ connections_dir = g_strdup (DEFAULT_CONNECTIONS_DIR);
+ if (!sysfs_dir)
+ sysfs_dir = g_strdup (DEFAULT_SYSFS_DIR);
+ if (dump_to_stdout)
+ g_clear_pointer (&connections_dir, g_free);
+
+ if (connections_dir && g_mkdir_with_parents (connections_dir, 0755) != 0) {
+ _LOGW (LOGD_CORE, "%s: %s\n", connections_dir, strerror (errno));
+ return 1;
+ }
+
+ connections = nmi_cmdline_reader_parse (sysfs_dir, remaining);
+ g_hash_table_foreach (connections, output_conn, connections_dir);
+ g_hash_table_destroy (connections);
+
+ return 0;
+}