summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLubomir Rintel <lkundrak@v3.sk>2018-04-28 20:36:15 +0200
committerLubomir Rintel <lkundrak@v3.sk>2018-05-21 19:02:53 +0200
commit68af115fba597501a886a8ec4be83e8c624e91e6 (patch)
treef59eb2c83723ebf3fcbc89f4f005545649b5f009
parentdab54a0917f097f7926c68b8fb083ddb14fa79f9 (diff)
[WIP] initrd: add configuration generatorlr/initrd
TODO: * Deal with more than a single initqueue/settle when a device appears * More dracut.cmdline(5) options: bootdev=, BOOTIF=, rd.bootif=0, nameserver=, rd.peerdns=0 * Hard errors on failing cmdline parsing
-rw-r--r--Makefile.am62
-rw-r--r--contrib/fedora/rpm/NetworkManager.spec1
-rw-r--r--src/initrd/nm-initrd-generator.c145
-rw-r--r--src/initrd/nm-initrd-generator.h (renamed from src/initrd/nmi-ibft-reader.h)13
-rw-r--r--src/initrd/nmi-cmdline-reader.c576
-rw-r--r--src/initrd/nmi-ibft-reader.c4
-rw-r--r--src/initrd/tests/test-ibft.c2
7 files changed, 795 insertions, 8 deletions
diff --git a/Makefile.am b/Makefile.am
index b4bd5437e..46e98b9f4 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1775,6 +1775,68 @@ $(src_nm_iface_helper_OBJECTS): $(libnm_core_lib_h_pub_mkenums)
###############################################################################
+noinst_LTLIBRARIES += src/initrd/libnmi-ibft-core.la
+
+src_initrd_libnmi_ibft_core_la_CPPFLAGS = \
+ $(src_cppflags)
+
+src_initrd_libnmi_ibft_core_la_SOURCES = \
+ src/initrd/nm-initrd-generator.h \
+ src/initrd/nmi-cmdline-reader.c \
+ src/initrd/nmi-ibft-reader.c
+
+$(src_initrd_libnmi_ibft_core_la_OBJECTS): $(libnm_core_lib_h_pub_mkenums)
+
+libexec_PROGRAMS += src/initrd/nm-initrd-generator
+
+src_initrd_nm_initrd_generator_CPPFLAGS = \
+ -DTEST_IBFT_DIR=\"$(abs_srcdir)/src/initrd/tests\" \
+ $(src_cppflags)
+
+src_initrd_nm_initrd_generator_SOURCES = \
+ src/initrd/nm-initrd-generator.c
+
+src_initrd_nm_initrd_generator_LDADD = \
+ src/initrd/libnmi-ibft-core.la \
+ libnm-core/libnm-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
+
+src_initrd_tests_test_ibft_CPPFLAGS = \
+ -DNETWORKMANAGER_COMPILATION_TEST \
+ -DTEST_IBFT_DIR=\"$(abs_srcdir)/src/initrd/tests\" \
+ -DTEST_SCRATCH_DIR=\"$(abs_builddir)/src/initrd/tests\" \
+ $(src_cppflags)
+
+src_initrd_tests_test_ibft_LDFLAGS = \
+ $(CODE_COVERAGE_LDFLAGS) \
+ $(SANITIZER_EXEC_LDFLAGS)
+
+src_initrd_tests_test_ibft_LDADD = \
+ src/initrd/libnmi-ibft-core.la \
+ libnm-core/libnm-core.la \
+ src/libNetworkManagerTest.la \
+ $(GLIB_LIBS)
+
+EXTRA_DIST += \
+ src/initrd/tests/iscsiadm-test-dhcp \
+ src/initrd/tests/iscsiadm-test-static \
+ src/initrd/tests/iscsiadm-test-bad-ipaddr \
+ src/initrd/tests/iscsiadm-test-bad-gateway \
+ src/initrd/tests/iscsiadm-test-bad-dns1 \
+ src/initrd/tests/iscsiadm-test-bad-dns2 \
+ src/initrd/tests/iscsiadm-test-bad-entry \
+ src/initrd/tests/iscsiadm-test-bad-record \
+ src/initrd/tests/iscsiadm-test-vlan
+
+###############################################################################
+
EXTRA_DIST += \
src/org.freedesktop.NetworkManager.conf \
src/nm-test-utils-core.h \
diff --git a/contrib/fedora/rpm/NetworkManager.spec b/contrib/fedora/rpm/NetworkManager.spec
index 618e6178b..88e14e48d 100644
--- a/contrib/fedora/rpm/NetworkManager.spec
+++ b/contrib/fedora/rpm/NetworkManager.spec
@@ -611,6 +611,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/src/initrd/nm-initrd-generator.c b/src/initrd/nm-initrd-generator.c
new file mode 100644
index 000000000..c15e87da5
--- /dev/null
+++ b/src/initrd/nm-initrd-generator.c
@@ -0,0 +1,145 @@
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; 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"
+
+static void
+output_conn (gpointer key, gpointer value, gpointer user_data)
+{
+ const char *interface = key;
+ const char *basename = interface ?: "default_connection";
+ 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_printerr ("%s\n", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ file = nm_keyfile_write (connection, NULL, NULL, &error);
+ if (file == NULL) {
+ g_printerr ("%s\n", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ data = g_key_file_to_data (file, &len, &error);
+ if (!data) {
+ g_printerr ("%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_printerr ("%s\n", error->message);
+ g_error_free (error);
+ }
+ g_free (filename);
+ } else {
+ g_printerr ("\n*** Connection '%s' ***\n\n%s\n", basename, data);
+ }
+
+ g_key_file_free (file);
+}
+
+#define DEFAULT_CONNECTIONS_DIR NMRUNDIR "/system-connections"
+#define DEFAULT_ISCSIADM SBINDIR "/iscsiadm"
+
+int
+main (int argc, char *argv[])
+{
+ GHashTable *connections;
+ GHashTable *ibft_blocks = NULL;
+ gs_free char *connections_dir = NULL;
+ gs_free char *iscsiadm = NULL;
+ gboolean dump_to_stdout = FALSE;
+ gboolean no_iscsi = 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 },
+ { "iscsiadm", 'i', 0, G_OPTION_ARG_FILENAME, &iscsiadm, "The scsiadm binary for iBFT", DEFAULT_ISCSIADM },
+ { "stdout", 's', 0, G_OPTION_ARG_NONE, &dump_to_stdout, "Dump connections to standard output", NULL },
+ { "no-iscsi", 'n', 0, G_OPTION_ARG_NONE, &no_iscsi, "Skip iBFT parsing", 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=...] [bridge=...] [team=...] [bond=...] [vlan=...] ... ");
+ 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)) {
+ g_printerr ("%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 (!iscsiadm)
+ iscsiadm = g_strdup (DEFAULT_ISCSIADM);
+ if (dump_to_stdout)
+ g_clear_pointer (&connections_dir, g_free);
+ if (no_iscsi)
+ g_clear_pointer (&iscsiadm, g_free);
+
+ if (connections_dir && g_mkdir_with_parents (connections_dir, 0755) != 0) {
+ g_printerr ("%s: %s\n", connections_dir, strerror (errno));
+ return 1;
+ }
+
+ if (iscsiadm) {
+ ibft_blocks = nmi_ibft_reader_load_blocks (iscsiadm, &error);
+ if (!ibft_blocks) {
+ g_printerr ("%s\n", error->message);
+ g_error_free (error);
+ }
+ /* Just don't fail yet and do our best. */
+ }
+
+ connections = nmi_cmdline_reader_parse (ibft_blocks, remaining);
+
+ g_hash_table_foreach (connections, output_conn, connections_dir);
+
+ if (ibft_blocks)
+ g_hash_table_destroy (ibft_blocks);
+ g_hash_table_destroy (connections);
+
+ return 0;
+}
diff --git a/src/initrd/nmi-ibft-reader.h b/src/initrd/nm-initrd-generator.h
index b0e06b540..49f613b8c 100644
--- a/src/initrd/nmi-ibft-reader.h
+++ b/src/initrd/nm-initrd-generator.h
@@ -1,5 +1,4 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/* NetworkManager system settings service
+/* NetworkManager -- Network link manager
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,11 +14,11 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Copyright 2014 Red Hat, Inc.
+ * Copyright (C) 2014, 2018 Red Hat, Inc.
*/
-#ifndef __NMS_IBFT_READER_H__
-#define __NMS_IBFT_READER_H__
+#ifndef __NM_INITRD_GENERATOR_H__
+#define __NM_INITRD_GENERATOR_H__
#include "nm-connection.h"
@@ -31,4 +30,6 @@ gboolean nmi_ibft_reader_parse_block (const GPtrArray *block, GError **error, ..
gboolean nmi_ibft_reader_update_connection_from_block (NMConnection *connection, const GPtrArray *block, GError **error);
-#endif /* __NMS_IBFT_READER_H__ */
+GHashTable *nmi_cmdline_reader_parse (GHashTable *ibft_blocks, char **argv);
+
+#endif /* __NM_INITRD_GENERATOR_H__ */
diff --git a/src/initrd/nmi-cmdline-reader.c b/src/initrd/nmi-cmdline-reader.c
new file mode 100644
index 000000000..f73fd315a
--- /dev/null
+++ b/src/initrd/nmi-cmdline-reader.c
@@ -0,0 +1,576 @@
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; 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-internal.h"
+
+#include "nm-initrd-generator.h"
+
+#include <string.h>
+
+static NMConnection *
+get_conn (GHashTable *connections, const char *ifname, const char *type_name)
+{
+ NMConnection *connection;
+ NMSetting *setting;
+
+ connection = g_hash_table_lookup (connections, ifname);
+ if (connection)
+ return connection;
+
+ if (!connection) {
+ connection = nm_simple_connection_new ();
+ g_hash_table_insert (connections, (gpointer)ifname, connection);
+
+ /* Start off assuming dynamic IP configurations. */
+
+ setting = nm_setting_ip4_config_new ();
+ nm_connection_add_setting (connection, setting);
+ g_object_set (setting,
+ NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO,
+ NM_SETTING_IP_CONFIG_MAY_FAIL, TRUE,
+ NULL);
+
+ setting = nm_setting_ip6_config_new ();
+ nm_connection_add_setting (connection, setting);
+ g_object_set (setting,
+ NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO,
+ NM_SETTING_IP_CONFIG_MAY_FAIL, TRUE,
+ NULL);
+
+ setting = nm_setting_connection_new ();
+ nm_connection_add_setting (connection, setting);
+ g_object_set (setting,
+ NM_SETTING_CONNECTION_ID, ifname ?: "Wired Connection",
+ NM_SETTING_CONNECTION_UUID, nm_utils_uuid_generate_a (),
+ NM_SETTING_CONNECTION_INTERFACE_NAME, ifname,
+ NULL);
+
+ if (!type_name)
+ type_name = NM_SETTING_WIRED_SETTING_NAME;
+ }
+
+ if (type_name) {
+ g_object_set (setting, NM_SETTING_CONNECTION_TYPE, type_name, NULL);
+ if (!nm_connection_get_setting_by_name (connection, type_name)) {
+ setting = g_object_new (nm_setting_lookup_type (type_name), NULL);
+ nm_connection_add_setting (connection, setting);
+ }
+ }
+
+ return connection;
+}
+
+static char *
+get_word (char **argument, const char separator)
+{
+ char *word;
+ int nest = 0;
+
+ if (**argument == '[') {
+ nest++;
+ (*argument)++;
+ }
+
+ word = *argument;
+
+ while (**argument != '\0') {
+ if (nest && **argument == ']') {
+ **argument = '\0';
+ (*argument)++;
+ nest--;
+ }
+
+ if (nest == 0 && **argument == separator) {
+ **argument = '\0';
+ (*argument)++;
+ break;
+ }
+ (*argument)++;
+ }
+
+ return *word ? word : NULL;
+}
+
+static gboolean
+guess_ip_address_family (const char *str)
+{
+ if (str == NULL)
+ return AF_UNSPEC;
+ if (strchr (str, '.'))
+ return AF_INET;
+ if (strchr (str, ':'))
+ return AF_INET6;
+ return AF_UNSPEC;
+}
+
+static void
+_merge_ibft_block (gpointer key, gpointer value, gpointer user_data)
+{
+ const char *ifname = key;
+ GPtrArray *block = value;
+ GHashTable *connections = user_data;
+ NMConnection *connection;
+ GError *error = NULL;
+
+ connection = get_conn (connections, ifname, NULL);
+ if (!nmi_ibft_reader_update_connection_from_block (connection, block, &error)) {
+ g_printerr ("Unable to merge iBFT configuration: %s", error->message);
+ g_error_free (error);
+ }
+}
+
+static void
+_base_setting_set (NMConnection *connection, const char *property, const char *value)
+{
+ NMSetting *setting;
+ const char *type_name = nm_connection_get_connection_type (connection);
+ GObjectClass *object_class = g_type_class_ref (nm_setting_lookup_type (type_name));
+ GParamSpec *spec = g_object_class_find_property (object_class, property);
+
+ if (!spec) {
+ g_printerr ("'%s' does not support setting %s\n", type_name, property);
+ return;
+ }
+
+ setting = nm_connection_get_setting_by_name (connection, type_name);
+
+ if (G_IS_PARAM_SPEC_UINT (spec))
+ g_object_set (setting, property, g_ascii_strtoull (value, NULL, 10), NULL);
+ else if (G_IS_PARAM_SPEC_STRING (spec))
+ g_object_set (setting, property, value, NULL);
+ else
+ g_printerr ("Don't know how to set '%s' of %s\n", property, type_name);
+
+ g_type_class_unref (object_class);
+}
+
+static void
+parse_ip (GHashTable *connections, GHashTable *ibft_blocks,
+ char *argument)
+{
+ NMConnection *connection;
+ NMSettingIPConfig *s_ip4 = NULL, *s_ip6 = NULL;
+ GError *error = NULL;
+ const char *tmp;
+ const char *kind = NULL;
+ const char *client_ip = NULL;
+ const char *peer = NULL;
+ const char *gateway_ip = NULL;
+ const char *netmask = NULL;
+ const char *client_hostname = NULL;
+ const char *ifname = NULL;
+ const char *mtu = NULL;
+ const char *macaddr = NULL;
+ int client_ip_family = AF_UNSPEC;
+ int client_ip_prefix = -1;
+ const char *dns[2] = { 0, };
+ int dns_addr_family[2] = { 0, };
+ int i;
+
+ if (argument == NULL)
+ return;
+
+ tmp = get_word (&argument, ':');
+ if (argument == NULL) {
+ /* ip={dhcp|on|any|dhcp6|auto6} */
+ kind = tmp;
+ } else {
+ client_ip_family = guess_ip_address_family (tmp);
+ if (client_ip_family != AF_UNSPEC) {
+ // <client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:
+ client_ip = tmp;
+ peer = get_word (&argument, ':');
+ gateway_ip = get_word (&argument, ':');
+ netmask = get_word (&argument, ':');
+ client_hostname = get_word (&argument, ':');
+ ifname = get_word (&argument, ':');
+ } else {
+ ifname = tmp;
+ }
+
+ /* <ifname>:{none|off|dhcp|on|any|dhcp6|auto6|ibft} */
+
+ kind = get_word (&argument, ':');
+
+ tmp = get_word (&argument, ':');
+ dns_addr_family[0] = guess_ip_address_family (tmp);
+ if (dns_addr_family[0] != AF_UNSPEC) {
+ dns[0] = tmp;
+ dns[1] = get_word (&argument, ':');
+ dns_addr_family[1] = guess_ip_address_family (dns[1]);
+ if (argument)
+ g_printerr ("Ignoring extra: '%s'.\n", argument);
+ } else {
+ mtu = tmp;
+ macaddr = argument;
+ }
+ }
+
+ if (ifname == NULL && g_strcmp0 (kind, "ibft") == 0) {
+ /* This is perhaps the ip=ibft case. Just take all we got from iBFT
+ * and don't process anything else, since there's no ifname
+ * specified to apply it to. */
+ if (ibft_blocks)
+ g_hash_table_foreach (ibft_blocks, _merge_ibft_block, connections);
+ else
+ g_printerr ("No iBFT blocks.\n");
+ return;
+ }
+
+ /* Parsing done, construct the NMConnection. */
+ connection = get_conn (connections, ifname, NULL);
+ s_ip4 = nm_connection_get_setting_ip4_config (connection);
+ s_ip6 = nm_connection_get_setting_ip6_config (connection);
+
+ if (netmask && *netmask) {
+ NMIPAddr addr;
+
+ if (nm_utils_parse_inaddr_bin (AF_INET, netmask, &addr)) {
+ client_ip_prefix = nm_utils_ip4_netmask_to_prefix (addr.addr4);
+ } else {
+ g_printerr ("Unrecognized address: %s\n", client_ip);
+ }
+ }
+
+ /* Static IP configuration might be present. */
+ if (client_ip && *client_ip) {
+ NMIPAddress *address = NULL;
+ NMIPAddr addr;
+
+ if (nm_utils_parse_inaddr_prefix_bin (client_ip_family, client_ip, &addr,
+ client_ip_prefix == -1 ? &client_ip_prefix : NULL)) {
+ if (client_ip_prefix == -1) {
+ switch (client_ip_family) {
+ case AF_INET:
+ client_ip_prefix = _nm_utils_ip4_get_default_prefix (addr.addr4);
+ break;
+ case AF_INET6:
+ client_ip_prefix = 64;
+ break;
+ }
+ }
+
+ address = nm_ip_address_new_binary (client_ip_family, &addr.addr_ptr, client_ip_prefix, &error);
+ if (!address) {
+ g_printerr ("Invalid address '%s': %s\n", client_ip, error->message);
+ g_clear_error (&error);
+ }
+ } else {
+ g_printerr ("Unrecognized address: %s\n", client_ip);
+ }
+
+ if (address) {
+ switch (client_ip_family) {
+ case AF_INET:
+ g_object_set (s_ip4,
+ NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
+ NM_SETTING_IP_CONFIG_MAY_FAIL, FALSE,
+ NULL);
+ nm_setting_ip_config_add_address (s_ip4, address);
+ break;
+ case AF_INET6:
+ g_object_set (s_ip6,
+ NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
+ NM_SETTING_IP_CONFIG_MAY_FAIL, FALSE,
+ NULL);
+ nm_setting_ip_config_add_address (s_ip6, address);
+ break;
+ default:
+ break;
+ g_printerr ("Unknown address family: %s\n", client_ip);
+ }
+ nm_ip_address_unref (address);
+ }
+ }
+
+ /* Dynamic IP configuration configured explicitly. */
+ if (g_strcmp0 (kind, "none") == 0 || (g_strcmp0 (kind, "off") == 0)) {
+ if (nm_setting_ip_config_get_num_addresses (s_ip6) == 0) {
+ g_object_set (s_ip6,
+ NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
+ NULL);
+ }
+ if (nm_setting_ip_config_get_num_addresses (s_ip4) == 0) {
+ g_object_set (s_ip4,
+ NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_DISABLED,
+ NULL);
+ }
+ } else if (g_strcmp0 (kind, "dhcp") == 0) {
+ g_object_set (s_ip4,
+ NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO,
+ NM_SETTING_IP_CONFIG_MAY_FAIL, FALSE,
+ NULL);
+ if (nm_setting_ip_config_get_num_addresses (s_ip6) == 0) {
+ g_object_set (s_ip6,
+ NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE,
+ NULL);
+ }
+ } else if (g_strcmp0 (kind, "dhcp6") == 0) {
+ g_object_set (s_ip6,
+ NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_DHCP,
+ NM_SETTING_IP_CONFIG_MAY_FAIL, FALSE,
+ NULL);
+ if (nm_setting_ip_config_get_num_addresses (s_ip4) == 0) {
+ g_object_set (s_ip4,
+ NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_DISABLED,
+ NULL);
+ }
+ } else if (g_strcmp0 (kind, "auto6") == 0) {
+ g_object_set (s_ip4,
+ NM_SETTING_IP_CONFIG_MAY_FAIL, FALSE,
+ NULL);
+ if (nm_setting_ip_config_get_num_addresses (s_ip4) == 0) {
+ g_object_set (s_ip4,
+ NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_DISABLED,
+ NULL);
+ }
+ } else if (g_strcmp0 (kind, "ibft") == 0) {
+ GPtrArray *block = g_hash_table_lookup (ibft_blocks, ifname);
+
+ if (!block) {
+ g_printerr ("No IBFT block for %s\n", ifname);
+ } else if (!nmi_ibft_reader_update_connection_from_block (connection, block, &error)) {
+ g_printerr ("Unable to merge iBFT configuration: %s", error->message);
+ g_error_free (error);
+ }
+ }
+
+ if (peer && *peer)
+ g_printerr ("Ignoring peer: %s (not implemented)\b", peer);
+
+ if (gateway_ip && *gateway_ip) {
+ int addr_family = guess_ip_address_family (gateway_ip);
+
+ if (nm_utils_ipaddr_valid (addr_family, gateway_ip)) {
+ switch (addr_family) {
+ case AF_INET:
+ g_object_set (s_ip4, NM_SETTING_IP_CONFIG_GATEWAY, gateway_ip, NULL);
+ break;
+ case AF_INET6:
+ g_object_set (s_ip6, NM_SETTING_IP_CONFIG_GATEWAY, gateway_ip, NULL);
+ break;
+ default:
+ break;
+ g_printerr ("Unknown address family: %s\n", gateway_ip);
+ }
+ } else {
+ g_printerr ("Invalid gateway: %s\n", gateway_ip);
+ }
+ }
+
+ if (client_hostname && *client_hostname) {
+ g_object_set (s_ip4, NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, client_hostname, NULL);
+ g_object_set (s_ip6, NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, client_hostname, NULL);
+ }
+
+ for (i = 0; i < 2; i++) {
+ if (dns_addr_family[i] == AF_UNSPEC)
+ break;
+ if (nm_utils_ipaddr_valid (dns_addr_family[i], dns[i])) {
+ switch (dns_addr_family[i]) {
+ case AF_INET:
+ nm_setting_ip_config_add_dns (s_ip4, dns[i]);
+ break;
+ case AF_INET6:
+ nm_setting_ip_config_add_dns (s_ip6, dns[i]);
+ break;
+ default:
+ break;
+ g_printerr ("Unknown address family: %s\n", dns[i]);
+ }
+ } else {
+ g_printerr ("Invalid name server: %s\n", dns[i]);
+ }
+ }
+
+ if (mtu && *mtu)
+ _base_setting_set (connection, "mtu", mtu);
+
+ if (macaddr && *macaddr)
+ _base_setting_set (connection, "cloned-mac-address", macaddr);
+
+ return;
+}
+
+static void
+parse_master (GHashTable *connections, char *argument, const char *type_name)
+{
+ NMConnection *connection;
+ NMSettingConnection *s_con;
+ NMSettingBond *s_bond;
+ const char *master;
+ char *slaves;
+ const char *slave;
+ char *opts;
+ char *opt;
+ const char *opt_name;
+ const char *mtu = NULL;
+
+ master = get_word (&argument, ':');
+ slaves = get_word (&argument, ':');
+
+ connection = get_conn (connections, master, type_name);
+ s_con = nm_connection_get_setting_connection (connection);
+ master = nm_setting_connection_get_uuid (s_con);
+
+ if (strcmp (type_name, NM_SETTING_BOND_SETTING_NAME) == 0) {
+ s_bond = (NMSettingBond *)nm_connection_get_setting_by_name (connection, type_name);
+
+ opts = get_word (&argument, ':');
+ while (opts) {
+ opt = get_word (&opts, ',');
+ opt_name = get_word (&opt, '=');
+ nm_setting_bond_add_option (s_bond, opt_name, opt);
+ }
+
+ mtu = get_word (&argument, ':');
+ }
+
+ do {
+ slave = get_word (&slaves, ',');
+ if (slave == NULL)
+ slave = "eth0";
+
+ connection = get_conn (connections, slave, NULL);
+ s_con = nm_connection_get_setting_connection (connection);
+ g_object_set (s_con,
+ NM_SETTING_CONNECTION_SLAVE_TYPE, type_name,
+ NM_SETTING_CONNECTION_MASTER, master,
+ NULL);
+ if (mtu)
+ _base_setting_set (connection, "mtu", mtu);
+ } while (*slaves != '\0');
+
+ if (argument)
+ g_printerr ("Ignoring extra: '%s'.\n", argument);
+}
+
+static void
+parse_rd_route (GHashTable *connections, char *argument)
+{
+ NMConnection *connection;
+ const char *net;
+ const char *gateway;
+ const char *interface;
+ int family = AF_UNSPEC;
+ NMIPAddr net_addr;
+ NMIPAddr gateway_addr;
+ int net_prefix;
+ NMIPRoute *route;
+ NMSettingIPConfig *s_ip;
+ GError *error = NULL;
+
+ net = get_word (&argument, ':');
+ gateway = get_word (&argument, ':');
+ interface = get_word (&argument, ':');
+
+ family = guess_ip_address_family (net);
+ connection = get_conn (connections, interface, NULL);
+
+ switch (family) {
+ case AF_INET:
+ s_ip = nm_connection_get_setting_ip4_config (connection);
+ break;
+ case AF_INET6:
+ s_ip = nm_connection_get_setting_ip6_config (connection);
+ break;
+ default:
+ g_printerr ("Unknown address family: %s\n", net);
+ break;
+ }
+
+ if (!nm_utils_parse_inaddr_prefix_bin (family, net, &net_addr, &net_prefix)) {
+ g_printerr ("Unrecognized address: %s\n", net);
+ return;
+ }
+
+ if (!nm_utils_parse_inaddr_bin (family, gateway, &gateway_addr)) {
+ g_printerr ("Unrecognized address: %s\n", gateway);
+ return;
+ }
+
+ route = nm_ip_route_new_binary (family, &net_addr.addr_ptr, net_prefix, &gateway_addr.addr_ptr, -1, &error);
+ if (!route) {
+ g_printerr ("Invalid route '%s via %s': %s\n", net, gateway, error->message);
+ g_clear_error (&error);
+ }
+
+ nm_setting_ip_config_add_route (s_ip, route);
+ nm_ip_route_unref (route);
+}
+
+static void
+parse_vlan (GHashTable *connections, char *argument)
+{
+ NMConnection *connection;
+ NMSettingVlan *s_vlan;
+ const char *vlan;
+ const char *phy;
+ const char *vlanid;
+
+ vlan = get_word (&argument, ':');
+ phy = get_word (&argument, ':');
+
+ for (vlanid = vlan + strlen (vlan); vlanid > vlan; vlanid--) {
+ if (!g_ascii_isdigit (*(vlanid - 1)))
+ break;
+ }
+
+ connection = get_conn (connections, vlan, NM_SETTING_VLAN_SETTING_NAME);
+
+ s_vlan = nm_connection_get_setting_vlan (connection);
+ g_object_set (s_vlan,
+ NM_SETTING_VLAN_PARENT, phy,
+ NM_SETTING_VLAN_ID, g_ascii_strtoull (vlanid, NULL, 10),
+ NULL);
+
+ if (argument)
+ g_printerr ("Ignoring extra: '%s'.\n", argument);
+}
+
+GHashTable *
+nmi_cmdline_reader_parse (GHashTable *ibft_blocks, char **argv)
+{
+ GHashTable *connections;
+ const char *tag;
+ char *argument;
+ int i;
+
+ connections = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, g_object_unref);
+
+ for (i = 0; argv[i]; i++) {
+ argument = argv[i];
+ tag = get_word (&argument, '=');
+ if (strcmp (tag, "ip") == 0)
+ parse_ip (connections, ibft_blocks, argument);
+ else if (strcmp (tag, "rd.route") == 0)
+ parse_rd_route (connections, argument);
+ else if (strcmp (tag, "bridge") == 0)
+ parse_master (connections, argument, NM_SETTING_BRIDGE_SETTING_NAME);
+ else if (strcmp (tag, "bond") == 0)
+ parse_master (connections, argument, NM_SETTING_BOND_SETTING_NAME);
+ else if (strcmp (tag, "team") == 0)
+ parse_master (connections, argument, NM_SETTING_TEAM_SETTING_NAME);
+ else if (strcmp (tag, "vlan") == 0)
+ parse_vlan (connections, argument);
+ }
+
+ return connections;
+}
diff --git a/src/initrd/nmi-ibft-reader.c b/src/initrd/nmi-ibft-reader.c
index 95bef60d3..d13331647 100644
--- a/src/initrd/nmi-ibft-reader.c
+++ b/src/initrd/nmi-ibft-reader.c
@@ -20,7 +20,7 @@
#include "nm-default.h"
-#include "nmi-ibft-reader.h"
+#include "nm-initrd-generator.h"
#include <stdlib.h>
#include <string.h>
@@ -125,6 +125,8 @@ nmi_ibft_reader_load_blocks (const char *iscsiadm_path, GError **error)
g_return_val_if_fail (iscsiadm_path != NULL, FALSE);
+ nm_utils_modprobe (NULL, FALSE, "ibft_iscsi", NULL);
+
if (!g_spawn_sync ("/", (char **) argv, (char **) envp, 0,
NULL, NULL, &out, &err, &status, error))
goto done;
diff --git a/src/initrd/tests/test-ibft.c b/src/initrd/tests/test-ibft.c
index 084415f3a..dfe529b4e 100644
--- a/src/initrd/tests/test-ibft.c
+++ b/src/initrd/tests/test-ibft.c
@@ -32,7 +32,7 @@
#include "nm-core-internal.h"
#include "NetworkManagerUtils.h"
-#include "../nmi-ibft-reader.h"
+#include "../nm-initrd-generator.h"
#include "nm-test-utils-core.h"