diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index aaba79c02e..984ce825b0 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -305,6 +305,7 @@ typedef struct { NMEthtoolPauseState *pause; NMEthtoolChannelsState *channels; NMEthtoolEEEState *eee; + NMEthtoolFec fec; } EthtoolState; typedef enum { @@ -2450,6 +2451,25 @@ _ethtool_features_reset(NMDevice *self, NMPlatform *platform, EthtoolState *etht _LOGD(LOGD_DEVICE, "ethtool: offload features successfully reset"); } +static inline _NMEthtoolFec +_NM_ETHTOOL_FEC_CAST(NMEthtoolFec v) +{ + return (_NMEthtoolFec) v; +} + +static void +_ethtool_fec_reset(NMDevice *self, NMPlatform *platform, EthtoolState *ethtool_state) +{ + gs_free NMEthtoolFeatureStates *features = NULL; + + if (!nm_platform_ethtool_set_fec(platform, + ethtool_state->ifindex, + _NM_ETHTOOL_FEC_CAST(NM_ETHTOOL_FEC_AUTO))) + _LOGW(LOGD_DEVICE, "ethtool: failure resetting FEC"); + else + _LOGD(LOGD_DEVICE, "ethtool: FEC reset to auto"); +} + static void _ethtool_features_set(NMDevice *self, NMPlatform *platform, @@ -2481,6 +2501,26 @@ _ethtool_features_set(NMDevice *self, ethtool_state->features = g_steal_pointer(&features); } +static void +_ethtool_fec_set(NMDevice *self, + NMPlatform *platform, + EthtoolState *ethtool_state, + NMSettingEthtool *s_ethtool) +{ + NMEthtoolFec fec_mode = ethtool_state->fec; + + if (fec_mode == NM_ETHTOOL_FEC_NONE) { + return; + } + + if (!nm_platform_ethtool_set_fec(platform, + ethtool_state->ifindex, + _NM_ETHTOOL_FEC_CAST(fec_mode))) + _LOGW(LOGD_DEVICE, "ethtool: failure setting FEC %d", fec_mode); + else + _LOGD(LOGD_DEVICE, "ethtool: FEC %d successfully set", fec_mode); +} + static void _ethtool_coalesce_reset(NMDevice *self, NMPlatform *platform, EthtoolState *ethtool_state) { @@ -2962,6 +3002,7 @@ _ethtool_state_reset(NMDevice *self) _ethtool_pause_reset(self, platform, ethtool_state); _ethtool_channels_reset(self, platform, ethtool_state); _ethtool_eee_reset(self, platform, ethtool_state); + _ethtool_fec_reset(self, platform, ethtool_state); } static void @@ -2998,6 +3039,7 @@ _ethtool_state_set(NMDevice *self) _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); + _ethtool_fec_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->eee) diff --git a/src/libnm-base/nm-base.h b/src/libnm-base/nm-base.h index e1cc27332e..080a6a92c7 100644 --- a/src/libnm-base/nm-base.h +++ b/src/libnm-base/nm-base.h @@ -6,6 +6,8 @@ #ifndef __NM_LIBNM_BASE_H__ #define __NM_LIBNM_BASE_H__ +#include + /*****************************************************************************/ /* this must be the same as NM_UTILS_HWADDR_LEN_MAX from libnm. */ @@ -135,7 +137,11 @@ typedef enum { NM_ETHTOOL_ID_CHANNELS_COMBINED, _NM_ETHTOOL_ID_CHANNELS_LAST = NM_ETHTOOL_ID_CHANNELS_COMBINED, - _NM_ETHTOOL_ID_LAST = _NM_ETHTOOL_ID_CHANNELS_LAST, + _NM_ETHTOOL_ID_FEC_FIRST = _NM_ETHTOOL_ID_CHANNELS_LAST + 1, + NM_ETHTOOL_ID_FEC = _NM_ETHTOOL_ID_FEC_FIRST, + _NM_ETHTOOL_ID_FEC_LAST = NM_ETHTOOL_ID_FEC, + + _NM_ETHTOOL_ID_LAST = _NM_ETHTOOL_ID_FEC_LAST, _NM_ETHTOOL_ID_COALESCE_NUM = (_NM_ETHTOOL_ID_COALESCE_LAST - _NM_ETHTOOL_ID_COALESCE_FIRST + 1), @@ -158,6 +164,7 @@ typedef enum { NM_ETHTOOL_TYPE_PAUSE, NM_ETHTOOL_TYPE_CHANNELS, NM_ETHTOOL_TYPE_EEE, + NM_ETHTOOL_TYPE_FEC, } NMEthtoolType; /****************************************************************************/ @@ -198,6 +205,22 @@ nm_ethtool_id_is_eee(NMEthtoolID id) return id >= _NM_ETHTOOL_ID_EEE_FIRST && id <= _NM_ETHTOOL_ID_EEE_LAST; } +static inline gboolean +nm_ethtool_id_is_fec(NMEthtoolID id) +{ + return id == NM_ETHTOOL_ID_FEC; +} + +typedef enum { + // Mirrors libnm's NMEthtoolFec. + _NM_ETHTOOL_FEC_NONE = ETHTOOL_FEC_NONE, + _NM_ETHTOOL_FEC_AUTO = ETHTOOL_FEC_AUTO, + _NM_ETHTOOL_FEC_OFF = ETHTOOL_FEC_OFF, + _NM_ETHTOOL_FEC_RS = ETHTOOL_FEC_RS, + _NM_ETHTOOL_FEC_BASER = ETHTOOL_FEC_BASER, + _NM_ETHTOOL_FEC_LLRS = ETHTOOL_FEC_LLRS, +} _NMEthtoolFec; + /*****************************************************************************/ typedef enum { diff --git a/src/libnm-base/nm-ethtool-base.c b/src/libnm-base/nm-ethtool-base.c index a02b901869..67acb40793 100644 --- a/src/libnm-base/nm-ethtool-base.c +++ b/src/libnm-base/nm-ethtool-base.c @@ -111,6 +111,7 @@ const NMEthtoolData *const nm_ethtool_data[_NM_ETHTOOL_ID_NUM + 1] = { ETHT_DATA(CHANNELS_TX), ETHT_DATA(CHANNELS_OTHER), ETHT_DATA(CHANNELS_COMBINED), + ETHT_DATA(FEC), [_NM_ETHTOOL_ID_NUM] = NULL, }; @@ -201,6 +202,7 @@ static const guint8 _by_name[_NM_ETHTOOL_ID_NUM] = { NM_ETHTOOL_ID_FEATURE_TX_UDP_TNL_SEGMENTATION, NM_ETHTOOL_ID_FEATURE_TX_VLAN_STAG_HW_INSERT, NM_ETHTOOL_ID_FEATURE_TXVLAN, + NM_ETHTOOL_ID_FEC, NM_ETHTOOL_ID_PAUSE_AUTONEG, NM_ETHTOOL_ID_PAUSE_RX, NM_ETHTOOL_ID_PAUSE_TX, @@ -305,6 +307,8 @@ nm_ethtool_id_to_type(NMEthtoolID id) return NM_ETHTOOL_TYPE_CHANNELS; if (nm_ethtool_id_is_eee(id)) return NM_ETHTOOL_TYPE_EEE; + if (nm_ethtool_id_is_fec(id)) + return NM_ETHTOOL_TYPE_FEC; return NM_ETHTOOL_TYPE_UNKNOWN; } @@ -319,6 +323,7 @@ nm_ethtool_id_get_variant_type(NMEthtoolID ethtool_id) return G_VARIANT_TYPE_BOOLEAN; case NM_ETHTOOL_TYPE_CHANNELS: case NM_ETHTOOL_TYPE_COALESCE: + case NM_ETHTOOL_TYPE_FEC: case NM_ETHTOOL_TYPE_RING: return G_VARIANT_TYPE_UINT32; case NM_ETHTOOL_TYPE_UNKNOWN: diff --git a/src/libnm-base/nm-ethtool-utils-base.h b/src/libnm-base/nm-ethtool-utils-base.h index 75fb63c571..16bb66f554 100644 --- a/src/libnm-base/nm-ethtool-utils-base.h +++ b/src/libnm-base/nm-ethtool-utils-base.h @@ -109,6 +109,8 @@ G_BEGIN_DECLS #define NM_ETHTOOL_OPTNAME_CHANNELS_OTHER "channels-other" #define NM_ETHTOOL_OPTNAME_CHANNELS_COMBINED "channels-combined" +#define NM_ETHTOOL_OPTNAME_FEC "fec" + #define NM_ETHTOOL_OPTNAME_EEE_ENABLED "eee-enabled" /*****************************************************************************/ diff --git a/src/libnm-client-impl/libnm.ver b/src/libnm-client-impl/libnm.ver index 6d7da16f81..13e1835bed 100644 --- a/src/libnm-client-impl/libnm.ver +++ b/src/libnm-client-impl/libnm.ver @@ -1981,6 +1981,7 @@ global: libnm_1_48_0 { global: + nm_ethtool_fec_get_type; nm_setting_connection_down_on_poweroff_get_type; nm_setting_connection_get_down_on_poweroff; nm_setting_ip_config_get_dhcp_send_release; diff --git a/src/libnm-client-public/nm-ethtool-utils.h b/src/libnm-client-public/nm-ethtool-utils.h index 75fb63c571..16bb66f554 100644 --- a/src/libnm-client-public/nm-ethtool-utils.h +++ b/src/libnm-client-public/nm-ethtool-utils.h @@ -109,6 +109,8 @@ G_BEGIN_DECLS #define NM_ETHTOOL_OPTNAME_CHANNELS_OTHER "channels-other" #define NM_ETHTOOL_OPTNAME_CHANNELS_COMBINED "channels-combined" +#define NM_ETHTOOL_OPTNAME_FEC "fec" + #define NM_ETHTOOL_OPTNAME_EEE_ENABLED "eee-enabled" /*****************************************************************************/ 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 04340e6dd6..553cc038c3 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 @@ -1340,6 +1340,10 @@ dbus-type="u" is-setting-option="1" /> + G_BEGIN_DECLS +/** + * NMEthtoolFec: + * @NM_ETHTOOL_FEC_NONE: Internal use only + * @NM_ETHTOOL_FEC_AUTO: Select default/best FEC mode automatically + * @NM_ETHTOOL_FEC_OFF: No FEC Mode + * @NM_ETHTOOL_FEC_RS: Reed-Solomon FEC Mode + * @NM_ETHTOOL_FEC_BASER: Base-R/Reed-Solomon FEC Mode + * @NM_ETHTOOL_FEC_LLRS: Low Latency Reed Solomon FEC Mode + * + * #NMEthtoolFec describe ethtool Forward Error Correction(FEC) encoding modes. + * FQDN. + * + * Since: 1.48 + */ +typedef enum /*< flags >*/ { + NM_ETHTOOL_FEC_NONE = ETHTOOL_FEC_NONE, + NM_ETHTOOL_FEC_AUTO = ETHTOOL_FEC_AUTO, + NM_ETHTOOL_FEC_OFF = ETHTOOL_FEC_OFF, + NM_ETHTOOL_FEC_RS = ETHTOOL_FEC_RS, + NM_ETHTOOL_FEC_BASER = ETHTOOL_FEC_BASER, + NM_ETHTOOL_FEC_LLRS = ETHTOOL_FEC_LLRS, +} NMEthtoolFec; + NM_AVAILABLE_IN_1_20 gboolean nm_ethtool_optname_is_feature(const char *optname); @@ -32,6 +56,9 @@ gboolean nm_ethtool_optname_is_channels(const char *optname); NM_AVAILABLE_IN_1_46 gboolean nm_ethtool_optname_is_eee(const char *optname); +NM_AVAILABLE_IN_1_48 +gboolean nm_ethtool_optname_is_fec(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 6074c3421f..5270757992 100644 --- a/src/libnm-platform/nm-platform-utils.c +++ b/src/libnm-platform/nm-platform-utils.c @@ -1818,6 +1818,24 @@ nmp_utils_ethtool_set_wake_on_lan(int ifindex, return _ethtool_call_once(ifindex, &wol_info, sizeof(wol_info)) >= 0; } +gboolean +nmp_utils_ethtool_set_fec(int ifindex, const _NMEthtoolFec fec) +{ + struct ethtool_fecparam fec_param = { + .cmd = ETHTOOL_SFECPARAM, + .fec = (uint32_t) fec, + }; + + g_return_val_if_fail(ifindex > 0, FALSE); + + if (fec == _NM_ETHTOOL_FEC_NONE) + return TRUE; + + nm_log_dbg(LOGD_PLATFORM, "ethtool[%d]: setting FEC options 0x%x", ifindex, fec); + + return _ethtool_call_once(ifindex, &fec_param, sizeof(fec_param)) >= 0; +} + /****************************************************************************** * mii *****************************************************************************/ diff --git a/src/libnm-platform/nm-platform-utils.h b/src/libnm-platform/nm-platform-utils.h index 18fc615557..1728556b89 100644 --- a/src/libnm-platform/nm-platform-utils.h +++ b/src/libnm-platform/nm-platform-utils.h @@ -66,6 +66,8 @@ gboolean nmp_utils_ethtool_get_eee(int ifindex, NMEthtoolEEEState *eee); gboolean nmp_utils_ethtool_set_eee(int ifindex, const NMEthtoolEEEState *eee); +gboolean nmp_utils_ethtool_set_fec(int ifindex, const _NMEthtoolFec fec); + /*****************************************************************************/ 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 b89b035925..db99410400 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -3569,6 +3569,16 @@ nm_platform_ethtool_set_features( return nmp_utils_ethtool_set_features(ifindex, features, requested, do_set); } +gboolean +nm_platform_ethtool_set_fec(NMPlatform *self, int ifindex, const _NMEthtoolFec fec) +{ + _CHECK_SELF_NETNS(self, klass, netns, FALSE); + + g_return_val_if_fail(ifindex > 0, FALSE); + + return nmp_utils_ethtool_set_fec(ifindex, fec); +} + gboolean nm_platform_ethtool_get_link_coalesce(NMPlatform *self, int ifindex, diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h index f6a6ba082b..0da94ad434 100644 --- a/src/libnm-platform/nm-platform.h +++ b/src/libnm-platform/nm-platform.h @@ -2615,6 +2615,8 @@ gboolean nm_platform_ethtool_set_channels(NMPlatform *self, int ifindex, const NMEthtoolChannelsState *channels); +gboolean nm_platform_ethtool_set_fec(NMPlatform *self, int ifindex, const _NMEthtoolFec fec); + gboolean nm_platform_ethtool_get_link_pause(NMPlatform *self, int ifindex, NMEthtoolPauseState *pause); diff --git a/src/libnm-platform/nmp-base.h b/src/libnm-platform/nmp-base.h index 70b5d1bc55..cf2f635d98 100644 --- a/src/libnm-platform/nmp-base.h +++ b/src/libnm-platform/nmp-base.h @@ -4,6 +4,7 @@ #define __NMP_FWD_H__ #include "libnm-base/nm-base.h" +#include /*****************************************************************************/ diff --git a/src/libnmc-setting/nm-meta-setting-desc.c b/src/libnmc-setting/nm-meta-setting-desc.c index 84e553452a..bb5cdd70d9 100644 --- a/src/libnmc-setting/nm-meta-setting-desc.c +++ b/src/libnmc-setting/nm-meta-setting-desc.c @@ -4459,6 +4459,8 @@ _get_fcn_ethtool(ARGS_GET_FCN) if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY) s = gettext(s); return s; + // NM_ETHTOOL_TYPE_FEC is not using `_pt_ethtool`, hence unreachable here + case NM_ETHTOOL_TYPE_FEC: case NM_ETHTOOL_TYPE_UNKNOWN: nm_assert_not_reached(); } @@ -4512,6 +4514,8 @@ _set_fcn_ethtool(ARGS_SET_FCN) nm_setting_option_set_boolean(setting, nm_ethtool_data[ethtool_id]->optname, !!t); return TRUE; + // NM_ETHTOOL_TYPE_FEC is not using `_pt_ethtool`, hence unreachable here + case NM_ETHTOOL_TYPE_FEC: case NM_ETHTOOL_TYPE_UNKNOWN: nm_assert_not_reached(); } @@ -5988,6 +5992,42 @@ static const NMMetaPropertyInfo *const property_infos_ETHTOOL[] = { PROPERTY_INFO_ETHTOOL (CHANNELS_TX), PROPERTY_INFO_ETHTOOL (CHANNELS_OTHER), PROPERTY_INFO_ETHTOOL (CHANNELS_COMBINED), +// PROPERTY_INFO_WITH_DESC (NM_ETHTOOL_OPTNAME_FEC, + PROPERTY_INFO(NM_ETHTOOL_OPTNAME_FEC, "TODO doc", + .property_type = &_pt_gobject_enum, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA + ( + PROPERTY_TYP_DATA_SUBTYPE + (gobject_enum, + .get_gtype = nm_ethtool_fec_get_type, + .value_infos = ENUM_VALUE_INFOS + ( + { + .value = NM_ETHTOOL_FEC_AUTO, + .nick = "auto", + }, + { + .value = NM_ETHTOOL_FEC_OFF, + .nick = "off", + }, + { + .value = NM_ETHTOOL_FEC_RS, + .nick = "rs", + }, + { + .value = NM_ETHTOOL_FEC_BASER, + .nick = "baser", + }, + { + .value = NM_ETHTOOL_FEC_LLRS, + .nick = "llrs", + }, + ), + ), + .typ_flags = NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PARSABLE_TEXT + | NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PRETTY_TEXT, + ), + ), NULL, }; diff --git a/src/nmcli/gen-metadata-nm-settings-nmcli.c b/src/nmcli/gen-metadata-nm-settings-nmcli.c index babf1f064b..c46798b286 100644 --- a/src/nmcli/gen-metadata-nm-settings-nmcli.c +++ b/src/nmcli/gen-metadata-nm-settings-nmcli.c @@ -122,6 +122,9 @@ get_ethtool_format(const NMMetaPropertyInfo *prop_info) case NM_ETHTOOL_TYPE_PAUSE: case NM_ETHTOOL_TYPE_EEE: return g_strdup("ternary"); + // NM_ETHTOOL_TYPE_FEC is not using NM_META_PROPERTY_TYPE_FORMAT_ETHTOOL, + // hence unreachable. + case NM_ETHTOOL_TYPE_FEC: case NM_ETHTOOL_TYPE_UNKNOWN: nm_assert_not_reached(); }; @@ -328,6 +331,9 @@ append_ethtool_valid_values(const NMMetaPropertyInfo *prop_info, GPtrArray *vali case NM_ETHTOOL_TYPE_EEE: append_vals(valid_values, "on", "off", "ignore"); break; + case NM_ETHTOOL_TYPE_FEC: + append_enum_valid_values(prop_info, valid_values); + break; case NM_ETHTOOL_TYPE_UNKNOWN: nm_assert_not_reached(); } diff --git a/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in b/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in index b38a235eef..01a5b2c2c2 100644 --- a/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in +++ b/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in @@ -1078,6 +1078,10 @@ +