diff options
author | Lubomir Rintel <lkundrak@v3.sk> | 2018-04-28 20:36:15 +0200 |
---|---|---|
committer | Lubomir Rintel <lkundrak@v3.sk> | 2018-05-21 19:02:53 +0200 |
commit | 68af115fba597501a886a8ec4be83e8c624e91e6 (patch) | |
tree | f59eb2c83723ebf3fcbc89f4f005545649b5f009 | |
parent | dab54a0917f097f7926c68b8fb083ddb14fa79f9 (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.am | 62 | ||||
-rw-r--r-- | contrib/fedora/rpm/NetworkManager.spec | 1 | ||||
-rw-r--r-- | src/initrd/nm-initrd-generator.c | 145 | ||||
-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.c | 576 | ||||
-rw-r--r-- | src/initrd/nmi-ibft-reader.c | 4 | ||||
-rw-r--r-- | src/initrd/tests/test-ibft.c | 2 |
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" |