summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Zink <j.zink@pengutronix.de>2023-10-25 16:52:47 +0200
committerJohannes Zink <j.zink@pengutronix.de>2023-11-03 15:41:21 +0000
commit3165d9a2deeaa2d0cd5fcb827ee32ec36818078e (patch)
tree54764963dc7753ff0163d3d5ff8a5d7ae7e3162b
parent384241851265b91abf32d3d6d24c013454f3c4c3 (diff)
ethtool: introduce EEE support
Some Applications require to explicitly enable or disable EEE. Therefore introduce EEE (Energy Efficient Ethernet) support with: * ethtool.eee on/off Unit test case included. Signed-off-by: Johannes Zink <j.zink@pengutronix.de>
-rw-r--r--src/core/devices/nm-device.c91
-rw-r--r--src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c12
-rw-r--r--src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c2
-rw-r--r--src/libnm-base/nm-base.h13
-rw-r--r--src/libnm-base/nm-ethtool-base.c5
-rw-r--r--src/libnm-base/nm-ethtool-utils-base.h1
-rw-r--r--src/libnm-client-impl/libnm.ver1
-rw-r--r--src/libnm-client-public/nm-ethtool-utils.h1
-rw-r--r--src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in4
-rw-r--r--src/libnm-core-impl/nm-setting-ethtool.c15
-rw-r--r--src/libnm-core-impl/tests/test-setting.c74
-rw-r--r--src/libnm-core-public/nm-setting-ethtool.h3
-rw-r--r--src/libnm-platform/nm-platform-utils.c59
-rw-r--r--src/libnm-platform/nm-platform-utils.h4
-rw-r--r--src/libnm-platform/nm-platform.c20
-rw-r--r--src/libnm-platform/nm-platform.h4
-rw-r--r--src/libnm-platform/nmp-base.h4
-rw-r--r--src/libnmc-setting/nm-meta-setting-desc.c3
-rw-r--r--src/nmcli/gen-metadata-nm-settings-nmcli.c2
-rw-r--r--src/nmcli/gen-metadata-nm-settings-nmcli.xml.in3
20 files changed, 318 insertions, 3 deletions
diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c
index 8031bd5dd4..d0cb5990d4 100644
--- a/src/core/devices/nm-device.c
+++ b/src/core/devices/nm-device.c
@@ -305,6 +305,7 @@ typedef struct {
NMEthtoolRingState *ring;
NMEthtoolPauseState *pause;
NMEthtoolChannelsState *channels;
+ NMEthtoolEEEState *eee;
} EthtoolState;
typedef enum {
@@ -2723,6 +2724,25 @@ _ethtool_pause_reset(NMDevice *self, NMPlatform *platform, EthtoolState *ethtool
}
static void
+_ethtool_eee_reset(NMDevice *self, NMPlatform *platform, EthtoolState *ethtool_state)
+{
+ gs_free NMEthtoolEEEState *eee = NULL;
+
+ nm_assert(NM_IS_DEVICE(self));
+ nm_assert(NM_IS_PLATFORM(platform));
+ nm_assert(ethtool_state);
+
+ eee = g_steal_pointer(&ethtool_state->eee);
+ if (!eee)
+ return;
+
+ if (!nm_platform_ethtool_set_eee(platform, ethtool_state->ifindex, eee))
+ _LOGW(LOGD_DEVICE, "ethtool: failure resetting eee settings");
+ else
+ _LOGD(LOGD_DEVICE, "ethtool: eee settings successfully reset");
+}
+
+static void
_ethtool_pause_set(NMDevice *self,
NMPlatform *platform,
EthtoolState *ethtool_state,
@@ -2811,6 +2831,73 @@ _ethtool_pause_set(NMDevice *self,
}
static void
+_ethtool_eee_set(NMDevice *self,
+ NMPlatform *platform,
+ EthtoolState *ethtool_state,
+ NMSettingEthtool *s_ethtool)
+{
+ NMEthtoolEEEState eee_old;
+ NMEthtoolEEEState eee_new;
+ GHashTable *hash;
+ GHashTableIter iter;
+ const char *name;
+ GVariant *variant;
+ gboolean has_old = FALSE;
+ NMTernary eee = NM_TERNARY_DEFAULT;
+
+ nm_assert(NM_IS_DEVICE(self));
+ nm_assert(NM_IS_PLATFORM(platform));
+ nm_assert(NM_IS_SETTING_ETHTOOL(s_ethtool));
+ nm_assert(ethtool_state);
+ nm_assert(!ethtool_state->eee);
+
+ hash = _nm_setting_option_hash(NM_SETTING(s_ethtool), FALSE);
+ if (!hash)
+ return;
+
+ g_hash_table_iter_init(&iter, hash);
+ while (g_hash_table_iter_next(&iter, (gpointer *) &name, (gpointer *) &variant)) {
+ NMEthtoolID ethtool_id = nm_ethtool_id_get_by_name(name);
+
+ if (!nm_ethtool_id_is_eee(ethtool_id))
+ continue;
+
+ nm_assert(g_variant_is_of_type(variant, G_VARIANT_TYPE_BOOLEAN));
+
+ if (!has_old) {
+ if (!nm_platform_ethtool_get_link_eee(platform, ethtool_state->ifindex, &eee_old)) {
+ _LOGW(LOGD_DEVICE,
+ "ethtool: failure setting eee options (cannot read "
+ "existing setting)");
+ return;
+ }
+ has_old = TRUE;
+ }
+
+ if (ethtool_id == NM_ETHTOOL_ID_EEE_ENABLED)
+ eee = g_variant_get_boolean(variant);
+ else
+ nm_assert_not_reached();
+ }
+
+ if (!has_old)
+ return;
+
+ eee_new = eee_old;
+ if (eee != NM_TERNARY_DEFAULT)
+ eee_new.enabled = !!eee;
+
+ ethtool_state->eee = nm_memdup(&eee_old, sizeof(eee_old));
+
+ if (!nm_platform_ethtool_set_eee(platform, ethtool_state->ifindex, &eee_new)) {
+ _LOGW(LOGD_DEVICE, "ethtool: failure setting eee settings");
+ return;
+ }
+
+ _LOGD(LOGD_DEVICE, "ethtool: eee settings successfully set");
+}
+
+static void
_ethtool_state_reset(NMDevice *self)
{
NMPlatform *platform = nm_device_get_platform(self);
@@ -2825,6 +2912,7 @@ _ethtool_state_reset(NMDevice *self)
_ethtool_ring_reset(self, platform, ethtool_state);
_ethtool_pause_reset(self, platform, ethtool_state);
_ethtool_channels_reset(self, platform, ethtool_state);
+ _ethtool_eee_reset(self, platform, ethtool_state);
}
static void
@@ -2860,9 +2948,10 @@ _ethtool_state_set(NMDevice *self)
_ethtool_ring_set(self, platform, ethtool_state, s_ethtool);
_ethtool_pause_set(self, platform, ethtool_state, s_ethtool);
_ethtool_channels_set(self, platform, ethtool_state, s_ethtool);
+ _ethtool_eee_set(self, platform, ethtool_state, s_ethtool);
if (ethtool_state->features || ethtool_state->coalesce || ethtool_state->ring
- || ethtool_state->pause || ethtool_state->channels)
+ || ethtool_state->pause || ethtool_state->channels || ethtool_state->eee)
priv->ethtool_state = g_steal_pointer(&ethtool_state);
}
diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
index 516f2fd890..fae336b703 100644
--- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
+++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
@@ -1439,6 +1439,18 @@ write_ethtool_setting(NMConnection *connection, shvarFile *ifcfg, GError **error
}
}
+ is_first = TRUE;
+ for (ethtool_id = _NM_ETHTOOL_ID_EEE_FIRST; ethtool_id <= _NM_ETHTOOL_ID_EEE_LAST;
+ ethtool_id++) {
+ if (nm_setting_option_get_boolean(NM_SETTING(s_ethtool),
+ nm_ethtool_data[ethtool_id]->optname,
+ &b)) {
+ nm_sprintf_buf(prop_name, "ethtool.%s", nm_ethtool_data[ethtool_id]->optname);
+ set_error_unsupported(error, connection, prop_name, FALSE);
+ return FALSE;
+ }
+ }
+
if (!any_option) {
/* Write an empty dummy "-A" option without arguments. This is to
* ensure that the reader will create an (all default) NMSettingEthtool.
diff --git a/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
index ccfc6ff394..d4374eb5e6 100644
--- a/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
+++ b/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
@@ -3623,7 +3623,7 @@ test_roundtrip_ethtool(void)
optname = nm_ethtool_data[ethtool_id]->optname;
vtype = nm_ethtool_id_get_variant_type(ethtool_id);
- if (nm_ethtool_optname_is_channels(optname)) {
+ if (nm_ethtool_optname_is_channels(optname) || nm_ethtool_optname_is_eee(optname)) {
/* Not supported */
continue;
}
diff --git a/src/libnm-base/nm-base.h b/src/libnm-base/nm-base.h
index 88acbcc5b2..34944408ca 100644
--- a/src/libnm-base/nm-base.h
+++ b/src/libnm-base/nm-base.h
@@ -117,7 +117,11 @@ typedef enum {
NM_ETHTOOL_ID_PAUSE_TX,
_NM_ETHTOOL_ID_PAUSE_LAST = NM_ETHTOOL_ID_PAUSE_TX,
- _NM_ETHTOOL_ID_RING_FIRST = _NM_ETHTOOL_ID_PAUSE_LAST + 1,
+ _NM_ETHTOOL_ID_EEE_FIRST = _NM_ETHTOOL_ID_PAUSE_LAST + 1,
+ NM_ETHTOOL_ID_EEE_ENABLED = _NM_ETHTOOL_ID_EEE_FIRST,
+ _NM_ETHTOOL_ID_EEE_LAST = NM_ETHTOOL_ID_EEE_ENABLED,
+
+ _NM_ETHTOOL_ID_RING_FIRST = _NM_ETHTOOL_ID_EEE_LAST + 1,
NM_ETHTOOL_ID_RING_RX = _NM_ETHTOOL_ID_RING_FIRST,
NM_ETHTOOL_ID_RING_RX_JUMBO,
NM_ETHTOOL_ID_RING_RX_MINI,
@@ -153,6 +157,7 @@ typedef enum {
NM_ETHTOOL_TYPE_RING,
NM_ETHTOOL_TYPE_PAUSE,
NM_ETHTOOL_TYPE_CHANNELS,
+ NM_ETHTOOL_TYPE_EEE,
} NMEthtoolType;
/****************************************************************************/
@@ -187,6 +192,12 @@ nm_ethtool_id_is_channels(NMEthtoolID id)
return id >= _NM_ETHTOOL_ID_CHANNELS_FIRST && id <= _NM_ETHTOOL_ID_CHANNELS_LAST;
}
+static inline gboolean
+nm_ethtool_id_is_eee(NMEthtoolID id)
+{
+ return id >= _NM_ETHTOOL_ID_EEE_FIRST && id <= _NM_ETHTOOL_ID_EEE_LAST;
+}
+
/*****************************************************************************/
typedef enum {
diff --git a/src/libnm-base/nm-ethtool-base.c b/src/libnm-base/nm-ethtool-base.c
index 25b12cda32..a02b901869 100644
--- a/src/libnm-base/nm-ethtool-base.c
+++ b/src/libnm-base/nm-ethtool-base.c
@@ -41,6 +41,7 @@ const NMEthtoolData *const nm_ethtool_data[_NM_ETHTOOL_ID_NUM + 1] = {
ETHT_DATA(COALESCE_TX_USECS_HIGH),
ETHT_DATA(COALESCE_TX_USECS_IRQ),
ETHT_DATA(COALESCE_TX_USECS_LOW),
+ ETHT_DATA(EEE_ENABLED),
ETHT_DATA(FEATURE_ESP_HW_OFFLOAD),
ETHT_DATA(FEATURE_ESP_TX_CSUM_HW_OFFLOAD),
ETHT_DATA(FEATURE_FCOE_MTU),
@@ -141,6 +142,7 @@ static const guint8 _by_name[_NM_ETHTOOL_ID_NUM] = {
NM_ETHTOOL_ID_COALESCE_TX_USECS_HIGH,
NM_ETHTOOL_ID_COALESCE_TX_USECS_IRQ,
NM_ETHTOOL_ID_COALESCE_TX_USECS_LOW,
+ NM_ETHTOOL_ID_EEE_ENABLED,
NM_ETHTOOL_ID_FEATURE_ESP_HW_OFFLOAD,
NM_ETHTOOL_ID_FEATURE_ESP_TX_CSUM_HW_OFFLOAD,
NM_ETHTOOL_ID_FEATURE_FCOE_MTU,
@@ -301,6 +303,8 @@ nm_ethtool_id_to_type(NMEthtoolID id)
return NM_ETHTOOL_TYPE_PAUSE;
if (nm_ethtool_id_is_channels(id))
return NM_ETHTOOL_TYPE_CHANNELS;
+ if (nm_ethtool_id_is_eee(id))
+ return NM_ETHTOOL_TYPE_EEE;
return NM_ETHTOOL_TYPE_UNKNOWN;
}
@@ -311,6 +315,7 @@ nm_ethtool_id_get_variant_type(NMEthtoolID ethtool_id)
switch (nm_ethtool_id_to_type(ethtool_id)) {
case NM_ETHTOOL_TYPE_FEATURE:
case NM_ETHTOOL_TYPE_PAUSE:
+ case NM_ETHTOOL_TYPE_EEE:
return G_VARIANT_TYPE_BOOLEAN;
case NM_ETHTOOL_TYPE_CHANNELS:
case NM_ETHTOOL_TYPE_COALESCE:
diff --git a/src/libnm-base/nm-ethtool-utils-base.h b/src/libnm-base/nm-ethtool-utils-base.h
index 80c640df39..6b7a5937bc 100644
--- a/src/libnm-base/nm-ethtool-utils-base.h
+++ b/src/libnm-base/nm-ethtool-utils-base.h
@@ -109,6 +109,7 @@ G_BEGIN_DECLS
#define NM_ETHTOOL_OPTNAME_CHANNELS_OTHER "channels-other"
#define NM_ETHTOOL_OPTNAME_CHANNELS_COMBINED "channels-combined"
+#define NM_ETHTOOL_OPTNAME_EEE_ENABLED "eee"
/*****************************************************************************/
G_END_DECLS
diff --git a/src/libnm-client-impl/libnm.ver b/src/libnm-client-impl/libnm.ver
index aeb51d3c26..a92f8991ad 100644
--- a/src/libnm-client-impl/libnm.ver
+++ b/src/libnm-client-impl/libnm.ver
@@ -1948,4 +1948,5 @@ libnm_1_46_0 {
global:
nm_access_point_get_bandwidth;
nm_ethtool_optname_is_channels;
+ nm_ethtool_optname_is_eee;
} libnm_1_44_0;
diff --git a/src/libnm-client-public/nm-ethtool-utils.h b/src/libnm-client-public/nm-ethtool-utils.h
index 80c640df39..6b7a5937bc 100644
--- a/src/libnm-client-public/nm-ethtool-utils.h
+++ b/src/libnm-client-public/nm-ethtool-utils.h
@@ -109,6 +109,7 @@ G_BEGIN_DECLS
#define NM_ETHTOOL_OPTNAME_CHANNELS_OTHER "channels-other"
#define NM_ETHTOOL_OPTNAME_CHANNELS_COMBINED "channels-combined"
+#define NM_ETHTOOL_OPTNAME_EEE_ENABLED "eee"
/*****************************************************************************/
G_END_DECLS
diff --git a/src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in b/src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in
index d84c6c6e3d..78394a0432 100644
--- a/src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in
+++ b/src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in
@@ -1276,6 +1276,10 @@
dbus-type="b"
is-setting-option="1"
/>
+ <property name="eee"
+ dbus-type="b"
+ is-setting-option="1"
+ />
<property name="ring-rx"
dbus-type="u"
is-setting-option="1"
diff --git a/src/libnm-core-impl/nm-setting-ethtool.c b/src/libnm-core-impl/nm-setting-ethtool.c
index 138e86c02e..06c9c12b0d 100644
--- a/src/libnm-core-impl/nm-setting-ethtool.c
+++ b/src/libnm-core-impl/nm-setting-ethtool.c
@@ -92,6 +92,21 @@ nm_ethtool_optname_is_channels(const char *optname)
}
/**
+ * nm_ethtool_optname_is_eee:
+ * @optname: (nullable): the option name to check
+ *
+ * Checks whether @optname is a valid option name for an eee setting.
+ *
+ * Returns: %TRUE, if @optname is valid
+ *
+ * Since: 1.46
+ */
+gboolean
+nm_ethtool_optname_is_eee(const char *optname)
+{
+ return optname && nm_ethtool_id_is_eee(nm_ethtool_id_get_by_name(optname));
+}
+/**
* nm_ethtool_optname_is_pause:
* @optname: (nullable): the option name to check
*
diff --git a/src/libnm-core-impl/tests/test-setting.c b/src/libnm-core-impl/tests/test-setting.c
index b30758ffab..1a8910d8d3 100644
--- a/src/libnm-core-impl/tests/test-setting.c
+++ b/src/libnm-core-impl/tests/test-setting.c
@@ -2303,6 +2303,79 @@ test_ethtool_pause(void)
g_assert_true(out_value);
}
+static void
+test_ethtool_eee(void)
+{
+ gs_unref_object NMConnection *con = NULL;
+ gs_unref_object NMConnection *con2 = NULL;
+ gs_unref_object NMConnection *con3 = NULL;
+ gs_unref_variant GVariant *variant = NULL;
+ gs_free_error GError *error = NULL;
+ nm_auto_unref_keyfile GKeyFile *keyfile = NULL;
+ NMSettingConnection *s_con;
+ NMSettingEthtool *s_ethtool;
+ NMSettingEthtool *s_ethtool2;
+ NMSettingEthtool *s_ethtool3;
+ gboolean out_value;
+
+ con =
+ nmtst_create_minimal_connection("ethtool-eee", NULL, NM_SETTING_WIRED_SETTING_NAME, &s_con);
+ s_ethtool = NM_SETTING_ETHTOOL(nm_setting_ethtool_new());
+ nm_connection_add_setting(con, NM_SETTING(s_ethtool));
+
+ nm_setting_option_set_boolean(NM_SETTING(s_ethtool), NM_ETHTOOL_OPTNAME_EEE_ENABLED, FALSE);
+
+ g_assert_true(nm_setting_option_get_boolean(NM_SETTING(s_ethtool),
+ NM_ETHTOOL_OPTNAME_EEE_ENABLED,
+ &out_value));
+ g_assert_true(!out_value);
+
+ nmtst_connection_normalize(con);
+
+ variant = nm_connection_to_dbus(con, NM_CONNECTION_SERIALIZE_ALL);
+
+ con2 = nm_simple_connection_new_from_dbus(variant, &error);
+ nmtst_assert_success(con2, error);
+
+ s_ethtool2 = NM_SETTING_ETHTOOL(nm_connection_get_setting(con2, NM_TYPE_SETTING_ETHTOOL));
+
+ g_assert_true(nm_setting_option_get_boolean(NM_SETTING(s_ethtool2),
+ NM_ETHTOOL_OPTNAME_EEE_ENABLED,
+ &out_value));
+ g_assert_true(!out_value);
+
+ nmtst_assert_connection_verifies_without_normalization(con2);
+
+ nmtst_assert_connection_equals(con, FALSE, con2, FALSE);
+
+ con2 = nm_simple_connection_new_from_dbus(variant, &error);
+ nmtst_assert_success(con2, error);
+
+ keyfile = nm_keyfile_write(con, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, &error);
+ nmtst_assert_success(keyfile, error);
+
+ con3 = nm_keyfile_read(keyfile,
+ "/ignored/current/working/directory/for/loading/relative/paths",
+ NM_KEYFILE_HANDLER_FLAGS_NONE,
+ NULL,
+ NULL,
+ &error);
+ nmtst_assert_success(con3, error);
+
+ nm_keyfile_read_ensure_id(con3, "unused-because-already-has-id");
+ nm_keyfile_read_ensure_uuid(con3, "unused-because-already-has-uuid");
+
+ nmtst_connection_normalize(con3);
+
+ nmtst_assert_connection_equals(con, FALSE, con3, FALSE);
+
+ s_ethtool3 = NM_SETTING_ETHTOOL(nm_connection_get_setting(con3, NM_TYPE_SETTING_ETHTOOL));
+
+ g_assert_true(nm_setting_option_get_boolean(NM_SETTING(s_ethtool3),
+ NM_ETHTOOL_OPTNAME_EEE_ENABLED,
+ &out_value));
+ g_assert_true(!out_value);
+}
/*****************************************************************************/
static void
@@ -5326,6 +5399,7 @@ main(int argc, char **argv)
g_test_add_func("/libnm/settings/ethtool/coalesce", test_ethtool_coalesce);
g_test_add_func("/libnm/settings/ethtool/ring", test_ethtool_ring);
g_test_add_func("/libnm/settings/ethtool/pause", test_ethtool_pause);
+ g_test_add_func("/libnm/settings/ethtool/eee", test_ethtool_eee);
g_test_add_func("/libnm/settings/6lowpan/1", test_6lowpan_1);
diff --git a/src/libnm-core-public/nm-setting-ethtool.h b/src/libnm-core-public/nm-setting-ethtool.h
index 47db2573b7..fe1fbc0e39 100644
--- a/src/libnm-core-public/nm-setting-ethtool.h
+++ b/src/libnm-core-public/nm-setting-ethtool.h
@@ -29,6 +29,9 @@ gboolean nm_ethtool_optname_is_pause(const char *optname);
NM_AVAILABLE_IN_1_46
gboolean nm_ethtool_optname_is_channels(const char *optname);
+NM_AVAILABLE_IN_1_46
+gboolean nm_ethtool_optname_is_eee(const char *optname);
+
/*****************************************************************************/
#define NM_TYPE_SETTING_ETHTOOL (nm_setting_ethtool_get_type())
diff --git a/src/libnm-platform/nm-platform-utils.c b/src/libnm-platform/nm-platform-utils.c
index bba822a7b3..fc68fbb148 100644
--- a/src/libnm-platform/nm-platform-utils.c
+++ b/src/libnm-platform/nm-platform-utils.c
@@ -1162,6 +1162,35 @@ nmp_utils_ethtool_get_pause(int ifindex, NMEthtoolPauseState *pause)
}
gboolean
+nmp_utils_ethtool_get_eee(int ifindex, NMEthtoolEEEState *eee)
+{
+ struct ethtool_eee eth_data;
+ nm_auto_socket_handle SocketHandle shandle = SOCKET_HANDLE_INIT(ifindex);
+
+ g_return_val_if_fail(ifindex > 0, FALSE);
+ g_return_val_if_fail(eee, FALSE);
+
+ eth_data.cmd = ETHTOOL_GEEE;
+ if (_ethtool_call_handle(&shandle, &eth_data, sizeof(struct ethtool_eee)) != 0) {
+ nm_log_trace(LOGD_PLATFORM,
+ "ethtool[%d]: %s: failure getting eee settings",
+ ifindex,
+ "get-eee");
+ return FALSE;
+ }
+
+ *eee = (NMEthtoolEEEState){
+ .enabled = eth_data.eee_enabled == 1,
+ };
+
+ nm_log_trace(LOGD_PLATFORM,
+ "ethtool[%d]: %s: retrieved kernel eee settings",
+ ifindex,
+ "get-eee");
+ return TRUE;
+}
+
+gboolean
nmp_utils_ethtool_set_pause(int ifindex, const NMEthtoolPauseState *pause)
{
struct ethtool_pauseparam eth_data;
@@ -1188,6 +1217,36 @@ nmp_utils_ethtool_set_pause(int ifindex, const NMEthtoolPauseState *pause)
return TRUE;
}
+gboolean
+nmp_utils_ethtool_set_eee(int ifindex, const NMEthtoolEEEState *eee)
+{
+ struct ethtool_eee eth_data;
+ nm_auto_socket_handle SocketHandle shandle = SOCKET_HANDLE_INIT(ifindex);
+
+ g_return_val_if_fail(ifindex > 0, FALSE);
+ g_return_val_if_fail(eee, FALSE);
+
+ eth_data.cmd = ETHTOOL_GEEE;
+ if (_ethtool_call_handle(&shandle, &eth_data, sizeof(struct ethtool_eee)) != 0) {
+ nm_log_trace(LOGD_PLATFORM,
+ "ethtool[%d]: %s: failure getting eee settings",
+ ifindex,
+ "get-eee");
+ return FALSE;
+ }
+
+ eth_data.cmd = ETHTOOL_SEEE, eth_data.eee_enabled = eee->enabled ? 1 : 0;
+
+ if (_ethtool_call_handle(&shandle, &eth_data, sizeof(struct ethtool_eee)) != 0) {
+ nm_log_trace(LOGD_PLATFORM,
+ "ethtool[%d]: %s: failure setting eee settings",
+ ifindex,
+ "set-eee");
+ return FALSE;
+ }
+ nm_log_trace(LOGD_PLATFORM, "ethtool[%d]: %s: set kernel eee settings", ifindex, "set-eee");
+ return TRUE;
+}
/*****************************************************************************/
gboolean
diff --git a/src/libnm-platform/nm-platform-utils.h b/src/libnm-platform/nm-platform-utils.h
index 815d165431..18fc615557 100644
--- a/src/libnm-platform/nm-platform-utils.h
+++ b/src/libnm-platform/nm-platform-utils.h
@@ -62,6 +62,10 @@ gboolean nmp_utils_ethtool_get_pause(int ifindex, NMEthtoolPauseState *pause);
gboolean nmp_utils_ethtool_set_pause(int ifindex, const NMEthtoolPauseState *pause);
+gboolean nmp_utils_ethtool_get_eee(int ifindex, NMEthtoolEEEState *eee);
+
+gboolean nmp_utils_ethtool_set_eee(int ifindex, const NMEthtoolEEEState *eee);
+
/*****************************************************************************/
gboolean nmp_utils_mii_supports_carrier_detect(int ifindex);
diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c
index d5acec98f5..68d41daa98 100644
--- a/src/libnm-platform/nm-platform.c
+++ b/src/libnm-platform/nm-platform.c
@@ -3629,6 +3629,17 @@ nm_platform_ethtool_get_link_pause(NMPlatform *self, int ifindex, NMEthtoolPause
}
gboolean
+nm_platform_ethtool_get_link_eee(NMPlatform *self, int ifindex, NMEthtoolEEEState *eee)
+{
+ _CHECK_SELF_NETNS(self, klass, netns, FALSE);
+
+ g_return_val_if_fail(ifindex > 0, FALSE);
+ g_return_val_if_fail(eee, FALSE);
+
+ return nmp_utils_ethtool_get_eee(ifindex, eee);
+}
+
+gboolean
nm_platform_ethtool_set_pause(NMPlatform *self, int ifindex, const NMEthtoolPauseState *pause)
{
_CHECK_SELF_NETNS(self, klass, netns, FALSE);
@@ -3638,6 +3649,15 @@ nm_platform_ethtool_set_pause(NMPlatform *self, int ifindex, const NMEthtoolPaus
return nmp_utils_ethtool_set_pause(ifindex, pause);
}
+gboolean
+nm_platform_ethtool_set_eee(NMPlatform *self, int ifindex, const NMEthtoolEEEState *eee)
+{
+ _CHECK_SELF_NETNS(self, klass, netns, FALSE);
+
+ g_return_val_if_fail(ifindex > 0, FALSE);
+
+ return nmp_utils_ethtool_set_eee(ifindex, eee);
+}
/*****************************************************************************/
const NMDedupMultiHeadEntry *
diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h
index 81d2b9d6fe..557b4190a8 100644
--- a/src/libnm-platform/nm-platform.h
+++ b/src/libnm-platform/nm-platform.h
@@ -2578,9 +2578,13 @@ gboolean nm_platform_ethtool_set_channels(NMPlatform *self,
gboolean
nm_platform_ethtool_get_link_pause(NMPlatform *self, int ifindex, NMEthtoolPauseState *pause);
+gboolean nm_platform_ethtool_get_link_eee(NMPlatform *self, int ifindex, NMEthtoolEEEState *eee);
+
gboolean
nm_platform_ethtool_set_pause(NMPlatform *self, int ifindex, const NMEthtoolPauseState *pause);
+gboolean nm_platform_ethtool_set_eee(NMPlatform *self, int ifindex, const NMEthtoolEEEState *eee);
+
void nm_platform_ip4_dev_route_blacklist_set(NMPlatform *self,
int ifindex,
GPtrArray *ip4_dev_route_blacklist);
diff --git a/src/libnm-platform/nmp-base.h b/src/libnm-platform/nmp-base.h
index eeaad024a0..578efa51b3 100644
--- a/src/libnm-platform/nmp-base.h
+++ b/src/libnm-platform/nmp-base.h
@@ -119,6 +119,10 @@ typedef struct {
guint32 combined;
} NMEthtoolChannelsState;
+typedef struct {
+ bool enabled : 1;
+} NMEthtoolEEEState;
+
/*****************************************************************************/
typedef struct _NMPNetns NMPNetns;
diff --git a/src/libnmc-setting/nm-meta-setting-desc.c b/src/libnmc-setting/nm-meta-setting-desc.c
index 18bd407768..2e9593f81e 100644
--- a/src/libnmc-setting/nm-meta-setting-desc.c
+++ b/src/libnmc-setting/nm-meta-setting-desc.c
@@ -4433,6 +4433,7 @@ _get_fcn_ethtool(ARGS_GET_FCN)
RETURN_STR_TO_FREE(nm_strdup_int(u32));
case NM_ETHTOOL_TYPE_FEATURE:
case NM_ETHTOOL_TYPE_PAUSE:
+ case NM_ETHTOOL_TYPE_EEE:
if (!nm_setting_option_get_boolean(setting, nm_ethtool_data[ethtool_id]->optname, &b)) {
NM_SET_OUT(out_is_default, TRUE);
return NULL;
@@ -4479,6 +4480,7 @@ _set_fcn_ethtool(ARGS_SET_FCN)
return TRUE;
case NM_ETHTOOL_TYPE_FEATURE:
case NM_ETHTOOL_TYPE_PAUSE:
+ case NM_ETHTOOL_TYPE_EEE:
if (!nmc_string_to_ternary_full(value,
NMC_STRING_TO_TERNARY_FLAGS_IGNORE_FOR_DEFAULT,
&t,
@@ -5926,6 +5928,7 @@ static const NMMetaPropertyInfo *const property_infos_ETHTOOL[] = {
DEFINE_PROPERTY_TYP_DATA_SUBTYPE
(ethtool, .ethtool_id = NM_ETHTOOL_ID_PAUSE_TX)
),
+ PROPERTY_INFO_ETHTOOL (EEE_ENABLED),
PROPERTY_INFO_ETHTOOL (RING_RX),
PROPERTY_INFO_ETHTOOL (RING_RX_JUMBO),
PROPERTY_INFO_ETHTOOL (RING_RX_MINI),
diff --git a/src/nmcli/gen-metadata-nm-settings-nmcli.c b/src/nmcli/gen-metadata-nm-settings-nmcli.c
index 2def909565..a7f7bb681b 100644
--- a/src/nmcli/gen-metadata-nm-settings-nmcli.c
+++ b/src/nmcli/gen-metadata-nm-settings-nmcli.c
@@ -118,6 +118,7 @@ get_ethtool_format(const NMMetaPropertyInfo *prop_info)
return g_strdup("integer");
case NM_ETHTOOL_TYPE_FEATURE:
case NM_ETHTOOL_TYPE_PAUSE:
+ case NM_ETHTOOL_TYPE_EEE:
return g_strdup("ternary");
case NM_ETHTOOL_TYPE_UNKNOWN:
nm_assert_not_reached();
@@ -317,6 +318,7 @@ append_ethtool_valid_values(const NMMetaPropertyInfo *prop_info, GPtrArray *vali
break;
case NM_ETHTOOL_TYPE_FEATURE:
case NM_ETHTOOL_TYPE_PAUSE:
+ case NM_ETHTOOL_TYPE_EEE:
append_vals(valid_values, "on", "off", "ignore");
break;
case NM_ETHTOOL_TYPE_UNKNOWN:
diff --git a/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in b/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in
index 82304a409a..7297a2852f 100644
--- a/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in
+++ b/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in
@@ -1028,6 +1028,9 @@
nmcli-description="Whether TX pause should be enabled. Only valid when automatic negotiation is disabled"
format="ternary"
values="on, off, ignore" />
+ <property name="eee"
+ format="ternary"
+ values="on, off, ignore" />
<property name="ring-rx"
format="integer"
values="0 - 4294967295" />