WIP: support ethtool Forward Error Correction(fec)

Signed-off-by: Gris Ge <fge@redhat.com>
This commit is contained in:
Gris Ge 2024-03-19 19:31:40 +08:00 committed by Fernando Fernandez Mancera
parent b699de9d4a
commit 78cbe53889
17 changed files with 205 additions and 1 deletions

View file

@ -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)

View file

@ -6,6 +6,8 @@
#ifndef __NM_LIBNM_BASE_H__
#define __NM_LIBNM_BASE_H__
#include <linux/ethtool.h>
/*****************************************************************************/
/* 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 {

View file

@ -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:

View file

@ -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"
/*****************************************************************************/

View file

@ -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;

View file

@ -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"
/*****************************************************************************/

View file

@ -1340,6 +1340,10 @@
dbus-type="u"
is-setting-option="1"
/>
<property name="fec"
dbus-type="u"
is-setting-option="1"
/>
</setting>
<setting name="generic"
gtype="NMSettingGeneric"

View file

@ -121,6 +121,21 @@ nm_ethtool_optname_is_pause(const char *optname)
{
return optname && nm_ethtool_id_is_pause(nm_ethtool_id_get_by_name(optname));
}
/**
* nm_ethtool_optname_is_fec:
* @optname: (nullable): the option name to check
*
* Checks whether @optname is a valid option name for a fec setting.
*
* Returns: %TRUE, if @optname is valid
*
* Since: 1.32
*/
gboolean
nm_ethtool_optname_is_fec(const char *optname)
{
return optname && nm_ethtool_id_is_fec(nm_ethtool_id_get_by_name(optname));
}
/*****************************************************************************/

View file

@ -11,9 +11,33 @@
#endif
#include "nm-setting.h"
#include <linux/ethtool.h>
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())

View file

@ -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
*****************************************************************************/

View file

@ -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);

View file

@ -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,

View file

@ -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);

View file

@ -4,6 +4,7 @@
#define __NMP_FWD_H__
#include "libnm-base/nm-base.h"
#include <linux/ethtool.h>
/*****************************************************************************/

View file

@ -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,
};

View file

@ -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();
}

View file

@ -1078,6 +1078,10 @@
<property name="channels-combined"
format="integer"
values="0 - 4294967295" />
<property name="fec"
format="flags (NMEthtoolFec)"
nmcli-description="The Forward Error Correction(FEC) encoding modes to set. Not all devices support all options. May be any combination of &quot;auto&quot; (0x2), &quot;off&quot; (0x4), &quot;rs&quot; (0x8), &quot;baser&quot; (0x10), &quot;llrs&quot; (0x20)"
values="auto(0x2), off(0x4), rs(0x8), baser(0x10), llrs(0x20)"/>
</setting>
<setting name="generic" >
<property name="device-handler"