diff --git a/NEWS b/NEWS index 427a1afe9..fc0a1f108 100644 --- a/NEWS +++ b/NEWS @@ -23,6 +23,7 @@ USE AT YOUR OWN RISK. NOT RECOMMENDED FOR PRODUCTION USE! ipv4.routed-dns and ipv6.routed-dns properties; when enabled, each name server is reached only via the device that specifies it. * Support OCI in nm-cloud-setup +* Added support for ethtool FEC mode ============================================= NetworkManager-1.50 diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index e8f7156bf..96572f970 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -315,6 +315,7 @@ typedef struct { NMEthtoolPauseState *pause; NMEthtoolChannelsState *channels; NMEthtoolEEEState *eee; + uint32_t fec_mode; } EthtoolState; typedef enum { @@ -2681,6 +2682,19 @@ _ethtool_features_reset(NMDevice *self, NMPlatform *platform, EthtoolState *etht _LOGD(LOGD_DEVICE, "ethtool: offload features successfully reset"); } +static void +_ethtool_fec_reset(NMDevice *self, NMPlatform *platform, EthtoolState *ethtool_state) +{ + if (ethtool_state->fec_mode) { + if (!nm_platform_ethtool_set_fec_mode(platform, + ethtool_state->ifindex, + ethtool_state->fec_mode)) + _LOGW(LOGD_DEVICE, "ethtool: failure resetting FEC"); + else + _LOGD(LOGD_DEVICE, "ethtool: FEC successfully reset"); + } +} + static void _ethtool_features_set(NMDevice *self, NMPlatform *platform, @@ -2712,6 +2726,55 @@ _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) +{ + uint32_t old_fec_mode; + uint32_t fec_mode = NM_SETTING_ETHTOOL_FEC_MODE_NONE; + GHashTable *hash; + GHashTableIter iter; + const char *name; + GVariant *variant; + + 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->fec_mode); + + 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_fec(ethtool_id)) + continue; + + nm_assert(g_variant_is_of_type(variant, G_VARIANT_TYPE_UINT32)); + fec_mode = g_variant_get_uint32(variant); + } + + nm_platform_ethtool_get_fec_mode(platform, ethtool_state->ifindex, &old_fec_mode); + + /* The NM_SETTING_ETHTOOL_FEC_MODE_NONE is query only value, hence do nothing. */ + if (!fec_mode || fec_mode == NM_SETTING_ETHTOOL_FEC_MODE_NONE) { + return; + } + + if (!nm_platform_ethtool_set_fec_mode(platform, ethtool_state->ifindex, fec_mode)) + _LOGW(LOGD_DEVICE, "ethtool: failure setting FEC %d", fec_mode); + else { + _LOGD(LOGD_DEVICE, "ethtool: FEC %d successfully set", fec_mode); + ethtool_state->fec_mode = old_fec_mode; + } +} + static void _ethtool_coalesce_reset(NMDevice *self, NMPlatform *platform, EthtoolState *ethtool_state) { @@ -3193,6 +3256,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 @@ -3229,9 +3293,11 @@ _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) + || ethtool_state->pause || ethtool_state->channels || ethtool_state->eee + || ethtool_state->fec_mode != 0) priv->ethtool_state = g_steal_pointer(ðtool_state); } @@ -8625,7 +8691,7 @@ port_state_changed(NMDevice *port, /** * nm_device_controller_add_port: * @self: the controller device - * @port: the port device to attach as port + * @port: the port device to attach as port * @configure: pass %TRUE if the port should be configured by the controller, or * %FALSE if it is already configured outside NetworkManager * 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 93b24230b..6e0411c65 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 @@ -1454,6 +1454,15 @@ write_ethtool_setting(NMConnection *connection, shvarFile *ifcfg, GError **error return FALSE; } } + if (ethtool_id == NM_ETHTOOL_ID_FEC_MODE) { + if (nm_setting_option_get_uint32(NM_SETTING(s_ethtool), + nm_ethtool_data[ethtool_id]->optname, + &u32)) { + 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 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 334662c36..fc7c7e64a 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,8 @@ 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) || nm_ethtool_optname_is_eee(optname)) { + if (nm_ethtool_optname_is_channels(optname) || nm_ethtool_optname_is_eee(optname) + || nm_ethtool_optname_is_fec(optname)) { /* Not supported */ continue; } diff --git a/src/libnm-base/nm-base.h b/src/libnm-base/nm-base.h index 4b1bff547..048c02416 100644 --- a/src/libnm-base/nm-base.h +++ b/src/libnm-base/nm-base.h @@ -135,7 +135,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_MODE = _NM_ETHTOOL_ID_FEC_FIRST, + _NM_ETHTOOL_ID_FEC_LAST = NM_ETHTOOL_ID_FEC_MODE, + + _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 +162,7 @@ typedef enum { NM_ETHTOOL_TYPE_PAUSE, NM_ETHTOOL_TYPE_CHANNELS, NM_ETHTOOL_TYPE_EEE, + NM_ETHTOOL_TYPE_FEC, } NMEthtoolType; /****************************************************************************/ @@ -198,6 +203,12 @@ 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_FIRST && id <= _NM_ETHTOOL_ID_FEC_LAST; +} + /*****************************************************************************/ typedef enum { diff --git a/src/libnm-base/nm-ethtool-base.c b/src/libnm-base/nm-ethtool-base.c index 8e7f7814a..6f2ab2111 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_MODE), [_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_MODE, 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 75fb63c57..435e88d23 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_MODE "fec-mode" + #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 67e970e54..3b658b939 100644 --- a/src/libnm-client-impl/libnm.ver +++ b/src/libnm-client-impl/libnm.ver @@ -2043,4 +2043,6 @@ global: nm_setting_connection_clear_ip_ping_addresses; nm_setting_connection_remove_ip_ping_address_by_value; nm_setting_connection_get_ip_ping_addresses_require_all; + nm_setting_ethtool_fec_mode_get_type; + nm_ethtool_optname_is_fec; } libnm_1_50_0; diff --git a/src/libnm-client-public/nm-ethtool-utils.h b/src/libnm-client-public/nm-ethtool-utils.h index 75fb63c57..435e88d23 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_MODE "fec-mode" + #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 402e5a82b..cdc190d12 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 @@ -1361,6 +1361,10 @@ dbus-type="u" is-setting-option="1" /> + = (_NM_SETTING_ETHTOOL_FEC_MODE_LAST << 1)) { + gs_free const char *cur_fec_mode = NULL; + gs_free const char **valid_all = NULL; + gs_free const char *valid_str = NULL; + + cur_fec_mode = _nm_utils_enum_to_str_full(nm_setting_ethtool_fec_mode_get_type(), + (int) (fec_mode & INT_MAX), + ", ", + NULL); + valid_all = nm_utils_enum_get_values(nm_setting_ethtool_fec_mode_get_type(), 0, G_MAXUINT); + valid_str = g_strjoinv(",", (char **) valid_all); + + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' is not valid FEC modes, valid modes are combinations of %s"), + cur_fec_mode, + valid_str); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_ETHTOOL_SETTING_NAME, + NM_ETHTOOL_OPTNAME_FEC_MODE); + return FALSE; + } + return TRUE; } diff --git a/src/libnm-core-impl/tests/test-setting.c b/src/libnm-core-impl/tests/test-setting.c index 55acbe94c..2064162a9 100644 --- a/src/libnm-core-impl/tests/test-setting.c +++ b/src/libnm-core-impl/tests/test-setting.c @@ -2383,6 +2383,85 @@ test_ethtool_eee(void) } /*****************************************************************************/ +static void +test_ethtool_fec(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; + guint32 out_value; + guint32 expected_fec_mode = + NM_SETTING_ETHTOOL_FEC_MODE_AUTO | NM_SETTING_ETHTOOL_FEC_MODE_BASER; + + con = + nmtst_create_minimal_connection("ethtool-fec", 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_uint32(NM_SETTING(s_ethtool), + NM_ETHTOOL_OPTNAME_FEC_MODE, + expected_fec_mode); + + g_assert_true(nm_setting_option_get_uint32(NM_SETTING(s_ethtool), + NM_ETHTOOL_OPTNAME_FEC_MODE, + &out_value)); + g_assert_true(out_value == expected_fec_mode); + + 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_uint32(NM_SETTING(s_ethtool2), + NM_ETHTOOL_OPTNAME_FEC_MODE, + &out_value)); + g_assert_true(out_value == expected_fec_mode); + + 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_uint32(NM_SETTING(s_ethtool3), + NM_ETHTOOL_OPTNAME_FEC_MODE, + &out_value)); + g_assert_true(out_value == expected_fec_mode); +} +/*****************************************************************************/ + static void test_sriov_vf(void) { @@ -5486,6 +5565,7 @@ main(int argc, char **argv) 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/ethtool/fec", test_ethtool_fec); 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 fe1fbc0e3..867bb0f2f 100644 --- a/src/libnm-core-public/nm-setting-ethtool.h +++ b/src/libnm-core-public/nm-setting-ethtool.h @@ -32,6 +32,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_52 +gboolean nm_ethtool_optname_is_fec(const char *optname); + /*****************************************************************************/ #define NM_TYPE_SETTING_ETHTOOL (nm_setting_ethtool_get_type()) @@ -74,6 +77,30 @@ NM_AVAILABLE_IN_1_14 NM_DEPRECATED_IN_1_26 void nm_setting_ethtool_clear_features(NMSettingEthtool *setting); +/** + * NMSettingEthtoolFecMode: + * @NM_SETTING_ETHTOOL_FEC_MODE_NONE: FEC mode configuration is not supported. + * @NM_SETTING_ETHTOOL_FEC_MODE_AUTO: Select default/best FEC mode automatically. + * @NM_SETTING_ETHTOOL_FEC_MODE_OFF: No FEC mode. + * @NM_SETTING_ETHTOOL_FEC_MODE_RS: Reed-Solomon FEC Mode. + * @NM_SETTING_ETHTOOL_FEC_MODE_BASER: Base-R/Reed-Solomon FEC Mode. + * @NM_SETTING_ETHTOOL_FEC_MODE_LLRS: Low Latency Reed Solomon FEC Mode. + * + * These flags modify the ethtool FEC(Forward Error Correction) mode. + * + * Since: 1.52 + **/ +typedef enum { /*< flags >*/ + NM_SETTING_ETHTOOL_FEC_MODE_NONE = 1 << 0, /*< skip >*/ + NM_SETTING_ETHTOOL_FEC_MODE_AUTO = 1 << 1, + NM_SETTING_ETHTOOL_FEC_MODE_OFF = 1 << 2, + NM_SETTING_ETHTOOL_FEC_MODE_RS = 1 << 3, + NM_SETTING_ETHTOOL_FEC_MODE_BASER = 1 << 4, + NM_SETTING_ETHTOOL_FEC_MODE_LLRS = 1 << 5, + /* New constant should align with linux/ethtool.h ETHTOOL_FEC_XXX */ + _NM_SETTING_ETHTOOL_FEC_MODE_LAST = NM_SETTING_ETHTOOL_FEC_MODE_LLRS, /*< skip >*/ +} NMSettingEthtoolFecMode; + G_END_DECLS #endif /* __NM_SETTING_ETHTOOL_H__ */ diff --git a/src/libnm-platform/nm-platform-utils.c b/src/libnm-platform/nm-platform-utils.c index 209f00931..15aac11c2 100644 --- a/src/libnm-platform/nm-platform-utils.c +++ b/src/libnm-platform/nm-platform-utils.c @@ -1820,6 +1820,46 @@ nmp_utils_ethtool_set_wake_on_lan(int ifindex, return _ethtool_call_once(ifindex, &wol_info, sizeof(wol_info)) >= 0; } +gboolean +nmp_utils_ethtool_get_fec_mode(int ifindex, uint32_t *fec_mode) +{ + int r; + struct ethtool_fecparam fec_param = { + .cmd = ETHTOOL_GFECPARAM, + .fec = 0, + }; + + g_return_val_if_fail(ifindex > 0, FALSE); + + if (_ethtool_call_once(ifindex, &fec_param, sizeof(fec_param)) >= 0) { + nm_log_dbg(LOGD_PLATFORM, "ethtool[%d]: get FEC options 0x%x", ifindex, fec_param.fec); + *fec_mode = fec_param.fec; + return TRUE; + } else { + r = -NM_ERRNO_NATIVE(errno); + nm_log_dbg(LOGD_PLATFORM, + "ethtool[%d]: ETHTOOL_GFECPARAM failure get fec mode: (%s)", + ifindex, + nm_strerror_native(-r)); + return FALSE; + } +} + +gboolean +nmp_utils_ethtool_set_fec_mode(int ifindex, uint32_t fec_mode) +{ + struct ethtool_fecparam fec_param = { + .cmd = ETHTOOL_SFECPARAM, + .fec = fec_mode, + }; + + g_return_val_if_fail(ifindex > 0, FALSE); + + nm_log_dbg(LOGD_PLATFORM, "ethtool[%d]: setting FEC options 0x%x", ifindex, fec_mode); + + 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 96ac22ef3..f47bcd492 100644 --- a/src/libnm-platform/nm-platform-utils.h +++ b/src/libnm-platform/nm-platform-utils.h @@ -66,6 +66,10 @@ 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_get_fec_mode(int ifindex, uint32_t *fec_mode); + +gboolean nmp_utils_ethtool_set_fec_mode(int ifindex, uint32_t fec_mode); + /*****************************************************************************/ 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 ff45cf3d0..5cc97717f 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -3617,6 +3617,26 @@ nm_platform_ethtool_set_features( return nmp_utils_ethtool_set_features(ifindex, features, requested, do_set); } +gboolean +nm_platform_ethtool_get_fec_mode(NMPlatform *self, int ifindex, uint32_t *fec_mode) +{ + _CHECK_SELF_NETNS(self, klass, netns, FALSE); + + g_return_val_if_fail(ifindex > 0, FALSE); + + return nmp_utils_ethtool_get_fec_mode(ifindex, fec_mode); +} + +gboolean +nm_platform_ethtool_set_fec_mode(NMPlatform *self, int ifindex, uint32_t fec_mode) +{ + _CHECK_SELF_NETNS(self, klass, netns, FALSE); + + g_return_val_if_fail(ifindex > 0, FALSE); + + return nmp_utils_ethtool_set_fec_mode(ifindex, fec_mode); +} + 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 30d9037e6..ec7067a52 100644 --- a/src/libnm-platform/nm-platform.h +++ b/src/libnm-platform/nm-platform.h @@ -2652,6 +2652,10 @@ gboolean nm_platform_ethtool_set_channels(NMPlatform *self, int ifindex, const NMEthtoolChannelsState *channels); +gboolean nm_platform_ethtool_get_fec_mode(NMPlatform *self, int ifindex, uint32_t *fec_mode); + +gboolean nm_platform_ethtool_set_fec_mode(NMPlatform *self, int ifindex, uint32_t fec_mode); + gboolean nm_platform_ethtool_get_link_pause(NMPlatform *self, int ifindex, NMEthtoolPauseState *pause); diff --git a/src/libnmc-setting/nm-meta-setting-desc.c b/src/libnmc-setting/nm-meta-setting-desc.c index 0fa6cf345..14d8a2c10 100644 --- a/src/libnmc-setting/nm-meta-setting-desc.c +++ b/src/libnmc-setting/nm-meta-setting-desc.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "libnm-core-aux-intern/nm-common-macros.h" #include "libnm-glib-aux/nm-enum-utils.h" @@ -4459,6 +4460,21 @@ _get_fcn_ethtool(ARGS_GET_FCN) if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY) s = gettext(s); return s; + case NM_ETHTOOL_TYPE_FEC: + if (!nm_setting_option_get_uint32(setting, nm_ethtool_data[ethtool_id]->optname, &u32)) { + NM_SET_OUT(out_is_default, TRUE); + return NULL; + } + s = _nm_utils_enum_to_str_full(nm_setting_ethtool_fec_mode_get_type(), + (int) (u32 & INT_MAX), + ", ", + NULL); + if (s == NULL) { + NM_SET_OUT(out_is_default, TRUE); + } + if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY) + s = gettext(s); + return s; case NM_ETHTOOL_TYPE_UNKNOWN: nm_assert_not_reached(); } @@ -4469,9 +4485,11 @@ _get_fcn_ethtool(ARGS_GET_FCN) static gboolean _set_fcn_ethtool(ARGS_SET_FCN) { - NMEthtoolID ethtool_id = property_info->property_typ_data->subtype.ethtool.ethtool_id; - gint64 i64; - NMTernary t; + NMEthtoolID ethtool_id = property_info->property_typ_data->subtype.ethtool.ethtool_id; + gint64 i64; + NMTernary t; + int fec_mode = 0; + gs_free char *invalid_fec_mode = NULL; if (_SET_FCN_DO_RESET_DEFAULT(property_info, modifier, value)) goto do_unset; @@ -4512,6 +4530,30 @@ _set_fcn_ethtool(ARGS_SET_FCN) nm_setting_option_set_boolean(setting, nm_ethtool_data[ethtool_id]->optname, !!t); return TRUE; + case NM_ETHTOOL_TYPE_FEC: + if (_nm_utils_enum_from_str_full(nm_setting_ethtool_fec_mode_get_type(), + value, + &fec_mode, + &invalid_fec_mode, + NULL)) { + nm_setting_option_set_uint32(setting, + NM_ETHTOOL_OPTNAME_FEC_MODE, + (uint32_t) (fec_mode & UINT32_MAX)); + return TRUE; + } else { + gs_free const char **valid_all = NULL; + gs_free const char *valid_str = NULL; + + valid_all = + nm_utils_enum_get_values(nm_setting_ethtool_fec_mode_get_type(), 0, G_MAXUINT); + valid_str = g_strjoinv(",", (char **) valid_all); + nm_utils_error_set(error, + NM_UTILS_ERROR_INVALID_ARGUMENT, + _("'%s' is not valid FEC modes, valid modes are combinations of %s"), + invalid_fec_mode, + valid_str); + return FALSE; + } case NM_ETHTOOL_TYPE_UNKNOWN: nm_assert_not_reached(); } @@ -5989,6 +6031,15 @@ static const NMMetaPropertyInfo *const property_infos_ETHTOOL[] = { PROPERTY_INFO_ETHTOOL (CHANNELS_TX), PROPERTY_INFO_ETHTOOL (CHANNELS_OTHER), PROPERTY_INFO_ETHTOOL (CHANNELS_COMBINED), + PROPERTY_INFO (NM_ETHTOOL_OPTNAME_FEC_MODE, + "The Forward Error Correction(FEC) encoding modes to set. " + "Not all devices support all options. " + "May be any combination of auto, off, rs, baser, llrs.", + .property_type = &_pt_ethtool, + .property_typ_data = + DEFINE_PROPERTY_TYP_DATA_SUBTYPE + (ethtool, .ethtool_id = NM_ETHTOOL_ID_FEC_MODE) + ), NULL, }; diff --git a/src/nmcli/gen-metadata-nm-settings-nmcli.c b/src/nmcli/gen-metadata-nm-settings-nmcli.c index 0d207321a..2ba959956 100644 --- a/src/nmcli/gen-metadata-nm-settings-nmcli.c +++ b/src/nmcli/gen-metadata-nm-settings-nmcli.c @@ -124,6 +124,8 @@ get_ethtool_format(const NMMetaPropertyInfo *prop_info) case NM_ETHTOOL_TYPE_PAUSE: case NM_ETHTOOL_TYPE_EEE: return g_strdup("ternary"); + case NM_ETHTOOL_TYPE_FEC: + return g_strdup("flags (NMSettingEthtoolFecMode)"); case NM_ETHTOOL_TYPE_UNKNOWN: nm_assert_not_reached(); }; @@ -334,6 +336,13 @@ 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(NM_TYPE_SETTING_ETHTOOL_FEC_MODE, + 0, + G_MAXUINT, + NULL, + 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 f0b77433c..57dfbe4b7 100644 --- a/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in +++ b/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in @@ -1096,6 +1096,10 @@ +