initrd: add support for rd.znet_ifnames

This uses interface names specified rd.znet_ifnames on kernel command line
instead of automatically generated names if possible.

Accompanied by a test.

https://bugzilla.redhat.com/show_bug.cgi?id=1980387
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1070
This commit is contained in:
Lubomir Rintel 2022-01-24 22:42:07 +01:00
parent 3f0ec85634
commit 68f500f5ce
2 changed files with 106 additions and 3 deletions

View file

@ -34,6 +34,7 @@ typedef struct {
NMConnection *bootdev_connection; /* connection for bootdev=$ifname */
NMConnection *default_connection; /* connection not bound to any ifname */
char *hostname;
GHashTable *znet_ifnames;
/* Parameters to be set for all connections */
gboolean ignore_auto_dns;
@ -55,6 +56,7 @@ reader_new(void)
g_hash_table_new_full(nm_direct_hash, NULL, g_object_unref, NULL),
.vlan_parents = g_ptr_array_new_with_free_func(g_free),
.array = g_ptr_array_new(),
.znet_ifnames = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_free),
};
return reader;
@ -70,6 +72,7 @@ reader_destroy(Reader *reader, gboolean free_hash)
g_hash_table_unref(reader->explicit_ip_connections);
hash = g_steal_pointer(&reader->hash);
nm_clear_g_free(&reader->hostname);
g_hash_table_unref(reader->znet_ifnames);
nm_clear_g_free(&reader->dhcp4_vci);
nm_g_slice_free(reader);
if (!free_hash)
@ -1091,19 +1094,36 @@ reader_parse_ib_pkey(Reader *reader, char *argument)
_LOGW(LOGD_CORE, "Ignoring extra: '%s' for ib.pkey=", argument);
}
static void
reader_parse_znet_ifname(Reader *reader, char *argument)
{
char *ifname;
ifname = get_word(&argument, ':');
if (!ifname) {
_LOGW(LOGD_CORE, "rd.znet_ifname= without argument");
return;
}
if (!g_hash_table_replace(reader->znet_ifnames, g_strdup(argument), g_strdup(ifname))) {
_LOGW(LOGD_CORE, "duplicate rd.znet_ifname for ifname=%s", ifname);
}
}
static void
reader_parse_rd_znet(Reader *reader, char *argument, gboolean net_ifnames)
{
const char *nettype;
const char *subchannels[4] = {0, 0, 0, 0};
const char *tmp;
gs_free char *ifname = NULL;
gs_free char *ifname = NULL;
gs_free char *str_subchannels = NULL;
const char *prefix;
NMConnection *connection;
NMSettingWired *s_wired;
static int count_ctc = 0;
static int count_eth = 0;
int index;
int index = -1;
nettype = get_word(&argument, ',');
subchannels[0] = get_word(&argument, ',');
@ -1131,7 +1151,13 @@ reader_parse_rd_znet(Reader *reader, char *argument, gboolean net_ifnames)
}
}
if (net_ifnames == TRUE) {
str_subchannels = g_strjoinv(",", (char **) subchannels);
ifname = g_hash_table_lookup(reader->znet_ifnames, str_subchannels);
if (ifname) {
ifname = g_strdup(ifname);
g_hash_table_remove(reader->znet_ifnames, str_subchannels);
} else if (net_ifnames == TRUE) {
const char *bus_id;
size_t bus_id_len;
size_t bus_id_start;
@ -1144,6 +1170,7 @@ reader_parse_rd_znet(Reader *reader, char *argument, gboolean net_ifnames)
ifname = g_strdup_printf("%sc%s", prefix, bus_id);
} else {
nm_assert(index > -1);
ifname = g_strdup_printf("%s%d", prefix, index);
}
@ -1423,6 +1450,8 @@ nmi_cmdline_reader_parse(const char *etc_connections_dir,
if (!znets)
znets = g_ptr_array_new_with_free_func(g_free);
g_ptr_array_add(znets, g_strdup(argument));
} else if (nm_streq(tag, "rd.znet_ifname")) {
reader_parse_znet_ifname(reader, argument);
} else if (g_ascii_strcasecmp(tag, "BOOTIF") == 0) {
nm_clear_g_free(&bootif_val);
bootif_val = g_strdup(argument);
@ -1533,6 +1562,10 @@ nmi_cmdline_reader_parse(const char *etc_connections_dir,
reader_parse_rd_znet(reader, znets->pdata[i], net_ifnames);
}
if (g_hash_table_size(reader->znet_ifnames)) {
_LOGW(LOGD_CORE, "Mismatch between rd.znet_ifname and rd.znet");
}
g_hash_table_foreach(reader->hash, _normalize_conn, NULL);
NM_SET_OUT(hostname, g_steal_pointer(&reader->hostname));

View file

@ -1897,6 +1897,75 @@ test_rd_znet_malformed(void)
}
}
static void
test_rd_znet_ifnames(void)
{
gs_unref_hashtable GHashTable *connections = NULL;
const char *const *const ARGV =
NM_MAKE_STRV("rd.znet_ifname=zeth1:0.0.0600,0.0.0601",
"rd.znet=qeth,0.0.0800,0.0.0801,0.0.0802,layer2=0,portno=1,foo",
"rd.znet=ctc,0.0.0600,0.0.0601",
"rd.znet_ifname=zeth0:0.0.0800,0.0.0801,0.0.0802",
"ip=zeth0:dhcp",
"ip=zeth1:dhcp");
NMConnection *connection;
NMSettingConnection *s_con;
NMSettingWired *s_wired;
gs_free char *hostname = NULL;
gint64 carrier_timeout_sec = 0;
const char *const *v_subchannels;
connections = _parse(ARGV, &hostname, &carrier_timeout_sec);
g_assert_cmpint(g_hash_table_size(connections), ==, 2);
connection = g_hash_table_lookup(connections, "zeth0");
g_assert(NM_IS_CONNECTION(connection));
s_con = nm_connection_get_setting_connection(connection);
g_assert(NM_IS_SETTING_CONNECTION(s_con));
g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
==,
NM_SETTING_WIRED_SETTING_NAME);
g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "zeth0");
g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, "zeth0");
s_wired = nm_connection_get_setting_wired(connection);
g_assert_cmpstr(nm_setting_wired_get_s390_nettype(s_wired), ==, "qeth");
g_assert(s_wired);
v_subchannels = nm_setting_wired_get_s390_subchannels(s_wired);
g_assert(v_subchannels);
g_assert_cmpstr(v_subchannels[0], ==, "0.0.0800");
g_assert_cmpstr(v_subchannels[1], ==, "0.0.0801");
g_assert_cmpstr(v_subchannels[2], ==, "0.0.0802");
g_assert_cmpstr(v_subchannels[3], ==, NULL);
nmtst_assert_connection_verifies_without_normalization(connection);
connection = g_hash_table_lookup(connections, "zeth1");
g_assert(NM_IS_CONNECTION(connection));
s_con = nm_connection_get_setting_connection(connection);
g_assert(NM_IS_SETTING_CONNECTION(s_con));
g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
==,
NM_SETTING_WIRED_SETTING_NAME);
g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "zeth1");
g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, "zeth1");
s_wired = nm_connection_get_setting_wired(connection);
g_assert_cmpstr(nm_setting_wired_get_s390_nettype(s_wired), ==, "ctc");
g_assert(s_wired);
v_subchannels = nm_setting_wired_get_s390_subchannels(s_wired);
g_assert(v_subchannels);
g_assert_cmpstr(v_subchannels[0], ==, "0.0.0600");
g_assert_cmpstr(v_subchannels[1], ==, "0.0.0601");
g_assert_cmpstr(v_subchannels[2], ==, NULL);
nmtst_assert_connection_verifies_without_normalization(connection);
}
static void
test_bootif_ip(void)
{
@ -2483,6 +2552,7 @@ main(int argc, char **argv)
g_test_add_func("/initrd/cmdline/rd_znet/legacy", test_rd_znet_legacy);
g_test_add_func("/initrd/cmdline/rd_znet/no_ip", test_rd_znet_no_ip);
g_test_add_func("/initrd/cmdline/rd_znet/empty", test_rd_znet_malformed);
g_test_add_func("/initrd/cmdline/rd_znet/ifnames", test_rd_znet_ifnames);
g_test_add_func("/initrd/cmdline/bootif/ip", test_bootif_ip);
g_test_add_func("/initrd/cmdline/bootif/no_ip", test_bootif_no_ip);
g_test_add_func("/initrd/cmdline/bootif/hwtype", test_bootif_hwtype);