diff options
author | Francesco Giudici <fgiudici@redhat.com> | 2016-11-22 15:28:23 +0100 |
---|---|---|
committer | Francesco Giudici <fgiudici@redhat.com> | 2016-11-22 15:28:23 +0100 |
commit | e0c50a970378daf8f066c293c613276d322cc056 (patch) | |
tree | 673bb570c846529b201979087e66494d4343cff6 | |
parent | 7b16b28a628c291a97a2d638a179fbc6a152d568 (diff) | |
parent | d5a743a619f79086e5a85510b49925d5d34bfc2d (diff) |
merge: branch 'fg/802-3-prop_rh1353612_II'
https://bugzilla.redhat.com/show_bug.cgi?id=1353612
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | clients/cli/settings.c | 51 | ||||
-rw-r--r-- | libnm-core/nm-connection.c | 25 | ||||
-rw-r--r-- | libnm-core/nm-setting-wired.c | 60 | ||||
-rw-r--r-- | src/NetworkManager.ver-orig | 3 | ||||
-rw-r--r-- | src/devices/nm-device-ethernet.c | 133 | ||||
-rw-r--r-- | src/platform/nm-platform-utils.c | 85 | ||||
-rw-r--r-- | src/platform/nm-platform-utils.h | 3 | ||||
-rw-r--r-- | src/platform/nm-platform.c | 33 | ||||
-rw-r--r-- | src/platform/nm-platform.h | 9 | ||||
-rw-r--r-- | src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c | 223 | ||||
-rw-r--r-- | src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c | 51 | ||||
-rw-r--r-- | src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-auto-negotiate-on | 22 | ||||
-rw-r--r-- | src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-unknown-ethtool-opt | 22 | ||||
-rw-r--r-- | src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c | 150 |
15 files changed, 718 insertions, 154 deletions
diff --git a/Makefile.am b/Makefile.am index 06d4e2ae58..edd5fca5dc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1971,6 +1971,8 @@ EXTRA_DIST += \ src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-trailing-spaces \ src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dns-options \ src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-wake-on-lan \ + src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-auto-negotiate-on \ + src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-unknown-ethtool-opt \ src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv6-only-1 \ src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-write-unknown-1 \ src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-write-unknown-1.expected \ diff --git a/clients/cli/settings.c b/clients/cli/settings.c index 89d779798d..875d435815 100644 --- a/clients/cli/settings.c +++ b/clients/cli/settings.c @@ -1800,8 +1800,6 @@ DEFINE_GETTER (nmc_property_wimax_get_mac_address, NM_SETTING_WIMAX_MAC_ADDRESS) /* --- NM_SETTING_WIRED_SETTING_NAME property get functions --- */ DEFINE_GETTER (nmc_property_wired_get_port, NM_SETTING_WIRED_PORT) -DEFINE_GETTER (nmc_property_wired_get_speed, NM_SETTING_WIRED_SPEED) -DEFINE_GETTER (nmc_property_wired_get_duplex, NM_SETTING_WIRED_DUPLEX) DEFINE_GETTER (nmc_property_wired_get_auto_negotiate, NM_SETTING_WIRED_AUTO_NEGOTIATE) DEFINE_GETTER (nmc_property_wired_get_mac_address, NM_SETTING_WIRED_MAC_ADDRESS) DEFINE_GETTER (nmc_property_wired_get_cloned_mac_address, NM_SETTING_WIRED_CLONED_MAC_ADDRESS) @@ -1813,6 +1811,30 @@ DEFINE_GETTER (nmc_property_wired_get_s390_options, NM_SETTING_WIRED_S390_OPTION DEFINE_GETTER (nmc_property_wired_get_wake_on_lan_password, NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD) static char * +nmc_property_wired_get_speed (NMSetting *setting, NmcPropertyGetType get_type) +{ + NMSettingWired *s_wired = NM_SETTING_WIRED (setting); + guint32 speed; + + speed = nm_setting_wired_get_speed (s_wired); + return g_strdup_printf ("%d", speed); +} + +static char * +nmc_property_wired_get_duplex (NMSetting *setting, NmcPropertyGetType get_type) +{ + NMSettingWired *s_wired = NM_SETTING_WIRED (setting); + const char *str; + + str = nm_setting_wired_get_duplex (s_wired); + if (!str) + return NULL; + else + return g_strdup (str); + +} + +static char * nmc_property_wired_get_mtu (NMSetting *setting, NmcPropertyGetType get_type) { NMSettingWired *s_wired = NM_SETTING_WIRED (setting); @@ -4996,10 +5018,10 @@ DEFINE_REMOVER_OPTION (nmc_property_vpn_remove_option_secret, /* --- NM_SETTING_WIRED_SETTING_NAME property setter functions --- */ #if 0 -/* - * Do not allow setting 'port' and 'duplex' for now. They are not implemented in - * NM core, nor in ifcfg-rh plugin. Enable this when it gets done. - */ +-/* +- * Do not allow setting 'port' for now. It is not implemented in +- * NM core, nor in ifcfg-rh plugin. Enable this when it gets done. +- */ /* 'port' */ static const char *wired_valid_ports[] = { "tp", "aui", "bnc", "mii", NULL }; @@ -5010,6 +5032,7 @@ nmc_property_wired_set_port (NMSetting *setting, const char *prop, const char *v } DEFINE_ALLOWED_VAL_FUNC (nmc_property_wired_allowed_port, wired_valid_ports) +#endif /* 'duplex' */ static const char *wired_valid_duplexes[] = { "half", "full", NULL }; @@ -5021,7 +5044,7 @@ nmc_property_wired_set_duplex (NMSetting *setting, const char *prop, const char } DEFINE_ALLOWED_VAL_FUNC (nmc_property_wired_allowed_duplex, wired_valid_duplexes) -#endif + /* 'mac-address-blacklist' */ DEFINE_SETTER_MAC_BLACKLIST (nmc_property_wired_set_mac_address_blacklist, @@ -7310,28 +7333,28 @@ nmc_properties_init (void) /* Add editable properties for NM_SETTING_WIRED_SETTING_NAME */ nmc_add_prop_funcs (GLUE (WIRED, PORT), nmc_property_wired_get_port, - NULL, /*nmc_property_wired_set_port,*/ + NULL, /* nmc_property_wired_set_port, */ NULL, NULL, - NULL, /*nmc_property_wired_allowed_port,*/ + NULL, /* nmc_property_wired_allowed_port, */ NULL); nmc_add_prop_funcs (GLUE (WIRED, SPEED), nmc_property_wired_get_speed, - NULL, + nmc_property_set_uint, NULL, NULL, NULL, NULL); nmc_add_prop_funcs (GLUE (WIRED, DUPLEX), nmc_property_wired_get_duplex, - NULL, /*nmc_property_wired_set_duplex,*/ - NULL, + nmc_property_wired_set_duplex, NULL, NULL, - NULL); /*nmc_property_wired_allowed_duplex);*/ + nmc_property_wired_allowed_duplex, + NULL); nmc_add_prop_funcs (GLUE (WIRED, AUTO_NEGOTIATE), nmc_property_wired_get_auto_negotiate, - NULL, + nmc_property_set_bool, NULL, NULL, NULL, diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c index b7bca4f90f..7bb7d4d9d0 100644 --- a/libnm-core/nm-connection.c +++ b/libnm-core/nm-connection.c @@ -718,6 +718,30 @@ _normalize_connection_slave_type (NMConnection *self) } static gboolean +_normalize_ethernet_link_neg (NMConnection *self) +{ + NMSettingWired *s_wired = nm_connection_get_setting_wired (self); + + if (s_wired) { + gboolean autoneg = nm_setting_wired_get_auto_negotiate (s_wired); + guint32 speed = nm_setting_wired_get_speed (s_wired); + const char *duplex = nm_setting_wired_get_duplex (s_wired); + + if (autoneg && (speed || duplex)) { + speed = 0; + duplex = NULL; + g_object_set (s_wired, + NM_SETTING_WIRED_SPEED, (guint) speed, + NM_SETTING_WIRED_DUPLEX, duplex, + NULL); + return TRUE; + } + } + + return FALSE; +} + +static gboolean _normalize_ip_config (NMConnection *self, GHashTable *parameters) { NMSettingConnection *s_con = nm_connection_get_setting_connection (self); @@ -1207,6 +1231,7 @@ nm_connection_normalize (NMConnection *connection, was_modified |= _normalize_connection_uuid (connection); was_modified |= _normalize_connection_type (connection); was_modified |= _normalize_connection_slave_type (connection); + was_modified |= _normalize_ethernet_link_neg (connection); was_modified |= _normalize_ip_config (connection, parameters); was_modified |= _normalize_infiniband_mtu (connection, parameters); was_modified |= _normalize_bond_mode (connection, parameters); diff --git a/libnm-core/nm-setting-wired.c b/libnm-core/nm-setting-wired.c index b27643d9a1..b070f2f6b8 100644 --- a/libnm-core/nm-setting-wired.c +++ b/libnm-core/nm-setting-wired.c @@ -618,15 +618,12 @@ static gboolean verify (NMSetting *setting, NMConnection *connection, GError **error) { NMSettingWiredPrivate *priv = NM_SETTING_WIRED_GET_PRIVATE (setting); - const char *valid_ports[] = { "tp", "aui", "bnc", "mii", NULL }; - const char *valid_duplex[] = { "half", "full", NULL }; - const char *valid_nettype[] = { "qeth", "lcs", "ctc", NULL }; GHashTableIter iter; const char *key, *value; int i; GError *local = NULL; - if (priv->port && !g_strv_contains (valid_ports, priv->port)) { + if (!NM_IN_STRSET (priv->port, NULL, "tp", "aui", "bnc", "mii")) { g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, @@ -636,7 +633,7 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) return FALSE; } - if (priv->duplex && !g_strv_contains (valid_duplex, priv->duplex)) { + if (!NM_IN_STRSET (priv->duplex, NULL, "half", "full")) { g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, @@ -682,7 +679,7 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) } } - if (priv->s390_nettype && !g_strv_contains (valid_nettype, priv->s390_nettype)) { + if (!NM_IN_STRSET (priv->s390_nettype, NULL, "qeth", "lcs", "ctc")) { g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, @@ -759,6 +756,27 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) return FALSE; } + /* Normalizable errors */ + + if (priv->auto_negotiate) { + if (priv->duplex) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("when link autonegotiation is enabled no duplex value is accepted")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_DUPLEX); + return NM_SETTING_VERIFY_NORMALIZABLE_ERROR; + } + if (priv->speed) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("when link autonegotiation is enabled speed should be 0")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_SPEED); + return NM_SETTING_VERIFY_NORMALIZABLE_ERROR; + } + } + return TRUE; } @@ -779,6 +797,12 @@ compare_property (NMSetting *setting, return parent_class->compare_property (setting, other, prop_spec, flags); } +static GVariant * +_override_autoneg_get (NMSetting *setting, const char *property) +{ + return g_variant_new_boolean (nm_setting_wired_get_auto_negotiate ((NMSettingWired *) setting)); +} + /*****************************************************************************/ static void @@ -1001,8 +1025,9 @@ nm_setting_wired_class_init (NMSettingWiredClass *setting_wired_class) **/ /* ---ifcfg-rh--- * property: speed - * variable: (none) - * description: The property is not saved by the plugin. + * variable: ETHTOOL_OPTS + * description: Fixed speed for the ethernet link. It is added as "speed" + * parameter in the ETHTOOL_OPTS variable. * ---end--- */ g_object_class_install_property @@ -1021,8 +1046,9 @@ nm_setting_wired_class_init (NMSettingWiredClass *setting_wired_class) **/ /* ---ifcfg-rh--- * property: duplex - * variable: (none) - * description: The property is not saved by the plugin. + * variable: ETHTOOL_OPTS + * description: Fixed duplex mode for the ethernet link. It is added as + * "duplex" parameter in the ETHOOL_OPTS variable. * ---end--- */ g_object_class_install_property @@ -1041,17 +1067,25 @@ nm_setting_wired_class_init (NMSettingWiredClass *setting_wired_class) **/ /* ---ifcfg-rh--- * property: auto-negotiate - * variable: (none) - * description: The property is not saved by the plugin. + * variable: ETHTOOL_OPTS + * description: Whether link speed and duplex autonegotiation is enabled. + * It is not saved only if disabled and no values are provided for the + * "speed" and "duplex" parameters (skips link configuration). * ---end--- */ g_object_class_install_property (object_class, PROP_AUTO_NEGOTIATE, g_param_spec_boolean (NM_SETTING_WIRED_AUTO_NEGOTIATE, "", "", - TRUE, + FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); + _nm_setting_class_override_property (setting_class, + NM_SETTING_WIRED_AUTO_NEGOTIATE, + G_VARIANT_TYPE_BOOLEAN, + _override_autoneg_get, + NULL, + NULL); /** * NMSettingWired:mac-address: 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/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index c3baf79510..313dbc8730 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -782,6 +782,84 @@ supplicant_interface_init (NMDeviceEthernet *self) return TRUE; } +NM_UTILS_LOOKUP_STR_DEFINE_STATIC (link_duplex_to_string, NMPlatformLinkDuplexType, + NM_UTILS_LOOKUP_DEFAULT_WARN (NULL), + NM_UTILS_LOOKUP_STR_ITEM (NM_PLATFORM_LINK_DUPLEX_UNKNOWN, "unknown"), + NM_UTILS_LOOKUP_STR_ITEM (NM_PLATFORM_LINK_DUPLEX_FULL, "full"), + NM_UTILS_LOOKUP_STR_ITEM (NM_PLATFORM_LINK_DUPLEX_HALF, "half"), +); + +static NMPlatformLinkDuplexType +link_duplex_to_platform (const char *duplex) +{ + if (!duplex) + return NM_PLATFORM_LINK_DUPLEX_UNKNOWN; + if (nm_streq (duplex, "full")) + return NM_PLATFORM_LINK_DUPLEX_FULL; + if (nm_streq (duplex, "half")) + return NM_PLATFORM_LINK_DUPLEX_HALF; + g_return_val_if_reached (NM_PLATFORM_LINK_DUPLEX_UNKNOWN); +} + +static void +link_negotiation_set (NMDevice *device) +{ + NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device); + NMSettingWired *s_wired; + gboolean autoneg = TRUE; + gboolean link_autoneg; + NMPlatformLinkDuplexType duplex = NM_PLATFORM_LINK_DUPLEX_UNKNOWN; + NMPlatformLinkDuplexType link_duplex; + guint32 speed = 0; + guint32 link_speed; + + s_wired = (NMSettingWired *) nm_device_get_applied_setting (device, NM_TYPE_SETTING_WIRED); + if (s_wired) { + autoneg = nm_setting_wired_get_auto_negotiate (s_wired); + if (!autoneg) { + speed = nm_setting_wired_get_speed (s_wired); + duplex = link_duplex_to_platform (nm_setting_wired_get_duplex (s_wired)); + if (!speed && !duplex) { + _LOGD (LOGD_DEVICE, "set-link: ignore link negotiation"); + return; + } + } + } + + if (!nm_platform_ethtool_get_link_settings (NM_PLATFORM_GET, nm_device_get_iface (device), + &link_autoneg, &link_speed, &link_duplex)) { + _LOGW (LOGD_DEVICE, "set-link: unable to retrieve link negotiation"); + return; + } + + /* If link negotiation setting are already in place do nothing and return with success */ + if ( (!!autoneg == !!link_autoneg) + && (!speed || (speed == link_speed)) + && (!duplex || (duplex == link_duplex))) { + _LOGD (LOGD_DEVICE, "set-link: link negotiation is already configured"); + return; + } + + if (autoneg) + _LOGD (LOGD_DEVICE, "set-link: configure autonegotiation"); + else { + _LOGD (LOGD_DEVICE, "set-link: configure static negotiation (%u Mbit%s - %s duplex%s)", + speed ?: link_speed, + speed ? "" : "*", + duplex ? link_duplex_to_string (duplex) : link_duplex_to_string (link_duplex), + duplex ? "" : "*"); + } + + if (!nm_platform_ethtool_set_link_settings (NM_PLATFORM_GET, + nm_device_get_iface (device), + autoneg, + speed, + duplex)) { + _LOGW (LOGD_DEVICE, "set-link: failure to set link negotiation"); + return; + } +} + static gboolean pppoe_reconnect_delay (gpointer user_data) { @@ -799,40 +877,41 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) { NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev); NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); - NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; + NMActStageReturn ret; g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); ret = NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->act_stage1_prepare (dev, reason); - if (ret == NM_ACT_STAGE_RETURN_SUCCESS) { - if (!nm_device_hw_addr_set_cloned (dev, nm_device_get_applied_connection (dev), FALSE)) - ret = NM_ACT_STAGE_RETURN_FAILURE; - } + if (ret != NM_ACT_STAGE_RETURN_SUCCESS) + return ret; - if (ret == NM_ACT_STAGE_RETURN_SUCCESS) { - /* If we're re-activating a PPPoE connection a short while after - * a previous PPPoE connection was torn down, wait a bit to allow the - * remote side to handle the disconnection. Otherwise the peer may - * get confused and fail to negotiate the new connection. (rh #1023503) - */ - if (priv->last_pppoe_time) { - gint32 delay = nm_utils_get_monotonic_timestamp_s () - priv->last_pppoe_time; - - if ( delay < PPPOE_RECONNECT_DELAY - && nm_device_get_applied_setting (dev, NM_TYPE_SETTING_PPPOE)) { - _LOGI (LOGD_DEVICE, "delaying PPPoE reconnect for %d seconds to ensure peer is ready...", - delay); - g_assert (!priv->pppoe_wait_id); - priv->pppoe_wait_id = g_timeout_add_seconds (delay, - pppoe_reconnect_delay, - self); - ret = NM_ACT_STAGE_RETURN_POSTPONE; - } else - priv->last_pppoe_time = 0; + link_negotiation_set (dev); + + if (!nm_device_hw_addr_set_cloned (dev, nm_device_get_applied_connection (dev), FALSE)) + return NM_ACT_STAGE_RETURN_FAILURE; + + /* If we're re-activating a PPPoE connection a short while after + * a previous PPPoE connection was torn down, wait a bit to allow the + * remote side to handle the disconnection. Otherwise the peer may + * get confused and fail to negotiate the new connection. (rh #1023503) + */ + if (priv->last_pppoe_time) { + gint32 delay = nm_utils_get_monotonic_timestamp_s () - priv->last_pppoe_time; + + if ( delay < PPPOE_RECONNECT_DELAY + && nm_device_get_applied_setting (dev, NM_TYPE_SETTING_PPPOE)) { + _LOGI (LOGD_DEVICE, "delaying PPPoE reconnect for %d seconds to ensure peer is ready...", + delay); + g_assert (!priv->pppoe_wait_id); + priv->pppoe_wait_id = g_timeout_add_seconds (delay, + pppoe_reconnect_delay, + self); + return NM_ACT_STAGE_RETURN_POSTPONE; } + priv->last_pppoe_time = 0; } - return ret; + return NM_ACT_STAGE_RETURN_SUCCESS; } static NMActStageReturn @@ -1522,7 +1601,7 @@ get_link_speed (NMDevice *device) NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); guint32 speed; - if (!nm_platform_ethtool_get_link_speed (NM_PLATFORM_GET, nm_device_get_iface (device), &speed)) + if (!nm_platform_ethtool_get_link_settings (NM_PLATFORM_GET, nm_device_get_iface (device), NULL, &speed, NULL)) return; if (priv->speed == speed) return; diff --git a/src/platform/nm-platform-utils.c b/src/platform/nm-platform-utils.c index f3983d3d74..9ef0707d58 100644 --- a/src/platform/nm-platform-utils.c +++ b/src/platform/nm-platform-utils.c @@ -40,6 +40,13 @@ /****************************************************************** * ethtool ******************************************************************/ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) +#define ethtool_cmd_speed(pedata) ((pedata)->speed) + +#define ethtool_cmd_speed_set(pedata, speed) \ + G_STMT_START { (pedata)->speed = (guint16) (speed); } G_STMT_END +#endif + static gboolean ethtool_get (const char *name, gpointer edata) @@ -261,30 +268,88 @@ nmp_utils_ethtool_get_wake_on_lan (const char *ifname) } gboolean -nmp_utils_ethtool_get_link_speed (const char *ifname, guint32 *out_speed) +nmp_utils_ethtool_get_link_settings (const char *ifname, + gboolean *out_autoneg, + guint32 *out_speed, + NMPlatformLinkDuplexType *out_duplex) { struct ethtool_cmd edata = { .cmd = ETHTOOL_GSET, }; - guint32 speed; if (!ethtool_get (ifname, &edata)) return FALSE; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) - speed = edata.speed; -#else - speed = ethtool_cmd_speed (&edata); -#endif - if (speed == G_MAXUINT16 || speed == G_MAXUINT32) - speed = 0; + if (out_autoneg) + *out_autoneg = (edata.autoneg == AUTONEG_ENABLE); + + if (out_speed) { + guint32 speed; + + speed = ethtool_cmd_speed (&edata); + if (speed == G_MAXUINT16 || speed == G_MAXUINT32) + speed = 0; - if (out_speed) *out_speed = speed; + } + + if (out_duplex) { + switch (edata.duplex) { + case DUPLEX_HALF: + *out_duplex = NM_PLATFORM_LINK_DUPLEX_HALF; + break; + case DUPLEX_FULL: + *out_duplex = NM_PLATFORM_LINK_DUPLEX_FULL; + break; + default: /* DUPLEX_UNKNOWN */ + *out_duplex = NM_PLATFORM_LINK_DUPLEX_UNKNOWN; + break; + } + } + return TRUE; } gboolean +nmp_utils_ethtool_set_link_settings (const char *ifname, gboolean autoneg, guint32 speed, NMPlatformLinkDuplexType duplex) +{ + struct ethtool_cmd edata = { + .cmd = ETHTOOL_GSET, + }; + + /* retrieve first current settings */ + if (!ethtool_get (ifname, &edata)) + return FALSE; + + /* then change the needed ones */ + edata.cmd = ETHTOOL_SSET; + if (autoneg) { + edata.autoneg = AUTONEG_ENABLE; + edata.advertising = edata.supported; + } else { + edata.autoneg = AUTONEG_DISABLE; + + if (speed) + ethtool_cmd_speed_set (&edata, speed); + + switch (duplex) { + case NM_PLATFORM_LINK_DUPLEX_HALF: + edata.duplex = DUPLEX_HALF; + break; + case NM_PLATFORM_LINK_DUPLEX_FULL: + edata.duplex = DUPLEX_FULL; + break; + case NM_PLATFORM_LINK_DUPLEX_UNKNOWN: + break; + default: + g_return_val_if_reached (FALSE); + } + } + + return ethtool_get (ifname, &edata); +} + +gboolean nmp_utils_ethtool_set_wake_on_lan (const char *ifname, NMSettingWiredWakeOnLan wol, const char *wol_password) diff --git a/src/platform/nm-platform-utils.h b/src/platform/nm-platform-utils.h index 456c08652d..4b4868c1e8 100644 --- a/src/platform/nm-platform-utils.h +++ b/src/platform/nm-platform-utils.h @@ -35,7 +35,8 @@ gboolean nmp_utils_ethtool_get_wake_on_lan (const char *ifname); gboolean nmp_utils_ethtool_set_wake_on_lan (const char *ifname, NMSettingWiredWakeOnLan wol, const char *wol_password); -gboolean nmp_utils_ethtool_get_link_speed (const char *ifname, guint32 *out_speed); +gboolean nmp_utils_ethtool_get_link_settings (const char *ifname, gboolean *out_autoneg, guint32 *out_speed, NMPlatformLinkDuplexType *out_duplex); +gboolean nmp_utils_ethtool_set_link_settings (const char *ifname, gboolean autoneg, guint32 speed, NMPlatformLinkDuplexType duplex); gboolean nmp_utils_ethtool_get_driver_info (const char *ifname, char **out_driver_name, diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 0b1d25d302..e3ec8e03cb 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -134,6 +134,17 @@ NM_DEFINE_SINGLETON_REGISTER (NMPlatform); (void) klass; \ } while (0) +#define _CHECK_SELF_NETNS(self, klass, netns, err_val) \ + nm_auto_pop_netns NMPNetns *netns = NULL; \ + NMPlatformClass *klass; \ + do { \ + g_return_val_if_fail (NM_IS_PLATFORM (self), err_val); \ + klass = NM_PLATFORM_GET_CLASS (self); \ + (void) klass; \ + if (!nm_platform_netns_push (self, &netns)) \ + return (err_val); \ + } while (0) + /** * nm_platform_setup: * @instance: the #NMPlatform instance @@ -2470,25 +2481,25 @@ _to_string_ifa_flags (guint32 ifa_flags, char *buf, gsize size) gboolean nm_platform_ethtool_set_wake_on_lan (NMPlatform *self, const char *ifname, NMSettingWiredWakeOnLan wol, const char *wol_password) { - nm_auto_pop_netns NMPNetns *netns = NULL; - _CHECK_SELF (self, klass, FALSE); - - if (!nm_platform_netns_push (self, &netns)) - return FALSE; + _CHECK_SELF_NETNS (self, klass, netns, FALSE); return nmp_utils_ethtool_set_wake_on_lan (ifname, wol, wol_password); } gboolean -nm_platform_ethtool_get_link_speed (NMPlatform *self, const char *ifname, guint32 *out_speed) +nm_platform_ethtool_set_link_settings (NMPlatform *self, const char *ifname, gboolean autoneg, guint32 speed, NMPlatformLinkDuplexType duplex) { - nm_auto_pop_netns NMPNetns *netns = NULL; - _CHECK_SELF (self, klass, FALSE); + _CHECK_SELF_NETNS (self, klass, netns, FALSE); - if (!nm_platform_netns_push (self, &netns)) - return FALSE; + return nmp_utils_ethtool_set_link_settings (ifname, autoneg, speed, duplex); +} + +gboolean +nm_platform_ethtool_get_link_settings (NMPlatform *self, const char *ifname, gboolean *out_autoneg, guint32 *out_speed, NMPlatformLinkDuplexType *out_duplex) +{ + _CHECK_SELF_NETNS (self, klass, netns, FALSE); - return nmp_utils_ethtool_get_link_speed (ifname, out_speed); + return nmp_utils_ethtool_get_link_settings (ifname, out_autoneg, out_speed, out_duplex); } /*****************************************************************************/ diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 1773586937..a546e4eaec 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -481,6 +481,12 @@ typedef struct { bool multi_queue:1; } NMPlatformTunProperties; +typedef enum { + NM_PLATFORM_LINK_DUPLEX_UNKNOWN, + NM_PLATFORM_LINK_DUPLEX_HALF, + NM_PLATFORM_LINK_DUPLEX_FULL, +} NMPlatformLinkDuplexType; + /*****************************************************************************/ struct _NMPlatformPrivate; @@ -975,6 +981,7 @@ const char *nm_platform_route_scope2str (int scope, char *buf, gsize len); int nm_platform_ip_address_cmp_expiry (const NMPlatformIPAddress *a, const NMPlatformIPAddress *b); gboolean nm_platform_ethtool_set_wake_on_lan (NMPlatform *self, const char *ifname, NMSettingWiredWakeOnLan wol, const char *wol_password); -gboolean nm_platform_ethtool_get_link_speed (NMPlatform *self, const char *ifname, guint32 *out_speed); +gboolean nm_platform_ethtool_set_link_settings (NMPlatform *self, const char *ifname, gboolean autoneg, guint32 speed, NMPlatformLinkDuplexType duplex); +gboolean nm_platform_ethtool_get_link_settings (NMPlatform *self, const char *ifname, gboolean *out_autoneg, guint32 *out_speed, NMPlatformLinkDuplexType *out_duplex); #endif /* __NETWORKMANAGER_PLATFORM_H__ */ 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 b48da212f7..843bad1c62 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -3656,10 +3656,120 @@ wireless_connection_from_ifcfg (const char *file, } static void -parse_ethtool_option (const char *value, NMSettingWiredWakeOnLan *out_flags, char **out_password) +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) +{ + NMSettingWiredWakeOnLan wol_flags = NM_SETTING_WIRED_WAKE_ON_LAN_NONE; + + if (!value) { + PARSE_WARNING ("Wake-on-LAN options missing"); + return; + } + + for (; *value; value++) { + switch (*value) { + case 'p': + wol_flags |= NM_SETTING_WIRED_WAKE_ON_LAN_PHY; + break; + case 'u': + wol_flags |= NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST; + break; + case 'm': + wol_flags |= NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST; + break; + case 'b': + wol_flags |= NM_SETTING_WIRED_WAKE_ON_LAN_BROADCAST; + break; + case 'a': + wol_flags |= NM_SETTING_WIRED_WAKE_ON_LAN_ARP; + break; + case 'g': + wol_flags |= NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC; + break; + case 's': + break; + case 'd': + wol_flags = NM_SETTING_WIRED_WAKE_ON_LAN_NONE; + break; + default: + PARSE_WARNING ("unrecognized Wake-on-LAN option '%c'", *value); + } + } + + *out_flags = wol_flags; +} + +static void parse_ethtool_option_sopass (const char *value, char **out_password) +{ + if (!value) { + PARSE_WARNING ("Wake-on-LAN password missing"); + return; + } + + g_clear_pointer (out_password, g_free); + if (!nm_utils_hwaddr_valid (value, ETH_ALEN)) { + PARSE_WARNING ("Wake-on-LAN password '%s' is invalid", value); + return; + } + + *out_password = g_strdup (value); +} + +static void +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, *flag; + const char **iter = NULL, *opt_val, *opt; if (!value || !value[0]) return; @@ -3668,77 +3778,37 @@ parse_ethtool_option (const char *value, NMSettingWiredWakeOnLan *out_flags, cha iter = (const char **) words; while (iter[0]) { - gboolean is_wol; - - if (g_str_equal (iter[0], "wol")) - is_wol = TRUE; - else if (g_str_equal (iter[0], "sopass")) - is_wol = FALSE; - else { - /* Silently skip unknown options */ + /* g_strsplit_set() returns empty tokens when extra spaces are found: skip them */ + if (!*iter[0]) { iter++; continue; } - iter++; + opt = iter++[0]; - /* g_strsplit_set() returns empty tokens, meaning that we must skip over repeated - * space characters like to parse "wol d". */ + /* skip over repeated space characters like to parse "wol d". */ while (iter[0] && !*iter[0]) iter++; - if (is_wol) { - NMSettingWiredWakeOnLan wol_flags = NM_SETTING_WIRED_WAKE_ON_LAN_NONE; - - if (!iter[0]) { - PARSE_WARNING ("Wake-on-LAN options missing"); - break; - } - - for (flag = iter[0]; *flag; flag++) { - switch (*flag) { - case 'p': - wol_flags |= NM_SETTING_WIRED_WAKE_ON_LAN_PHY; - break; - case 'u': - wol_flags |= NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST; - break; - case 'm': - wol_flags |= NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST; - break; - case 'b': - wol_flags |= NM_SETTING_WIRED_WAKE_ON_LAN_BROADCAST; - break; - case 'a': - wol_flags |= NM_SETTING_WIRED_WAKE_ON_LAN_ARP; - break; - case 'g': - wol_flags |= NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC; - break; - case 's': - break; - case 'd': - wol_flags = NM_SETTING_WIRED_WAKE_ON_LAN_NONE; - break; - default: - PARSE_WARNING ("unrecognized Wake-on-LAN option '%c'", *flag); - } - } - - *out_flags = wol_flags; - } else { - if (!iter[0]) { - PARSE_WARNING ("Wake-on-LAN password missing"); - break; - } - - g_clear_pointer (out_password, g_free); - if (nm_utils_hwaddr_valid (iter[0], ETH_ALEN)) - *out_password = g_strdup (iter[0]); - else - PARSE_WARNING ("Wake-on-LAN password '%s' is invalid", iter[0]); + opt_val = iter[0]; + + 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); + else { + /* Silently skip unknown options */ + continue; } - iter++; + + if (iter[0]) + iter++; } } @@ -3746,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); diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-auto-negotiate-on b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-auto-negotiate-on new file mode 100644 index 0000000000..d0b50775a1 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-auto-negotiate-on @@ -0,0 +1,22 @@ +# Intel Corporation 82540EP Gigabit Ethernet Controller (Mobile) +TYPE=Ethernet +DEVICE=eth0 +HWADDR=00:11:22:33:44:ee +BOOTPROTO=none +ONBOOT=yes +USERCTL=yes +MTU=1492 +NM_CONTROLLED=yes +DNS1=4.2.2.1 +DNS2=4.2.2.2 +IPADDR=192.168.1.5 +NETMASK=255.255.255.0 +GATEWAY=192.168.1.1 +IPV6INIT=yes +IPV6_AUTOCONF=no +IPV6ADDR=dead:beaf::1 +IPV6ADDR_SECONDARIES="dead:beaf::2/56" +DNS3=1:2:3:4::a +DNS4=1:2:3:4::b +RES_OPTIONS= +ETHTOOL_OPTS="wol apgs sopass 00:11:22:33:44:55 autoneg on speed 100" diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-unknown-ethtool-opt b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-unknown-ethtool-opt new file mode 100644 index 0000000000..861dd41f24 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-unknown-ethtool-opt @@ -0,0 +1,22 @@ +# Intel Corporation 82540EP Gigabit Ethernet Controller (Mobile) +TYPE=Ethernet +DEVICE=eth0 +HWADDR=00:11:22:33:44:ee +BOOTPROTO=none +ONBOOT=yes +USERCTL=yes +MTU=1492 +NM_CONTROLLED=yes +DNS1=4.2.2.1 +DNS2=4.2.2.2 +IPADDR=192.168.1.5 +NETMASK=255.255.255.0 +GATEWAY=192.168.1.1 +IPV6INIT=yes +IPV6_AUTOCONF=no +IPV6ADDR=dead:beaf::1 +IPV6ADDR_SECONDARIES="dead:beaf::2/56" +DNS3=1:2:3:4::a +DNS4=1:2:3:4::b +RES_OPTIONS= +ETHTOOL_OPTS="unknown1 wol apgs sopass 00:11:22:33:44:55 unkwnown2 opt2 unknown3" diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index 6e974e1e59..a35a830b86 100644 --- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -2985,6 +2985,81 @@ test_read_wired_wake_on_lan (void) } static void +test_read_wired_auto_negotiate_off (void) +{ + gs_unref_object NMConnection *connection = NULL; + NMSettingConnection *s_con; + NMSettingWired *s_wired; + + connection = _connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-wake-on-lan", + NULL, TYPE_ETHERNET, NULL); + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_WIRED_SETTING_NAME); + + s_wired = nm_connection_get_setting_wired (connection); + g_assert (s_wired); + + 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"); +} + +static void +test_read_wired_auto_negotiate_on (void) +{ + gs_unref_object NMConnection *connection = NULL; + NMSettingConnection *s_con; + NMSettingWired *s_wired; + + connection = _connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-auto-negotiate-on", + NULL, TYPE_ETHERNET, NULL); + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_WIRED_SETTING_NAME); + + s_wired = nm_connection_get_setting_wired (connection); + g_assert (s_wired); + + g_assert (nm_setting_wired_get_auto_negotiate (s_wired)); + g_assert_cmpint (nm_setting_wired_get_speed (s_wired), ==, 0); + g_assert_cmpstr (nm_setting_wired_get_duplex (s_wired), ==, NULL); +} + +static void +test_read_wired_unknown_ethtool_opt (void) +{ + gs_unref_object NMConnection *connection = NULL; + NMSettingConnection *s_con; + NMSettingWired *s_wired; + + connection = _connection_from_file (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-unknown-ethtool-opt", + NULL, TYPE_ETHERNET, NULL); + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_WIRED_SETTING_NAME); + + s_wired = nm_connection_get_setting_wired (connection); + g_assert (s_wired); + + g_assert (!nm_setting_wired_get_auto_negotiate (s_wired)); + g_assert (!nm_setting_wired_get_speed (s_wired)); + g_assert (!nm_setting_wired_get_duplex (s_wired)); + + g_assert_cmpint (nm_setting_wired_get_wake_on_lan (s_wired), + ==, + NM_SETTING_WIRED_WAKE_ON_LAN_ARP | + NM_SETTING_WIRED_WAKE_ON_LAN_PHY | + NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC); + g_assert_cmpstr (nm_setting_wired_get_wake_on_lan_password (s_wired), + ==, + "00:11:22:33:44:55"); +} + +static void test_read_wifi_hidden (void) { NMConnection *connection; @@ -3198,6 +3273,76 @@ test_write_wired_wake_on_lan (void) } static void +test_write_wired_auto_negotiate_off (void) +{ + nmtst_auto_unlinkfile char *testfile = NULL; + gs_unref_object NMConnection *connection = NULL; + gs_unref_object NMConnection *reread = NULL; + NMSettingWired *s_wired; + char *val; + shvarFile *f; + + connection = nmtst_create_minimal_connection ("Test Write Wired Auto-Negotiate", NULL, NM_SETTING_WIRED_SETTING_NAME, NULL); + s_wired = nm_connection_get_setting_wired (connection); + g_object_set (s_wired, + NM_SETTING_WIRED_AUTO_NEGOTIATE, FALSE, + NM_SETTING_WIRED_DUPLEX, "half", + NM_SETTING_WIRED_SPEED, 10, + NULL); + + _writer_new_connection (connection, + TEST_SCRATCH_DIR "/network-scripts/", + &testfile); + + f = _svOpenFile (testfile); + val = svGetValueString (f, "ETHTOOL_OPTS"); + g_assert (val); + g_assert (strstr (val, "autoneg off")); + g_assert (strstr (val, "speed 10")); + g_assert (strstr (val, "duplex half")); + g_free (val); + svCloseFile (f); + + reread = _connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL); + + nmtst_assert_connection_equals (connection, TRUE, reread, FALSE); +} + +static void +test_write_wired_auto_negotiate_on (void) +{ + nmtst_auto_unlinkfile char *testfile = NULL; + gs_unref_object NMConnection *connection = NULL; + gs_unref_object NMConnection *reread = NULL; + NMSettingWired *s_wired; + char *val; + shvarFile *f; + + connection = nmtst_create_minimal_connection ("Test Write Wired Auto-Negotiate", NULL, NM_SETTING_WIRED_SETTING_NAME, NULL); + s_wired = nm_connection_get_setting_wired (connection); + g_object_set (s_wired, + NM_SETTING_WIRED_AUTO_NEGOTIATE, TRUE, + NULL); + + _writer_new_connection (connection, + TEST_SCRATCH_DIR "/network-scripts/", + &testfile); + + f = _svOpenFile (testfile); + val = svGetValueString (f, "ETHTOOL_OPTS"); + g_assert (val); + g_assert (strstr (val, "autoneg on")); + g_assert (!strstr (val, "speed")); + g_assert (!strstr (val, "duplex")); + g_free (val); + svCloseFile (f); + + reread = _connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL); + + nmtst_assert_connection_equals (connection, TRUE, reread, FALSE); +} + +static void test_read_wifi_band_a (void) { NMConnection *connection; @@ -8780,6 +8925,9 @@ int main (int argc, char **argv) g_test_add_func (TPATH "vlan/read/reorder-hdr-1", test_read_vlan_reorder_hdr_1); g_test_add_func (TPATH "vlan/read/reorder-hdr-2", test_read_vlan_reorder_hdr_2); g_test_add_func (TPATH "wired/read/read-wake-on-lan", test_read_wired_wake_on_lan); + g_test_add_func (TPATH "wired/read/read-auto-negotiate-off", test_read_wired_auto_negotiate_off); + g_test_add_func (TPATH "wired/read/read-auto-negotiate-on", test_read_wired_auto_negotiate_on); + g_test_add_func (TPATH "wired/read/unkwnown-ethtool-opt", test_read_wired_unknown_ethtool_opt); g_test_add_func (TPATH "wired/write/static", test_write_wired_static); g_test_add_func (TPATH "wired/write/static-ip6-only", test_write_wired_static_ip6_only); @@ -8799,6 +8947,8 @@ int main (int argc, char **argv) g_test_add_func (TPATH "wired/write-aliases", test_write_wired_aliases); g_test_add_func (TPATH "ipv4/write-static-addresses-GATEWAY", test_write_gateway); g_test_add_func (TPATH "wired/write-wake-on-lan", test_write_wired_wake_on_lan); + g_test_add_func (TPATH "wired/write-auto-negotiate-off", test_write_wired_auto_negotiate_off); + g_test_add_func (TPATH "wired/write-auto-negotiate-on", test_write_wired_auto_negotiate_on); g_test_add_func (TPATH "wifi/write/open", test_write_wifi_open); g_test_add_func (TPATH "wifi/write/open/hex-ssid", test_write_wifi_open_hex_ssid); g_test_add_func (TPATH "wifi/write/wep", test_write_wifi_wep); |