From 12b9d30ae625000c578d6b4f4bcf8c3a119132dc Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Wed, 14 Sep 2016 17:48:13 +0200 Subject: ifcfg-rh: add support to 802-3.[auto-negotiate,speed,duplex] properties NOTE: changed the default value for auto-negotiate from TRUE to FALSE. Normalization enforces that no values for speed and duplex are there when autonegotiation is on. This is required as autoneg on with specific speed and duplex set means to ethtool to use autonegotiation but advertise that specific speed and duplex only. autoneg off, speed 0 and duplex NULL means to ignore link negotiation. --- src/NetworkManager.ver-orig | 3 + .../plugins/ifcfg-rh/nms-ifcfg-rh-reader.c | 87 ++++++++++++++++++++-- .../plugins/ifcfg-rh/nms-ifcfg-rh-writer.c | 51 ++++++++++--- 3 files changed, 126 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/NetworkManager.ver-orig b/src/NetworkManager.ver-orig index 08d5c6e4ec..e89ed95e0d 100644 --- a/src/NetworkManager.ver-orig +++ b/src/NetworkManager.ver-orig @@ -425,7 +425,9 @@ global: nm_setting_vlan_get_type; nm_setting_vlan_new; nm_setting_wired_add_s390_option; + nm_setting_wired_get_auto_negotiate; nm_setting_wired_get_cloned_mac_address; + nm_setting_wired_get_duplex; nm_setting_wired_get_generate_mac_address_mask; nm_setting_wired_get_mac_address; nm_setting_wired_get_mac_address_blacklist; @@ -435,6 +437,7 @@ global: nm_setting_wired_get_s390_option; nm_setting_wired_get_s390_option_by_key; nm_setting_wired_get_s390_subchannels; + nm_setting_wired_get_speed; nm_setting_wired_get_type; nm_setting_wired_get_wake_on_lan; nm_setting_wired_get_wake_on_lan_password; diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index 0ce6f6c140..843bad1c62 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -3655,6 +3655,52 @@ wireless_connection_from_ifcfg (const char *file, return connection; } +static void +parse_ethtool_option_autoneg (const char *value, gboolean *out_autoneg) +{ + if (!value) { + PARSE_WARNING ("Auto-negotiation option missing"); + return; + } + + if (g_str_equal (value, "off")) + *out_autoneg = FALSE; + else if (g_str_equal (value, "on")) + *out_autoneg = TRUE; + else + PARSE_WARNING ("Auto-negotiation unknown value: %s", value); +} + +static void +parse_ethtool_option_speed (const char *value, guint32 *out_speed) +{ + if (!value) { + PARSE_WARNING ("Speed option missing"); + return; + } + + *out_speed = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXUINT32, 0); + if (errno) + PARSE_WARNING ("Speed value '%s' is invalid", value); +} + +static void +parse_ethtool_option_duplex (const char *value, const char **out_duplex) +{ + if (!value) { + PARSE_WARNING ("Duplex option missing"); + return; + } + + if (g_str_equal (value, "half")) + *out_duplex = "half"; + else if (g_str_equal (value, "full")) + *out_duplex = "full"; + else + PARSE_WARNING ("Duplex unknown value: %s", value); + +} + static void parse_ethtool_option_wol (const char *value, NMSettingWiredWakeOnLan *out_flags) { @@ -3715,10 +3761,16 @@ static void parse_ethtool_option_sopass (const char *value, char **out_password) } static void -parse_ethtool_option (const char *value, NMSettingWiredWakeOnLan *out_flags, char **out_password) +parse_ethtool_option (const char *value, + NMSettingWiredWakeOnLan *out_flags, + char **out_password, + gboolean *out_autoneg, + guint32 *out_speed, + const char **out_duplex) { gs_strfreev char **words = NULL; const char **iter = NULL, *opt_val, *opt; + if (!value || !value[0]) return; @@ -3740,7 +3792,13 @@ parse_ethtool_option (const char *value, NMSettingWiredWakeOnLan *out_flags, cha opt_val = iter[0]; - if (g_str_equal (opt, "wol")) + if (g_str_equal (opt, "autoneg")) + parse_ethtool_option_autoneg (opt_val, out_autoneg); + else if (g_str_equal (opt, "speed")) + parse_ethtool_option_speed (opt_val, out_speed); + else if (g_str_equal (opt, "duplex")) + parse_ethtool_option_duplex (opt_val, out_duplex); + else if (g_str_equal (opt, "wol")) parse_ethtool_option_wol (opt_val, out_flags); else if (g_str_equal (opt, "sopass")) parse_ethtool_option_sopass (opt_val, out_password); @@ -3758,31 +3816,48 @@ static void parse_ethtool_options (shvarFile *ifcfg, NMSettingWired *s_wired, const char *value) { NMSettingWiredWakeOnLan wol_flags = NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT; - gs_free char *wol_password = NULL; - gboolean ignore_wol_password = FALSE; + gs_free char *wol_password = NULL, *wol_value = NULL; + gboolean ignore_wol_password = FALSE, autoneg = FALSE; + guint32 speed = 0; + const char *duplex = NULL; if (value) { gs_strfreev char **opts = NULL; const char **iter; - wol_flags = NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE; + /* WAKE_ON_LAN_IGNORE is inferred from a specified but empty ETHTOOL_OPTS */ + if (!value[0]) + wol_flags = NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE; opts = g_strsplit_set (value, ";", 0); for (iter = (const char **) opts; iter[0]; iter++) { /* in case of repeated wol_passwords, parse_ethtool_option() * will do the right thing and clear wol_password before resetting. */ - parse_ethtool_option (iter[0], &wol_flags, &wol_password); + parse_ethtool_option (iter[0], &wol_flags, &wol_password, &autoneg, &speed, &duplex); } } + /* ETHTOOL_WAKE_ON_LAN = ignore overrides WoL settings in ETHTOOL_OPTS */ + wol_value = svGetValueString (ifcfg, "ETHTOOL_WAKE_ON_LAN"); + if (wol_value) { + if (strcmp (wol_value, "ignore") == 0) + wol_flags = NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE; + else + PARSE_WARNING ("invalid ETHTOOL_WAKE_ON_LAN value '%s'", wol_value); + } + if ( wol_password && !NM_FLAGS_HAS (wol_flags, NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC)) { PARSE_WARNING ("Wake-on-LAN password not expected"); ignore_wol_password = TRUE; } + g_object_set (s_wired, NM_SETTING_WIRED_WAKE_ON_LAN, wol_flags, NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD, ignore_wol_password ? NULL : wol_password, + NM_SETTING_WIRED_AUTO_NEGOTIATE, autoneg, + NM_SETTING_WIRED_SPEED, autoneg ? 0 : speed, + NM_SETTING_WIRED_DUPLEX, autoneg ? NULL : duplex, NULL); } diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index 1696e1ad43..22454fb347 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -1008,11 +1008,12 @@ write_wired_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) NMSettingWired *s_wired; const char *device_mac, *cloned_mac; char *tmp; - const char *nettype, *portname, *ctcprot, *s390_key, *s390_val; - guint32 mtu, num_opts, i; + const char *nettype, *portname, *ctcprot, *s390_key, *s390_val, *duplex; + guint32 mtu, num_opts, speed, i; const char *const *s390_subchannels; - GString *str; + GString *str = NULL; const char * const *macaddr_blacklist; + gboolean auto_negotiate; NMSettingWiredWakeOnLan wol; const char *wol_password; @@ -1101,14 +1102,44 @@ write_wired_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) g_string_free (str, TRUE); } + /* Stuff ETHTOOL_OPT with required options */ + str = NULL; + auto_negotiate = nm_setting_wired_get_auto_negotiate (s_wired); + /* autoneg off + speed 0 + duplex NULL, means we want NM + * to skip link configuration which is default. So write + * down link config only if we have auto-negotiate true or + * a valid value for one among speed and duplex. + */ + if (auto_negotiate) { + str = g_string_sized_new (64); + g_string_printf (str, "autoneg on"); + } else { + speed = nm_setting_wired_get_speed (s_wired); + duplex = nm_setting_wired_get_duplex (s_wired); + if (speed || duplex) { + str = g_string_sized_new (64); + g_string_printf (str, "autoneg off"); + if (speed) + g_string_append_printf (str, " speed %u", speed); + if (duplex) + g_string_append_printf (str, " duplex %s", duplex); + } + } + wol = nm_setting_wired_get_wake_on_lan (s_wired); wol_password = nm_setting_wired_get_wake_on_lan_password (s_wired); + if (wol == NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE) - svSetValue (ifcfg, "ETHTOOL_OPTS", ""); - else if (wol == NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT) - svUnsetValue (ifcfg, "ETHTOOL_OPTS"); - else { - str = g_string_sized_new (30); + svSetValue (ifcfg, "ETHTOOL_WAKE_ON_LAN", "ignore"); + else if (wol == NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT) { + if (!str) + svUnsetValue (ifcfg, "ETHTOOL_OPTS"); + } else { + if (!str) + str = g_string_sized_new (30); + else + g_string_append (str, " "); + g_string_append (str, "wol "); if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_PHY)) @@ -1129,10 +1160,12 @@ write_wired_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) if (wol_password && NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC)) g_string_append_printf (str, "s sopass %s", wol_password); - + } + if (str) { svSetValueString (ifcfg, "ETHTOOL_OPTS", str->str); g_string_free (str, TRUE); } + /* End ETHTOOL_OPT stuffing */ svSetValueString (ifcfg, "TYPE", TYPE_ETHERNET); -- cgit v1.2.1