summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrancesco Giudici <fgiudici@redhat.com>2016-11-22 15:28:23 +0100
committerFrancesco Giudici <fgiudici@redhat.com>2016-11-22 15:28:23 +0100
commite0c50a970378daf8f066c293c613276d322cc056 (patch)
tree673bb570c846529b201979087e66494d4343cff6
parent7b16b28a628c291a97a2d638a179fbc6a152d568 (diff)
parentd5a743a619f79086e5a85510b49925d5d34bfc2d (diff)
merge: branch 'fg/802-3-prop_rh1353612_II'
https://bugzilla.redhat.com/show_bug.cgi?id=1353612
-rw-r--r--Makefile.am2
-rw-r--r--clients/cli/settings.c51
-rw-r--r--libnm-core/nm-connection.c25
-rw-r--r--libnm-core/nm-setting-wired.c60
-rw-r--r--src/NetworkManager.ver-orig3
-rw-r--r--src/devices/nm-device-ethernet.c133
-rw-r--r--src/platform/nm-platform-utils.c85
-rw-r--r--src/platform/nm-platform-utils.h3
-rw-r--r--src/platform/nm-platform.c33
-rw-r--r--src/platform/nm-platform.h9
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c223
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c51
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-auto-negotiate-on22
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-unknown-ethtool-opt22
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c150
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);