nm-initrd-generator: add kernel command line options ethtool autoneg, speed and duplex to configure NICs

Merge Request !941
This commit is contained in:
Ana Cabral
2021-07-26 12:14:19 -03:00
parent 97041efee1
commit f06c89f596
2 changed files with 281 additions and 1 deletions

View File

@@ -1170,6 +1170,97 @@ reader_parse_rd_znet(Reader *reader, char *argument, gboolean net_ifnames)
}
}
static void
reader_parse_ethtool(Reader *reader, char *argument)
{
NMConnection * connection = NULL;
NMSettingWired *s_wired = NULL;
const char * read = NULL;
const char * interface = NULL;
gboolean autoneg = FALSE;
guint speed = 0;
interface = get_word(&argument, ':');
if (!interface) {
_LOGW(LOGD_CORE, "Impossible to set rd.ethtool options: invalid format");
return;
}
if (!*argument)
return;
read = get_word(&argument, ':');
if (read) {
autoneg = _nm_utils_ascii_str_to_bool(read, -1);
if (autoneg == -1)
_LOGW(LOGD_CORE, "rd.ethtool autoneg was not set, invalid value");
else {
connection =
reader_get_connection(reader, interface, NM_SETTING_WIRED_SETTING_NAME, TRUE);
s_wired = nm_connection_get_setting_wired(connection);
g_object_set(s_wired, NM_SETTING_WIRED_AUTO_NEGOTIATE, autoneg, NULL);
}
}
if (!*argument)
return;
read = get_word(&argument, ':');
if (read) {
speed = _nm_utils_ascii_str_to_int64(read, 10, 0, G_MAXUINT32, -1);
if (speed == -1) {
_LOGW(LOGD_CORE,
"rd.ethtool speed was not set, invalid value. Then, duplex was disregarded.");
/* Duplex does not need to be evaluated after, because it can't be set without speed value */
return;
} else {
connection =
reader_get_connection(reader, interface, NM_SETTING_WIRED_SETTING_NAME, TRUE);
s_wired = nm_connection_get_setting_wired(connection);
/* duplex option is available for legacy purposes */
/* speed must be always set having duplex set, otherwise it will fail in verifications */
if (*argument) {
/* duplex value was informed, and has a valid value */
if (NM_IN_STRSET(argument, "half", "full"))
g_object_set(s_wired,
NM_SETTING_WIRED_SPEED,
speed,
NM_SETTING_WIRED_DUPLEX,
argument,
NULL);
/* duplex value was informed, and does not have a valid value */
else {
_LOGW(LOGD_CORE,
"rd.ethtool.duplex has a invalid format, duplex was set as default:full");
g_object_set(s_wired,
NM_SETTING_WIRED_SPEED,
speed,
NM_SETTING_WIRED_DUPLEX,
"full",
NULL);
}
} else {
/* duplex value was not informed, then it will have default 'full' value */
g_object_set(s_wired,
NM_SETTING_WIRED_SPEED,
speed,
NM_SETTING_WIRED_DUPLEX,
"full",
NULL);
}
/* Duplex does not need to be evaluated alone - it can't be set without speed value */
return;
}
}
if (!*argument)
return;
else {
/* Duplex does not need to be evaluated, because it can't be set without speed value */
_LOGW(LOGD_CORE, "rd.ethtool.duplex needs rd.ethtool.speed value to be set");
}
}
static void
_normalize_conn(gpointer key, gpointer value, gpointer user_data)
{
@@ -1351,7 +1442,8 @@ nmi_cmdline_reader_parse(const char * sysfs_dir,
} else if (g_ascii_strcasecmp(tag, "BOOTIF") == 0) {
nm_clear_g_free(&bootif_val);
bootif_val = g_strdup(argument);
}
} else if (nm_streq(tag, "rd.ethtool"))
reader_parse_ethtool(reader, argument);
}
for (i = 0; i < reader->vlan_parents->len; i++) {

View File

@@ -2262,6 +2262,193 @@ test_carrier_timeout(void)
g_assert_cmpint(carrier_timeout_sec, ==, 20);
}
/* Obs1.: this function is implemented as macro, and not as a function, to show g_assert() line on debug */
#define _ethtool_connection_check_and_get(connection) \
({ \
NMSettingWired *_s_wired = NULL; \
NMConnection * _connection = connection; \
\
g_assert(nm_connection_get_setting_connection(_connection)); \
g_assert(nm_connection_is_type(_connection, NM_SETTING_WIRED_SETTING_NAME)); \
g_assert(nm_connection_get_setting_ip4_config(_connection)); \
g_assert(nm_connection_get_setting_ip6_config(_connection)); \
_s_wired = nm_connection_get_setting_wired(_connection); \
g_assert(_s_wired); \
\
_s_wired; \
})
static void
test_rd_ethtool(void)
{
const char *const *ARGV = NULL;
NMConnection * connection = NULL;
GHashTable * connections = NULL;
NMSettingWired * s_wired = NULL;
ARGV = NM_MAKE_STRV("rd.ethtool=");
NMTST_EXPECT_NM_WARN("cmdline-reader: Impossible to set rd.ethtool options: invalid format");
connections = _parse_cons(ARGV);
g_assert_cmpint(g_hash_table_size(connections), ==, 0);
g_hash_table_unref(connections);
g_test_assert_expected_messages();
ARGV = NM_MAKE_STRV("rd.ethtool=eth0");
connections = _parse_cons(ARGV);
g_assert_cmpint(g_hash_table_size(connections), ==, 0);
g_hash_table_unref(connections);
ARGV = NM_MAKE_STRV("rd.ethtool=eth0:");
connections = _parse_cons(ARGV);
g_assert_cmpint(g_hash_table_size(connections), ==, 0);
g_hash_table_unref(connections);
ARGV = NM_MAKE_STRV("rd.ethtool=::");
NMTST_EXPECT_NM_WARN("cmdline-reader: Impossible to set rd.ethtool options: invalid format");
connections = _parse_cons(ARGV);
g_assert_cmpint(g_hash_table_size(connections), ==, 0);
g_test_assert_expected_messages();
g_hash_table_unref(connections);
ARGV = NM_MAKE_STRV("rd.ethtool=eth0:on");
connection = _parse_con(ARGV, "eth0");
s_wired = _ethtool_connection_check_and_get(connection);
g_assert(nm_setting_wired_get_auto_negotiate(s_wired));
g_object_unref(connection);
ARGV = NM_MAKE_STRV("rd.ethtool=eth0:off");
connection = _parse_con(ARGV, "eth0");
s_wired = _ethtool_connection_check_and_get(connection);
g_assert(!nm_setting_wired_get_auto_negotiate(s_wired));
g_object_unref(connection);
ARGV = NM_MAKE_STRV("rd.ethtool=eth0:true");
connection = _parse_con(ARGV, "eth0");
s_wired = _ethtool_connection_check_and_get(connection);
g_assert(nm_setting_wired_get_auto_negotiate(s_wired));
g_object_unref(connection);
ARGV = NM_MAKE_STRV("rd.ethtool=eth0:false");
connection = _parse_con(ARGV, "eth0");
s_wired = _ethtool_connection_check_and_get(connection);
g_assert(!nm_setting_wired_get_auto_negotiate(s_wired));
g_object_unref(connection);
ARGV = NM_MAKE_STRV("rd.ethtool=eth0:1");
connection = _parse_con(ARGV, "eth0");
s_wired = _ethtool_connection_check_and_get(connection);
g_assert(nm_setting_wired_get_auto_negotiate(s_wired));
g_object_unref(connection);
ARGV = NM_MAKE_STRV("rd.ethtool=eth0:0");
connection = _parse_con(ARGV, "eth0");
s_wired = _ethtool_connection_check_and_get(connection);
g_assert(!nm_setting_wired_get_auto_negotiate(s_wired));
g_object_unref(connection);
ARGV = NM_MAKE_STRV("rd.ethtool=eth0:randomstring");
NMTST_EXPECT_NM_WARN("cmdline-reader: rd.ethtool autoneg was not set, invalid value");
connections = _parse_cons(ARGV);
g_assert_cmpint(g_hash_table_size(connections), ==, 0);
g_test_assert_expected_messages();
g_hash_table_unref(connections);
ARGV = NM_MAKE_STRV("rd.ethtool=eth0::");
connections = _parse_cons(ARGV);
g_assert_cmpint(g_hash_table_size(connections), ==, 0);
g_hash_table_unref(connections);
ARGV = NM_MAKE_STRV("rd.ethtool=eth0::astring");
NMTST_EXPECT_NM_WARN("cmdline-reader: rd.ethtool speed was not set, invalid value. Then, "
"duplex was disregarded.");
connections = _parse_cons(ARGV);
g_assert_cmpint(g_hash_table_size(connections), ==, 0);
g_test_assert_expected_messages();
g_hash_table_unref(connections);
ARGV = NM_MAKE_STRV("rd.ethtool=eth0::1000000000000000000000000000000000000");
NMTST_EXPECT_NM_WARN("cmdline-reader: rd.ethtool speed was not set, invalid value. Then, "
"duplex was disregarded.");
connections = _parse_cons(ARGV);
g_assert_cmpint(g_hash_table_size(connections), ==, 0);
g_test_assert_expected_messages();
g_hash_table_unref(connections);
ARGV = NM_MAKE_STRV("rd.ethtool=eth0::0.67");
NMTST_EXPECT_NM_WARN("cmdline-reader: rd.ethtool speed was not set, invalid value. Then, "
"duplex was disregarded.");
connections = _parse_cons(ARGV);
g_assert_cmpint(g_hash_table_size(connections), ==, 0);
g_test_assert_expected_messages();
g_hash_table_unref(connections);
ARGV = NM_MAKE_STRV("rd.ethtool=eth0::-23");
NMTST_EXPECT_NM_WARN("cmdline-reader: rd.ethtool speed was not set, invalid value. Then, "
"duplex was disregarded.");
connections = _parse_cons(ARGV);
g_assert_cmpint(g_hash_table_size(connections), ==, 0);
g_test_assert_expected_messages();
g_hash_table_unref(connections);
ARGV = NM_MAKE_STRV("rd.ethtool=eth0:1:10");
connection = _parse_con(ARGV, "eth0");
s_wired = _ethtool_connection_check_and_get(connection);
g_assert(nm_setting_wired_get_auto_negotiate(s_wired));
g_assert_cmpint(nm_setting_wired_get_speed(s_wired), ==, 10);
g_assert_cmpstr(nm_setting_wired_get_duplex(s_wired), ==, "full");
g_object_unref(connection);
ARGV = NM_MAKE_STRV("rd.ethtool=eth0::100");
connection = _parse_con(ARGV, "eth0");
s_wired = _ethtool_connection_check_and_get(connection);
g_assert(!nm_setting_wired_get_auto_negotiate(s_wired));
g_assert_cmpint(nm_setting_wired_get_speed(s_wired), ==, 100);
g_assert_cmpstr(nm_setting_wired_get_duplex(s_wired), ==, "full");
g_object_unref(connection);
ARGV = NM_MAKE_STRV("rd.ethtool=eth0:::half");
NMTST_EXPECT_NM_WARN(
"cmdline-reader: rd.ethtool.duplex needs rd.ethtool.speed value to be set");
connections = _parse_cons(ARGV);
g_assert_cmpint(g_hash_table_size(connections), ==, 0);
g_test_assert_expected_messages();
g_hash_table_unref(connections);
ARGV = NM_MAKE_STRV("rd.ethtool=eth0::10:half");
connection = _parse_con(ARGV, "eth0");
s_wired = _ethtool_connection_check_and_get(connection);
g_assert(!nm_setting_wired_get_auto_negotiate(s_wired));
g_assert_cmpint(nm_setting_wired_get_speed(s_wired), ==, 10);
g_assert_cmpstr(nm_setting_wired_get_duplex(s_wired), ==, "half");
g_object_unref(connection);
ARGV = NM_MAKE_STRV("rd.ethtool=eth0:on:100:full");
connection = _parse_con(ARGV, "eth0");
s_wired = _ethtool_connection_check_and_get(connection);
g_assert(nm_setting_wired_get_auto_negotiate(s_wired));
g_assert_cmpint(nm_setting_wired_get_speed(s_wired), ==, 100);
g_assert_cmpstr(nm_setting_wired_get_duplex(s_wired), ==, "full");
g_object_unref(connection);
ARGV = NM_MAKE_STRV("rd.ethtool=eth0:on:100:anyvalue");
NMTST_EXPECT_NM_WARN(
"cmdline-reader: rd.ethtool.duplex has a invalid format, duplex was set as default:full");
connection = _parse_con(ARGV, "eth0");
s_wired = _ethtool_connection_check_and_get(connection);
g_assert(nm_setting_wired_get_auto_negotiate(s_wired));
g_assert_cmpint(nm_setting_wired_get_speed(s_wired), ==, 100);
g_assert_cmpstr(nm_setting_wired_get_duplex(s_wired), ==, "full");
g_test_assert_expected_messages();
g_object_unref(connection);
ARGV = NM_MAKE_STRV("rd.ethtool=:::");
NMTST_EXPECT_NM_WARN("cmdline-reader: Impossible to set rd.ethtool options: invalid format");
connections = _parse_cons(ARGV);
g_assert_cmpint(g_hash_table_size(connections), ==, 0);
g_test_assert_expected_messages();
g_hash_table_unref(connections);
}
NMTST_DEFINE();
int
@@ -2316,6 +2503,7 @@ main(int argc, char **argv)
g_test_add_func("/initrd/cmdline/infiniband/mac", test_infiniband_mac);
g_test_add_func("/initrd/cmdline/infiniband/pkey", test_infiniband_pkey);
g_test_add_func("/initrd/cmdline/carrier_timeout", test_carrier_timeout);
g_test_add_func("/initrd/cmdline/rd_ethtool", test_rd_ethtool);
return g_test_run();
}