ethtool: merge branch 'ac/ethtool_opts'

Add support for ethtool coalesce options

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/496
This commit is contained in:
Antonio Cardace 2020-05-13 10:15:49 +02:00
commit 79f254850c
No known key found for this signature in database
GPG key ID: 6BF80ABD43E377D3
20 changed files with 1128 additions and 113 deletions

View file

@ -4097,61 +4097,104 @@ _gobject_enum_pre_set_notify_fcn_wireless_security_wep_key_type (const NMMetaPro
static gconstpointer
_get_fcn_ethtool (ARGS_GET_FCN)
{
const char *s;
NMTernary val;
char *return_str;
guint32 u32;
NMEthtoolID ethtool_id = property_info->property_typ_data->subtype.ethtool.ethtool_id;
RETURN_UNSUPPORTED_GET_TYPE ();
val = nm_setting_ethtool_get_feature (NM_SETTING_ETHTOOL (setting),
nm_ethtool_data[ethtool_id]->optname);
if (nm_ethtool_id_is_coalesce (ethtool_id)) {
if (!nm_setting_ethtool_get_coalesce (NM_SETTING_ETHTOOL (setting),
nm_ethtool_data[ethtool_id]->optname,
&u32)) {
NM_SET_OUT (out_is_default, TRUE);
return NULL;
}
if (val == NM_TERNARY_TRUE)
s = N_("on");
else if (val == NM_TERNARY_FALSE)
s = N_("off");
else {
s = NULL;
NM_SET_OUT (out_is_default, TRUE);
return_str = g_strdup_printf ("%"G_GUINT32_FORMAT, u32);
RETURN_STR_TO_FREE (return_str);
} else if (nm_ethtool_id_is_feature (ethtool_id)) {
const char *s;
NMTernary val;
val = nm_setting_ethtool_get_feature (NM_SETTING_ETHTOOL (setting),
nm_ethtool_data[ethtool_id]->optname);
if (val == NM_TERNARY_TRUE)
s = N_("on");
else if (val == NM_TERNARY_FALSE)
s = N_("off");
else {
s = NULL;
NM_SET_OUT (out_is_default, TRUE);
}
if (s && get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY)
s = gettext (s);
return s;
}
if (s && get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY)
s = gettext (s);
return s;
nm_assert_not_reached();
return NULL;
}
static gboolean
_set_fcn_ethtool (ARGS_SET_FCN)
{
gs_free char *value_to_free = NULL;
NMTernary val;
gint64 i64;
NMEthtoolID ethtool_id = property_info->property_typ_data->subtype.ethtool.ethtool_id;
if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value)) {
val = NM_TERNARY_DEFAULT;
goto set;
if (nm_ethtool_id_is_coalesce (ethtool_id)) {
i64 = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXUINT32, -1);
if (i64 == -1) {
g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT,
_("'%s' is out of range [%"G_GUINT32_FORMAT", %"G_GUINT32_FORMAT"]"),
value, 0, G_MAXUINT32);
return FALSE;
}
nm_setting_ethtool_set_coalesce (NM_SETTING_ETHTOOL (setting),
nm_ethtool_data[ethtool_id]->optname,
(guint32) i64);
return TRUE;
}
value = nm_strstrip_avoid_copy_a (300, value, &value_to_free);
if (nm_ethtool_id_is_feature (ethtool_id)) {
gs_free char *value_to_free = NULL;
NMTernary val;
if (NM_IN_STRSET (value, "1", "yes", "true", "on"))
val = NM_TERNARY_TRUE;
else if (NM_IN_STRSET (value, "0", "no", "false", "off"))
val = NM_TERNARY_FALSE;
else if (NM_IN_STRSET (value, "", "ignore", "default"))
val = NM_TERNARY_DEFAULT;
else {
g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT,
_("'%s' is not valid; use 'on', 'off', or 'ignore'"),
value);
return FALSE;
}
if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value)) {
val = NM_TERNARY_DEFAULT;
goto set;
}
value = nm_strstrip_avoid_copy_a (300, value, &value_to_free);
if (NM_IN_STRSET (value, "1", "yes", "true", "on"))
val = NM_TERNARY_TRUE;
else if (NM_IN_STRSET (value, "0", "no", "false", "off"))
val = NM_TERNARY_FALSE;
else if (NM_IN_STRSET (value, "", "ignore", "default"))
val = NM_TERNARY_DEFAULT;
else {
g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT,
_("'%s' is not valid; use 'on', 'off', or 'ignore'"),
value);
return FALSE;
}
set:
nm_setting_ethtool_set_feature (NM_SETTING_ETHTOOL (setting),
nm_setting_ethtool_set_feature (NM_SETTING_ETHTOOL (setting),
nm_ethtool_data[ethtool_id]->optname,
val);
return TRUE;
return TRUE;
}
nm_assert_not_reached();
g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_SETTING_MISSING,
_("ethtool property not supported"));
return FALSE;
}
static const char *const*
@ -4170,10 +4213,14 @@ _complete_fcn_ethtool (ARGS_COMPLETE_FCN)
"ignore",
NULL,
};
NMEthtoolID ethtool_id = property_info->property_typ_data->subtype.ethtool.ethtool_id;
if (!text || !text[0])
return &v[7];
return v;
if (nm_ethtool_id_is_feature (ethtool_id)) {
if (!text || !text[0])
return &v[7];
return v;
}
return NULL;
}
/*****************************************************************************/
@ -5431,6 +5478,28 @@ static const NMMetaPropertyInfo *const property_infos_ETHTOOL[] = {
PROPERTY_INFO_ETHTOOL (FEATURE_TX_UDP_TNL_CSUM_SEGMENTATION),
PROPERTY_INFO_ETHTOOL (FEATURE_TX_UDP_TNL_SEGMENTATION),
PROPERTY_INFO_ETHTOOL (FEATURE_TX_VLAN_STAG_HW_INSERT),
PROPERTY_INFO_ETHTOOL (COALESCE_ADAPTIVE_RX),
PROPERTY_INFO_ETHTOOL (COALESCE_ADAPTIVE_TX),
PROPERTY_INFO_ETHTOOL (COALESCE_PKT_RATE_HIGH),
PROPERTY_INFO_ETHTOOL (COALESCE_PKT_RATE_LOW),
PROPERTY_INFO_ETHTOOL (COALESCE_RX_FRAMES),
PROPERTY_INFO_ETHTOOL (COALESCE_RX_FRAMES_IRQ),
PROPERTY_INFO_ETHTOOL (COALESCE_RX_FRAMES_HIGH),
PROPERTY_INFO_ETHTOOL (COALESCE_RX_FRAMES_LOW),
PROPERTY_INFO_ETHTOOL (COALESCE_RX_USECS),
PROPERTY_INFO_ETHTOOL (COALESCE_RX_USECS_IRQ),
PROPERTY_INFO_ETHTOOL (COALESCE_RX_USECS_HIGH),
PROPERTY_INFO_ETHTOOL (COALESCE_RX_USECS_LOW),
PROPERTY_INFO_ETHTOOL (COALESCE_SAMPLE_INTERVAL),
PROPERTY_INFO_ETHTOOL (COALESCE_STATS_BLOCK_USECS),
PROPERTY_INFO_ETHTOOL (COALESCE_TX_FRAMES),
PROPERTY_INFO_ETHTOOL (COALESCE_TX_FRAMES_IRQ),
PROPERTY_INFO_ETHTOOL (COALESCE_TX_FRAMES_HIGH),
PROPERTY_INFO_ETHTOOL (COALESCE_TX_FRAMES_LOW),
PROPERTY_INFO_ETHTOOL (COALESCE_TX_USECS),
PROPERTY_INFO_ETHTOOL (COALESCE_TX_USECS_IRQ),
PROPERTY_INFO_ETHTOOL (COALESCE_TX_USECS_HIGH),
PROPERTY_INFO_ETHTOOL (COALESCE_TX_USECS_LOW),
NULL,
};

View file

@ -42,6 +42,22 @@ nm_ethtool_optname_is_feature (const char *optname)
return optname && nm_ethtool_id_is_feature (nm_ethtool_id_get_by_name (optname));
}
/**
* nm_ethtool_optname_is_coalesce:
* @optname: (allow-none): the option name to check
*
* Checks whether @optname is a valid option name for a coalesce setting.
*
* %Returns: %TRUE, if @optname is valid
*
* Since: 1.26
*/
gboolean
nm_ethtool_optname_is_coalesce (const char *optname)
{
return optname && nm_ethtool_id_is_coalesce (nm_ethtool_id_get_by_name (optname));
}
/*****************************************************************************/
/**
@ -239,6 +255,143 @@ nm_setting_ethtool_init_features (NMSettingEthtool *setting,
return n_req;
}
/**
* nm_setting_ethtool_get_coalesce:
* @setting: the #NMSettingEthtool
* @optname: option name of the coalescing setting to get
* @out_value (out) (allow-none): value of the coalescing setting
*
* Gets the value of coalescing setting.
*
* Note that @optname must be a valid name for a setting, according to
* nm_ethtool_optname_is_coalesce().
*
*
* Returns: %TRUE and places the coalesce setting value in @out_value or %FALSE if unset.
*
* Since: 1.26
*/
gboolean
nm_setting_ethtool_get_coalesce (NMSettingEthtool *setting,
const char *optname,
guint32 *out_value)
{
GVariant *v;
g_return_val_if_fail (NM_IS_SETTING_ETHTOOL (setting), FALSE);
g_return_val_if_fail (nm_ethtool_optname_is_coalesce (optname), FALSE);
v = nm_setting_gendata_get (NM_SETTING (setting), optname);
if ( v
&& g_variant_is_of_type (v, G_VARIANT_TYPE_UINT32)) {
NM_SET_OUT (out_value, g_variant_get_uint32 (v));
return TRUE;
}
NM_SET_OUT (out_value, 0);
return FALSE;
}
/**
* nm_setting_ethtool_set_coalesce:
* @setting: the #NMSettingEthtool
* @optname: option name of the coalesce setting
* @value: the new value to set.
*
* Sets a coalesce setting.
*
* Note that @optname must be a valid name for a coalesce setting, according to
* nm_ethtool_optname_is_coalesce().
*
* Since: 1.26
*/
void
nm_setting_ethtool_set_coalesce (NMSettingEthtool *setting,
const char *optname,
guint32 value)
{
GHashTable *ht;
NMEthtoolID ethtool_id;
g_return_if_fail (NM_IS_SETTING_ETHTOOL (setting));
ethtool_id = nm_ethtool_id_get_by_name (optname);
g_return_if_fail (nm_ethtool_id_is_coalesce (ethtool_id));
ht = _nm_setting_gendata_hash (NM_SETTING (setting),
TRUE);
if (NM_IN_SET (ethtool_id,
NM_ETHTOOL_ID_COALESCE_ADAPTIVE_RX,
NM_ETHTOOL_ID_COALESCE_ADAPTIVE_TX))
value = !!value;
g_hash_table_insert (ht,
g_strdup (optname),
g_variant_ref_sink (g_variant_new_uint32 (value)));
_notify_attributes (setting);
}
/**
* nm_setting_ethtool_clear_coalesce:
* @setting: the #NMSettingEthtool
* @optname: option name of the coalesce setting
*
* Clear a coalesce setting
*
* Since: 1.26
*/
void
nm_setting_ethtool_clear_coalesce (NMSettingEthtool *setting,
const char *optname)
{
GHashTable *hash;
g_return_if_fail (NM_IS_SETTING_ETHTOOL (setting));
g_return_if_fail (nm_str_not_empty (optname));
hash = _nm_setting_gendata_hash (NM_SETTING (setting), FALSE);
if (!hash)
return;
if (g_hash_table_remove (hash, optname))
_notify_attributes (setting);
}
/**
* nm_setting_ethtool_clear_coalesce_all:
* @setting: the #NMSettingEthtool
*
* Clears all coalesce settings
*
* Since: 1.26
*/
void
nm_setting_ethtool_clear_coalesce_all (NMSettingEthtool *setting)
{
GHashTable *hash;
GHashTableIter iter;
const char *name;
gboolean changed = FALSE;
g_return_if_fail (NM_IS_SETTING_ETHTOOL (setting));
hash = _nm_setting_gendata_hash (NM_SETTING (setting), FALSE);
if (!hash)
return;
g_hash_table_iter_init (&iter, hash);
while (g_hash_table_iter_next (&iter, (gpointer *) &name, NULL)) {
if (nm_ethtool_optname_is_coalesce (name)) {
g_hash_table_iter_remove (&iter);
changed = TRUE;
}
}
if (changed)
_notify_attributes (setting);
}
/*****************************************************************************/
/**
@ -284,19 +437,29 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
g_hash_table_iter_init (&iter, hash);
while (g_hash_table_iter_next (&iter, (gpointer *) &optname, (gpointer *) &variant)) {
if (!nm_ethtool_optname_is_feature (optname)) {
if (nm_ethtool_optname_is_feature (optname)) {
if (!g_variant_is_of_type (variant, G_VARIANT_TYPE_BOOLEAN)) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("offload feature has invalid variant type"));
g_prefix_error (error, "%s.%s: ", NM_SETTING_ETHTOOL_SETTING_NAME, optname);
return FALSE;
}
} else if (nm_ethtool_optname_is_coalesce (optname)) {
if (!g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32)) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("coalesce setting has invalid variant type"));
g_prefix_error (error, "%s.%s: ", NM_SETTING_ETHTOOL_SETTING_NAME, optname);
return FALSE;
}
} else {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("unsupported offload feature"));
g_prefix_error (error, "%s.%s: ", NM_SETTING_ETHTOOL_SETTING_NAME, optname);
return FALSE;
}
if (!g_variant_is_of_type (variant, G_VARIANT_TYPE_BOOLEAN)) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("offload feature has invalid variant type"));
_("unsupported ethtool setting"));
g_prefix_error (error, "%s.%s: ", NM_SETTING_ETHTOOL_SETTING_NAME, optname);
return FALSE;
}
@ -316,6 +479,9 @@ get_variant_type (const NMSettInfoSetting *sett_info,
if (nm_ethtool_optname_is_feature (name))
return G_VARIANT_TYPE_BOOLEAN;
if (nm_ethtool_optname_is_coalesce (name))
return G_VARIANT_TYPE_UINT32;
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,

View file

@ -69,9 +69,35 @@ G_BEGIN_DECLS
#define NM_ETHTOOL_OPTNAME_FEATURE_TX_UDP_TNL_SEGMENTATION "feature-tx-udp_tnl-segmentation"
#define NM_ETHTOOL_OPTNAME_FEATURE_TX_VLAN_STAG_HW_INSERT "feature-tx-vlan-stag-hw-insert"
#define NM_ETHTOOL_OPTNAME_COALESCE_ADAPTIVE_RX "coalesce-adaptive-rx"
#define NM_ETHTOOL_OPTNAME_COALESCE_ADAPTIVE_TX "coalesce-adaptive-tx"
#define NM_ETHTOOL_OPTNAME_COALESCE_PKT_RATE_HIGH "coalesce-pkt-rate-high"
#define NM_ETHTOOL_OPTNAME_COALESCE_PKT_RATE_LOW "coalesce-pkt-rate-low"
#define NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES "coalesce-rx-frames"
#define NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES_HIGH "coalesce-rx-frames-high"
#define NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES_IRQ "coalesce-rx-frames-irq"
#define NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES_LOW "coalesce-rx-frames-low"
#define NM_ETHTOOL_OPTNAME_COALESCE_RX_USECS "coalesce-rx-usecs"
#define NM_ETHTOOL_OPTNAME_COALESCE_RX_USECS_HIGH "coalesce-rx-usecs-high"
#define NM_ETHTOOL_OPTNAME_COALESCE_RX_USECS_IRQ "coalesce-rx-usecs-irq"
#define NM_ETHTOOL_OPTNAME_COALESCE_RX_USECS_LOW "coalesce-rx-usecs-low"
#define NM_ETHTOOL_OPTNAME_COALESCE_SAMPLE_INTERVAL "coalesce-sample-interval"
#define NM_ETHTOOL_OPTNAME_COALESCE_STATS_BLOCK_USECS "coalesce-stats-block-usecs"
#define NM_ETHTOOL_OPTNAME_COALESCE_TX_FRAMES "coalesce-tx-frames"
#define NM_ETHTOOL_OPTNAME_COALESCE_TX_FRAMES_HIGH "coalesce-tx-frames-high"
#define NM_ETHTOOL_OPTNAME_COALESCE_TX_FRAMES_IRQ "coalesce-tx-frames-irq"
#define NM_ETHTOOL_OPTNAME_COALESCE_TX_FRAMES_LOW "coalesce-tx-frames-low"
#define NM_ETHTOOL_OPTNAME_COALESCE_TX_USECS "coalesce-tx-usecs"
#define NM_ETHTOOL_OPTNAME_COALESCE_TX_USECS_HIGH "coalesce-tx-usecs-high"
#define NM_ETHTOOL_OPTNAME_COALESCE_TX_USECS_IRQ "coalesce-tx-usecs-irq"
#define NM_ETHTOOL_OPTNAME_COALESCE_TX_USECS_LOW "coalesce-tx-usecs-low"
NM_AVAILABLE_IN_1_20
gboolean nm_ethtool_optname_is_feature (const char *optname);
NM_AVAILABLE_IN_1_26
gboolean nm_ethtool_optname_is_coalesce (const char *optname);
/*****************************************************************************/
#define NM_TYPE_SETTING_ETHTOOL (nm_setting_ethtool_get_type ())
@ -109,6 +135,23 @@ NM_AVAILABLE_IN_1_20
const char ** nm_setting_ethtool_get_optnames (NMSettingEthtool *setting,
guint *out_length);
NM_AVAILABLE_IN_1_26
gboolean nm_setting_ethtool_get_coalesce (NMSettingEthtool *setting,
const char *optname,
guint32 *out_value);
NM_AVAILABLE_IN_1_26
void nm_setting_ethtool_set_coalesce (NMSettingEthtool *setting,
const char *optname,
guint32 value);
NM_AVAILABLE_IN_1_26
void nm_setting_ethtool_clear_coalesce (NMSettingEthtool *setting,
const char *optname);
NM_AVAILABLE_IN_1_26
void nm_setting_ethtool_clear_coalesce_all (NMSettingEthtool *setting);
G_END_DECLS
#endif /* __NM_SETTING_ETHTOOL_H__ */

View file

@ -1571,6 +1571,90 @@ test_ethtool_1 (void)
g_assert_cmpint (nm_setting_ethtool_get_feature (s_ethtool3, NM_ETHTOOL_OPTNAME_FEATURE_SG), ==, NM_TERNARY_DEFAULT);
}
static void
test_ethtool_coalesce (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;
gs_unref_keyfile GKeyFile *keyfile = NULL;
NMSettingConnection *s_con;
NMSettingEthtool *s_ethtool;
NMSettingEthtool *s_ethtool2;
NMSettingEthtool *s_ethtool3;
guint32 out_value;
con = nmtst_create_minimal_connection ("ethtool-coalesce",
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_ethtool_set_coalesce (s_ethtool,
NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES,
4);
g_assert_true (nm_setting_ethtool_get_coalesce (s_ethtool, NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES, &out_value));
g_assert_cmpuint (out_value, ==, 4);
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_ethtool_get_coalesce (s_ethtool2, NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES, &out_value));
g_assert_cmpuint (out_value, ==, 4);
nmtst_assert_connection_verifies_without_normalization (con2);
nmtst_assert_connection_equals (con, FALSE, con2, FALSE);
keyfile = nm_keyfile_write (con, NULL, NULL, &error);
nmtst_assert_success (keyfile, error);
con3 = nm_keyfile_read (keyfile,
"/ignored/current/working/directory/for/loading/relative/paths",
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_ethtool_get_coalesce (s_ethtool3, NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES, &out_value));
g_assert_cmpuint (out_value, ==, 4);
nm_setting_ethtool_clear_coalesce (s_ethtool, NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES);
g_assert_false (nm_setting_ethtool_get_coalesce (s_ethtool, NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES, NULL));
nm_setting_ethtool_set_coalesce (s_ethtool,
NM_ETHTOOL_OPTNAME_COALESCE_TX_FRAMES,
8);
g_assert_true (nm_setting_ethtool_get_coalesce (s_ethtool, NM_ETHTOOL_OPTNAME_COALESCE_TX_FRAMES, &out_value));
g_assert_cmpuint (out_value, ==, 8);
nm_setting_ethtool_clear_coalesce_all (s_ethtool);
g_assert_false (nm_setting_ethtool_get_coalesce (s_ethtool, NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES, NULL));
g_assert_false (nm_setting_ethtool_get_coalesce (s_ethtool, NM_ETHTOOL_OPTNAME_COALESCE_TX_FRAMES, NULL));
g_assert_false (nm_setting_ethtool_get_coalesce (s_ethtool, NM_ETHTOOL_OPTNAME_COALESCE_TX_USECS, NULL));
}
/*****************************************************************************/
static void
@ -3771,6 +3855,7 @@ main (int argc, char **argv)
g_test_add_func ("/libnm/settings/dcb/bandwidth-sums", test_dcb_bandwidth_sums);
g_test_add_func ("/libnm/settings/ethtool/1", test_ethtool_1);
g_test_add_func ("/libnm/settings/ethtool/coalesce", test_ethtool_coalesce);
g_test_add_func ("/libnm/settings/sriov/vf", test_sriov_vf);
g_test_add_func ("/libnm/settings/sriov/vf-dup", test_sriov_vf_dup);

View file

@ -1698,6 +1698,7 @@ global:
libnm_1_26_0 {
global:
nm_ethtool_optname_is_coalesce;
nm_setting_bridge_get_multicast_hash_max;
nm_setting_bridge_get_multicast_last_member_count;
nm_setting_bridge_get_multicast_last_member_interval;
@ -1708,6 +1709,10 @@ global:
nm_setting_bridge_get_multicast_startup_query_count;
nm_setting_bridge_get_multicast_startup_query_interval;
nm_setting_connection_get_mud_url;
nm_setting_ethtool_clear_coalesce;
nm_setting_ethtool_clear_coalesce_all;
nm_setting_ethtool_get_coalesce;
nm_setting_ethtool_set_coalesce;
nm_setting_match_add_driver;
nm_setting_match_add_kernel_command_line;
nm_setting_match_clear_drivers;

View file

@ -3243,6 +3243,22 @@ _read_setting (KeyfileReaderInfo *info)
continue;
}
variant = g_variant_new_boolean (v);
} else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_UINT32)) {
guint64 v;
v = g_key_file_get_uint64 (info->keyfile,
info->group,
key,
&local);
if (local) {
if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
_("key '%s.%s' is not a uint32"),
info->group, key))
break;
continue;
}
variant = g_variant_new_uint32 ((guint32) v);
} else {
nm_assert_not_reached ();
continue;
@ -3851,6 +3867,11 @@ nm_keyfile_write (NMConnection *connection,
setting_name,
key,
g_variant_get_boolean (v));
} else if (g_variant_is_of_type (v, G_VARIANT_TYPE_UINT32)) {
g_key_file_set_uint64 (info.keyfile,
setting_name,
key,
(guint64) g_variant_get_uint32 (v));
} else {
/* BUG: The variant type is not implemented. Since the connection
* verifies, this can only mean we either wrongly didn't reject

View file

@ -19,6 +19,28 @@
const NMEthtoolData *const nm_ethtool_data[_NM_ETHTOOL_ID_NUM + 1] = {
/* indexed by NMEthtoolID */
ETHT_DATA (COALESCE_ADAPTIVE_RX),
ETHT_DATA (COALESCE_ADAPTIVE_TX),
ETHT_DATA (COALESCE_PKT_RATE_HIGH),
ETHT_DATA (COALESCE_PKT_RATE_LOW),
ETHT_DATA (COALESCE_RX_FRAMES),
ETHT_DATA (COALESCE_RX_FRAMES_HIGH),
ETHT_DATA (COALESCE_RX_FRAMES_IRQ),
ETHT_DATA (COALESCE_RX_FRAMES_LOW),
ETHT_DATA (COALESCE_RX_USECS),
ETHT_DATA (COALESCE_RX_USECS_HIGH),
ETHT_DATA (COALESCE_RX_USECS_IRQ),
ETHT_DATA (COALESCE_RX_USECS_LOW),
ETHT_DATA (COALESCE_SAMPLE_INTERVAL),
ETHT_DATA (COALESCE_STATS_BLOCK_USECS),
ETHT_DATA (COALESCE_TX_FRAMES),
ETHT_DATA (COALESCE_TX_FRAMES_HIGH),
ETHT_DATA (COALESCE_TX_FRAMES_IRQ),
ETHT_DATA (COALESCE_TX_FRAMES_LOW),
ETHT_DATA (COALESCE_TX_USECS),
ETHT_DATA (COALESCE_TX_USECS_HIGH),
ETHT_DATA (COALESCE_TX_USECS_IRQ),
ETHT_DATA (COALESCE_TX_USECS_LOW),
ETHT_DATA (FEATURE_ESP_HW_OFFLOAD),
ETHT_DATA (FEATURE_ESP_TX_CSUM_HW_OFFLOAD),
ETHT_DATA (FEATURE_FCOE_MTU),
@ -76,6 +98,28 @@ const NMEthtoolData *const nm_ethtool_data[_NM_ETHTOOL_ID_NUM + 1] = {
static const guint8 _by_name[_NM_ETHTOOL_ID_NUM] = {
/* sorted by optname. */
NM_ETHTOOL_ID_COALESCE_ADAPTIVE_RX,
NM_ETHTOOL_ID_COALESCE_ADAPTIVE_TX,
NM_ETHTOOL_ID_COALESCE_PKT_RATE_HIGH,
NM_ETHTOOL_ID_COALESCE_PKT_RATE_LOW,
NM_ETHTOOL_ID_COALESCE_RX_FRAMES,
NM_ETHTOOL_ID_COALESCE_RX_FRAMES_HIGH,
NM_ETHTOOL_ID_COALESCE_RX_FRAMES_IRQ,
NM_ETHTOOL_ID_COALESCE_RX_FRAMES_LOW,
NM_ETHTOOL_ID_COALESCE_RX_USECS,
NM_ETHTOOL_ID_COALESCE_RX_USECS_HIGH,
NM_ETHTOOL_ID_COALESCE_RX_USECS_IRQ,
NM_ETHTOOL_ID_COALESCE_RX_USECS_LOW,
NM_ETHTOOL_ID_COALESCE_SAMPLE_INTERVAL,
NM_ETHTOOL_ID_COALESCE_STATS_BLOCK_USECS,
NM_ETHTOOL_ID_COALESCE_TX_FRAMES,
NM_ETHTOOL_ID_COALESCE_TX_FRAMES_HIGH,
NM_ETHTOOL_ID_COALESCE_TX_FRAMES_IRQ,
NM_ETHTOOL_ID_COALESCE_TX_FRAMES_LOW,
NM_ETHTOOL_ID_COALESCE_TX_USECS,
NM_ETHTOOL_ID_COALESCE_TX_USECS_HIGH,
NM_ETHTOOL_ID_COALESCE_TX_USECS_IRQ,
NM_ETHTOOL_ID_COALESCE_TX_USECS_LOW,
NM_ETHTOOL_ID_FEATURE_ESP_HW_OFFLOAD,
NM_ETHTOOL_ID_FEATURE_ESP_TX_CSUM_HW_OFFLOAD,
NM_ETHTOOL_ID_FEATURE_FCOE_MTU,

View file

@ -13,7 +13,32 @@ typedef enum {
_NM_ETHTOOL_ID_FIRST = 0,
_NM_ETHTOOL_ID_FEATURE_FIRST = _NM_ETHTOOL_ID_FIRST,
_NM_ETHTOOL_ID_COALESCE_FIRST = _NM_ETHTOOL_ID_FIRST,
NM_ETHTOOL_ID_COALESCE_ADAPTIVE_RX = _NM_ETHTOOL_ID_COALESCE_FIRST,
NM_ETHTOOL_ID_COALESCE_ADAPTIVE_TX,
NM_ETHTOOL_ID_COALESCE_PKT_RATE_HIGH,
NM_ETHTOOL_ID_COALESCE_PKT_RATE_LOW,
NM_ETHTOOL_ID_COALESCE_RX_FRAMES,
NM_ETHTOOL_ID_COALESCE_RX_FRAMES_HIGH,
NM_ETHTOOL_ID_COALESCE_RX_FRAMES_IRQ,
NM_ETHTOOL_ID_COALESCE_RX_FRAMES_LOW,
NM_ETHTOOL_ID_COALESCE_RX_USECS,
NM_ETHTOOL_ID_COALESCE_RX_USECS_HIGH,
NM_ETHTOOL_ID_COALESCE_RX_USECS_IRQ,
NM_ETHTOOL_ID_COALESCE_RX_USECS_LOW,
NM_ETHTOOL_ID_COALESCE_SAMPLE_INTERVAL,
NM_ETHTOOL_ID_COALESCE_STATS_BLOCK_USECS,
NM_ETHTOOL_ID_COALESCE_TX_FRAMES,
NM_ETHTOOL_ID_COALESCE_TX_FRAMES_HIGH,
NM_ETHTOOL_ID_COALESCE_TX_FRAMES_IRQ,
NM_ETHTOOL_ID_COALESCE_TX_FRAMES_LOW,
NM_ETHTOOL_ID_COALESCE_TX_USECS,
NM_ETHTOOL_ID_COALESCE_TX_USECS_HIGH,
NM_ETHTOOL_ID_COALESCE_TX_USECS_IRQ,
NM_ETHTOOL_ID_COALESCE_TX_USECS_LOW,
_NM_ETHTOOL_ID_COALESCE_LAST = NM_ETHTOOL_ID_COALESCE_TX_USECS_LOW,
_NM_ETHTOOL_ID_FEATURE_FIRST = _NM_ETHTOOL_ID_COALESCE_LAST + 1,
NM_ETHTOOL_ID_FEATURE_ESP_HW_OFFLOAD = _NM_ETHTOOL_ID_FEATURE_FIRST,
NM_ETHTOOL_ID_FEATURE_ESP_TX_CSUM_HW_OFFLOAD,
NM_ETHTOOL_ID_FEATURE_FCOE_MTU,
@ -67,10 +92,11 @@ typedef enum {
NM_ETHTOOL_ID_FEATURE_TX_UDP_TNL_SEGMENTATION,
NM_ETHTOOL_ID_FEATURE_TX_VLAN_STAG_HW_INSERT,
_NM_ETHTOOL_ID_FEATURE_LAST = NM_ETHTOOL_ID_FEATURE_TX_VLAN_STAG_HW_INSERT,
_NM_ETHTOOL_ID_FEATURE_NUM = (_NM_ETHTOOL_ID_FEATURE_LAST - _NM_ETHTOOL_ID_FEATURE_FIRST + 1),
_NM_ETHTOOL_ID_LAST = _NM_ETHTOOL_ID_FEATURE_LAST,
_NM_ETHTOOL_ID_COALESCE_NUM = (_NM_ETHTOOL_ID_COALESCE_LAST - _NM_ETHTOOL_ID_COALESCE_FIRST + 1),
_NM_ETHTOOL_ID_FEATURE_NUM = (_NM_ETHTOOL_ID_FEATURE_LAST - _NM_ETHTOOL_ID_FEATURE_FIRST + 1),
_NM_ETHTOOL_ID_NUM = (_NM_ETHTOOL_ID_LAST - _NM_ETHTOOL_ID_FIRST + 1),
} NMEthtoolID;
@ -100,6 +126,12 @@ nm_ethtool_id_is_feature (NMEthtoolID id)
return id >= _NM_ETHTOOL_ID_FEATURE_FIRST && id <= _NM_ETHTOOL_ID_FEATURE_LAST;
}
static inline gboolean
nm_ethtool_id_is_coalesce (NMEthtoolID id)
{
return id >= _NM_ETHTOOL_ID_COALESCE_FIRST && id <= _NM_ETHTOOL_ID_COALESCE_LAST;
}
/****************************************************************************/
#endif /* __NM_ETHTOOL_UTILS_H__ */

View file

@ -185,6 +185,7 @@ typedef struct {
int ifindex;
NMEthtoolFeatureStates *features;
NMTernary requested[_NM_ETHTOOL_ID_FEATURE_NUM];
NMEthtoolCoalesceStates *coalesce;
} EthtoolState;
/*****************************************************************************/
@ -812,64 +813,47 @@ NM_UTILS_LOOKUP_STR_DEFINE (mtu_source_to_str, NMDeviceMtuSource,
/*****************************************************************************/
static void
_ethtool_state_reset (NMDevice *self)
_ethtool_features_reset (NMDevice *self,
NMPlatform *platform,
EthtoolState *ethtool_state)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
gs_free NMEthtoolFeatureStates *features;
if (priv->ethtool_state) {
gs_free NMEthtoolFeatureStates *features = priv->ethtool_state->features;
gs_free EthtoolState *ethtool_state = g_steal_pointer (&priv->ethtool_state);
features = g_steal_pointer (&ethtool_state->features);
if (!nm_platform_ethtool_set_features (nm_device_get_platform (self),
ethtool_state->ifindex,
features,
ethtool_state->requested,
FALSE))
_LOGW (LOGD_DEVICE, "ethtool: failure resetting one or more offload features");
else
_LOGD (LOGD_DEVICE, "ethtool: offload features successfully reset");
}
if (!nm_platform_ethtool_set_features (platform,
ethtool_state->ifindex,
features,
ethtool_state->requested,
FALSE))
_LOGW (LOGD_DEVICE, "ethtool: failure resetting one or more offload features");
else
_LOGD (LOGD_DEVICE, "ethtool: offload features successfully reset");
}
static void
_ethtool_state_set (NMDevice *self)
_ethtool_features_set (NMDevice *self,
NMPlatform *platform,
EthtoolState *ethtool_state,
NMSettingEthtool *s_ethtool)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
int ifindex;
NMConnection *connection;
NMSettingEthtool *s_ethtool;
NMPlatform *platform;
gs_free EthtoolState *ethtool_state = NULL;
gs_free NMEthtoolFeatureStates *features = NULL;
_ethtool_state_reset (self);
if (ethtool_state->features)
_ethtool_features_reset (self, platform, ethtool_state);
connection = nm_device_get_applied_connection (self);
if (!connection)
return;
ifindex = nm_device_get_ip_ifindex (self);
if (ifindex <= 0)
return;
s_ethtool = NM_SETTING_ETHTOOL (nm_connection_get_setting (connection, NM_TYPE_SETTING_ETHTOOL));
if (!s_ethtool)
return;
ethtool_state = g_new (EthtoolState, 1);
if (nm_setting_ethtool_init_features (s_ethtool, ethtool_state->requested) == 0)
return;
platform = nm_device_get_platform (self);
features = nm_platform_ethtool_get_link_features (platform, ifindex);
features = nm_platform_ethtool_get_link_features (platform,
ethtool_state->ifindex);
if (!features) {
_LOGW (LOGD_DEVICE, "ethtool: failure setting offload features (cannot read features)");
return;
}
if (!nm_platform_ethtool_set_features (platform,
ifindex,
ethtool_state->ifindex,
features,
ethtool_state->requested,
TRUE))
@ -877,9 +861,170 @@ _ethtool_state_set (NMDevice *self)
else
_LOGD (LOGD_DEVICE, "ethtool: offload features successfully set");
ethtool_state->ifindex = ifindex;
ethtool_state->features = g_steal_pointer (&features);
priv->ethtool_state = g_steal_pointer (&ethtool_state);
}
static gboolean
_ethtool_init_coalesce (NMDevice *self,
NMPlatform *platform,
NMSettingEthtool *s_ethtool,
NMEthtoolCoalesceStates *coalesce)
{
GHashTable *hash;
GHashTableIter iter;
const char *name;
GVariant *variant;
gsize n_coalesce_set = 0;
nm_assert (self);
nm_assert (platform);
nm_assert (coalesce);
nm_assert (NM_IS_SETTING_ETHTOOL (s_ethtool));
hash = _nm_setting_gendata_hash (NM_SETTING (s_ethtool), FALSE);
if (!hash)
return FALSE;
g_hash_table_iter_init (&iter, hash);
while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer *) &variant)) {
if (!g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32))
continue;
if (!nm_platform_ethtool_init_coalesce (platform,
coalesce,
name,
g_variant_get_uint32(variant))) {
_LOGW (LOGD_DEVICE, "ethtool: invalid coalesce setting %s", name);
return FALSE;
}
++n_coalesce_set;
}
return (!!n_coalesce_set);
}
static void
_ethtool_coalesce_reset (NMDevice *self,
NMPlatform *platform,
EthtoolState *ethtool_state)
{
gs_free NMEthtoolCoalesceStates *coalesce = NULL;
nm_assert (NM_IS_DEVICE (self));
nm_assert (NM_IS_PLATFORM (platform));
nm_assert (ethtool_state);
coalesce = g_steal_pointer (&ethtool_state->coalesce);
if (!nm_platform_ethtool_set_coalesce (platform,
ethtool_state->ifindex,
coalesce,
FALSE))
_LOGW (LOGD_DEVICE, "ethtool: failure resetting one or more coalesce settings");
else
_LOGD (LOGD_DEVICE, "ethtool: coalesce settings successfully reset");
}
static void
_ethtool_coalesce_set (NMDevice *self,
NMPlatform *platform,
EthtoolState *ethtool_state,
NMSettingEthtool *s_ethtool)
{
gs_free NMEthtoolCoalesceStates *coalesce = NULL;
nm_assert (ethtool_state);
nm_assert (NM_IS_DEVICE (self));
nm_assert (NM_IS_PLATFORM (platform));
nm_assert (NM_IS_SETTING_ETHTOOL (s_ethtool));
coalesce = nm_platform_ethtool_get_link_coalesce (platform,
ethtool_state->ifindex);
if (!coalesce) {
_LOGW (LOGD_DEVICE, "ethtool: failure getting coalesce settings (cannot read)");
return;
}
if (!_ethtool_init_coalesce (self,
platform,
s_ethtool,
coalesce))
return;
if (!nm_platform_ethtool_set_coalesce (platform,
ethtool_state->ifindex,
coalesce,
TRUE)) {
_LOGW (LOGD_DEVICE, "ethtool: failure setting coalesce settings");
return;
}
_LOGD (LOGD_DEVICE, "ethtool: coalesce settings successfully set");
ethtool_state->coalesce = g_steal_pointer (&coalesce);
}
static void
_ethtool_state_reset (NMDevice *self)
{
NMPlatform *platform = nm_device_get_platform (self);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
gs_free EthtoolState *ethtool_state = g_steal_pointer (&priv->ethtool_state);
if (!ethtool_state)
return;
if (ethtool_state->features)
_ethtool_features_reset (self, platform, ethtool_state);
if (ethtool_state->coalesce)
_ethtool_coalesce_reset (self, platform, ethtool_state);
}
static void
_ethtool_state_set (NMDevice *self)
{
int ifindex;
NMPlatform *platform;
NMConnection *connection;
NMSettingEthtool *s_ethtool;
gs_free EthtoolState *ethtool_state = NULL;
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
ifindex = nm_device_get_ip_ifindex (self);
if (ifindex <= 0)
return;
platform = nm_device_get_platform (self);
nm_assert (platform);
connection = nm_device_get_applied_connection (self);
if (!connection)
return;
s_ethtool = NM_SETTING_ETHTOOL (nm_connection_get_setting (connection, NM_TYPE_SETTING_ETHTOOL));
if (!s_ethtool)
return;
ethtool_state = g_new0 (EthtoolState, 1);
ethtool_state->ifindex = ifindex;
_ethtool_features_set (self,
platform,
ethtool_state,
s_ethtool);
_ethtool_coalesce_set (self,
platform,
ethtool_state,
s_ethtool);
if ( ethtool_state->features
|| ethtool_state->coalesce)
priv->ethtool_state = g_steal_pointer (&ethtool_state);
}
/*****************************************************************************/

View file

@ -264,6 +264,7 @@ out:
static
NM_UTILS_ENUM2STR_DEFINE (_ethtool_cmd_to_string, guint32,
NM_UTILS_ENUM2STR (ETHTOOL_GCOALESCE, "ETHTOOL_GCOALESCE"),
NM_UTILS_ENUM2STR (ETHTOOL_GDRVINFO, "ETHTOOL_GDRVINFO"),
NM_UTILS_ENUM2STR (ETHTOOL_GFEATURES, "ETHTOOL_GFEATURES"),
NM_UTILS_ENUM2STR (ETHTOOL_GLINK, "ETHTOOL_GLINK"),
@ -273,6 +274,7 @@ NM_UTILS_ENUM2STR_DEFINE (_ethtool_cmd_to_string, guint32,
NM_UTILS_ENUM2STR (ETHTOOL_GSTATS, "ETHTOOL_GSTATS"),
NM_UTILS_ENUM2STR (ETHTOOL_GSTRINGS, "ETHTOOL_GSTRINGS"),
NM_UTILS_ENUM2STR (ETHTOOL_GWOL, "ETHTOOL_GWOL"),
NM_UTILS_ENUM2STR (ETHTOOL_SCOALESCE, "ETHTOOL_SCOALESCE"),
NM_UTILS_ENUM2STR (ETHTOOL_SFEATURES, "ETHTOOL_SFEATURES"),
NM_UTILS_ENUM2STR (ETHTOOL_SSET, "ETHTOOL_SSET"),
NM_UTILS_ENUM2STR (ETHTOOL_SWOL, "ETHTOOL_SWOL"),
@ -804,6 +806,145 @@ nmp_utils_ethtool_set_features (int ifindex,
return success;
}
static gboolean
ethtool_get_coalesce (SocketHandle *shandle,
NMEthtoolCoalesceState *out_state)
{
struct ethtool_coalesce eth_data;
eth_data.cmd = ETHTOOL_GCOALESCE;
if (_ethtool_call_handle (shandle,
&eth_data,
sizeof (struct ethtool_coalesce)) != 0)
return FALSE;
out_state->rx_coalesce_usecs = eth_data.rx_coalesce_usecs;
out_state->rx_max_coalesced_frames = eth_data.rx_max_coalesced_frames;
out_state->rx_coalesce_usecs_irq = eth_data.rx_coalesce_usecs_irq;
out_state->rx_max_coalesced_frames_irq = eth_data.rx_max_coalesced_frames_irq;
out_state->tx_coalesce_usecs = eth_data.tx_coalesce_usecs;
out_state->tx_max_coalesced_frames = eth_data.tx_max_coalesced_frames;
out_state->tx_coalesce_usecs_irq = eth_data.tx_coalesce_usecs_irq;
out_state->tx_max_coalesced_frames_irq = eth_data.tx_max_coalesced_frames_irq;
out_state->stats_block_coalesce_usecs = eth_data.stats_block_coalesce_usecs;
out_state->use_adaptive_rx_coalesce = eth_data.use_adaptive_rx_coalesce;
out_state->use_adaptive_tx_coalesce = eth_data.use_adaptive_tx_coalesce;
out_state->pkt_rate_low = eth_data.pkt_rate_low;
out_state->rx_coalesce_usecs_low = eth_data.rx_coalesce_usecs_low;
out_state->rx_max_coalesced_frames_low = eth_data.rx_max_coalesced_frames_low;
out_state->tx_coalesce_usecs_low = eth_data.tx_coalesce_usecs_low;
out_state->tx_max_coalesced_frames_low = eth_data.tx_max_coalesced_frames_low;
out_state->pkt_rate_high = eth_data.pkt_rate_high;
out_state->rx_coalesce_usecs_high = eth_data.rx_coalesce_usecs_high;
out_state->rx_max_coalesced_frames_high = eth_data.rx_max_coalesced_frames_high;
out_state->tx_coalesce_usecs_high = eth_data.tx_coalesce_usecs_high;
out_state->tx_max_coalesced_frames_high = eth_data.tx_max_coalesced_frames_high;
out_state->rate_sample_interval = eth_data.rate_sample_interval;
return TRUE;
}
NMEthtoolCoalesceStates *
nmp_utils_ethtool_get_coalesce (int ifindex)
{
gs_free NMEthtoolCoalesceStates *coalesce = NULL;
nm_auto_socket_handle SocketHandle shandle = SOCKET_HANDLE_INIT (ifindex);
g_return_val_if_fail (ifindex > 0, NULL);
coalesce = g_new0 (NMEthtoolCoalesceStates, 1);
if (!ethtool_get_coalesce (&shandle, &coalesce->old_state)) {
nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: failure getting coalesce settings",
ifindex,
"get-coalesce");
return NULL;
}
/* copy into requested as well, so that they're merged when applying */
coalesce->requested_state = coalesce->old_state;
nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: retrieved kernel coalesce settings",
ifindex,
"get-coalesce");
return g_steal_pointer (&coalesce);
}
static gboolean
ethtool_set_coalesce (SocketHandle *shandle,
const NMEthtoolCoalesceState *state)
{
gboolean success;
struct ethtool_coalesce eth_data;
g_return_val_if_fail (shandle, FALSE);
g_return_val_if_fail (state, FALSE);
eth_data = (struct ethtool_coalesce) {
.cmd = ETHTOOL_SCOALESCE,
.rx_coalesce_usecs = state->rx_coalesce_usecs,
.rx_max_coalesced_frames = state->rx_max_coalesced_frames,
.rx_coalesce_usecs_irq = state->rx_coalesce_usecs_irq,
.rx_max_coalesced_frames_irq = state->rx_max_coalesced_frames_irq,
.tx_coalesce_usecs = state->tx_coalesce_usecs,
.tx_max_coalesced_frames = state->tx_max_coalesced_frames,
.tx_coalesce_usecs_irq = state->tx_coalesce_usecs_irq,
.tx_max_coalesced_frames_irq = state->tx_max_coalesced_frames_irq,
.stats_block_coalesce_usecs = state->stats_block_coalesce_usecs,
.use_adaptive_rx_coalesce = state->use_adaptive_rx_coalesce,
.use_adaptive_tx_coalesce = state->use_adaptive_tx_coalesce,
.pkt_rate_low = state->pkt_rate_low,
.rx_coalesce_usecs_low = state->rx_coalesce_usecs_low,
.rx_max_coalesced_frames_low = state->rx_max_coalesced_frames_low,
.tx_coalesce_usecs_low = state->tx_coalesce_usecs_low,
.tx_max_coalesced_frames_low = state->tx_max_coalesced_frames_low,
.pkt_rate_high = state->pkt_rate_high,
.rx_coalesce_usecs_high = state->rx_coalesce_usecs_high,
.rx_max_coalesced_frames_high = state->rx_max_coalesced_frames_high,
.tx_coalesce_usecs_high = state->tx_coalesce_usecs_high,
.tx_max_coalesced_frames_high = state->tx_max_coalesced_frames_high,
.rate_sample_interval = state->rate_sample_interval,
};
success = (_ethtool_call_handle (shandle,
&eth_data,
sizeof (struct ethtool_coalesce)) == 0);
return success;
}
gboolean
nmp_utils_ethtool_set_coalesce (int ifindex,
const NMEthtoolCoalesceStates *coalesce,
gboolean do_set)
{
gboolean success;
nm_auto_socket_handle SocketHandle shandle = SOCKET_HANDLE_INIT (ifindex);
g_return_val_if_fail (ifindex > 0, FALSE);
g_return_val_if_fail (coalesce, FALSE);
if (do_set)
success = ethtool_set_coalesce (&shandle, &coalesce->requested_state);
else
success = ethtool_set_coalesce (&shandle, &coalesce->old_state);
if (!success) {
nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: failure %s coalesce settings",
ifindex,
"set-coalesce",
do_set ? "setting" : "resetting");
return FALSE;
}
nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: %s kernel coalesce settings",
ifindex,
"set-coalesce",
do_set ? "set" : "reset");
return TRUE;
}
/*****************************************************************************/
gboolean

View file

@ -92,6 +92,42 @@ gboolean nmp_utils_ethtool_set_features (int ifindex,
const NMTernary *requested /* indexed by NMEthtoolID - _NM_ETHTOOL_ID_FEATURE_FIRST */,
gboolean do_set /* or reset */);
typedef struct {
guint32 rx_coalesce_usecs;
guint32 rx_max_coalesced_frames;
guint32 rx_coalesce_usecs_irq;
guint32 rx_max_coalesced_frames_irq;
guint32 tx_coalesce_usecs;
guint32 tx_max_coalesced_frames;
guint32 tx_coalesce_usecs_irq;
guint32 tx_max_coalesced_frames_irq;
guint32 stats_block_coalesce_usecs;
guint32 use_adaptive_rx_coalesce;
guint32 use_adaptive_tx_coalesce;
guint32 pkt_rate_low;
guint32 rx_coalesce_usecs_low;
guint32 rx_max_coalesced_frames_low;
guint32 tx_coalesce_usecs_low;
guint32 tx_max_coalesced_frames_low;
guint32 pkt_rate_high;
guint32 rx_coalesce_usecs_high;
guint32 rx_max_coalesced_frames_high;
guint32 tx_coalesce_usecs_high;
guint32 tx_max_coalesced_frames_high;
guint32 rate_sample_interval;
} NMEthtoolCoalesceState;
struct _NMEthtoolCoalesceStates {
NMEthtoolCoalesceState old_state;
NMEthtoolCoalesceState requested_state;
};
NMEthtoolCoalesceStates * nmp_utils_ethtool_get_coalesce (int ifindex);
gboolean nmp_utils_ethtool_set_coalesce (int ifindex,
const NMEthtoolCoalesceStates *coalesce,
gboolean do_set);
/*****************************************************************************/
gboolean nmp_utils_mii_supports_carrier_detect (int ifindex);

View file

@ -3214,6 +3214,121 @@ nm_platform_ethtool_set_features (NMPlatform *self,
return nmp_utils_ethtool_set_features (ifindex, features, requested, do_set);
}
NMEthtoolCoalesceStates *
nm_platform_ethtool_get_link_coalesce (NMPlatform *self, int ifindex)
{
_CHECK_SELF_NETNS (self, klass, netns, NULL);
g_return_val_if_fail (ifindex > 0, NULL);
return nmp_utils_ethtool_get_coalesce (ifindex);
}
gboolean
nm_platform_ethtool_init_coalesce (NMPlatform *self,
NMEthtoolCoalesceStates *coalesce,
const char *option_name,
guint32 value)
{
NMEthtoolID ethtool_id;
NMEthtoolCoalesceState *state;
g_return_val_if_fail (coalesce, FALSE);
g_return_val_if_fail (option_name, FALSE);
state = &coalesce->requested_state;
ethtool_id = nm_ethtool_id_get_by_name (option_name);
if (!nm_ethtool_id_is_coalesce (ethtool_id))
return FALSE;
switch (ethtool_id) {
case NM_ETHTOOL_ID_COALESCE_ADAPTIVE_RX:
state->use_adaptive_rx_coalesce = value;
break;
case NM_ETHTOOL_ID_COALESCE_ADAPTIVE_TX:
state->use_adaptive_tx_coalesce = value;
break;
case NM_ETHTOOL_ID_COALESCE_PKT_RATE_HIGH:
state->pkt_rate_high = value;
break;
case NM_ETHTOOL_ID_COALESCE_PKT_RATE_LOW:
state->pkt_rate_low = value;
break;
case NM_ETHTOOL_ID_COALESCE_RX_FRAMES:
state->rx_max_coalesced_frames = value;
break;
case NM_ETHTOOL_ID_COALESCE_RX_FRAMES_HIGH:
state->rx_max_coalesced_frames_high = value;
break;
case NM_ETHTOOL_ID_COALESCE_RX_FRAMES_IRQ:
state->rx_max_coalesced_frames_irq = value;
break;
case NM_ETHTOOL_ID_COALESCE_RX_FRAMES_LOW:
state->rx_max_coalesced_frames_low = value;
break;
case NM_ETHTOOL_ID_COALESCE_RX_USECS:
state->rx_coalesce_usecs = value;
break;
case NM_ETHTOOL_ID_COALESCE_RX_USECS_HIGH:
state->rx_coalesce_usecs_high = value;
break;
case NM_ETHTOOL_ID_COALESCE_RX_USECS_IRQ:
state->rx_coalesce_usecs_irq = value;
break;
case NM_ETHTOOL_ID_COALESCE_RX_USECS_LOW:
state->rx_coalesce_usecs_low = value;
break;
case NM_ETHTOOL_ID_COALESCE_SAMPLE_INTERVAL:
state->rate_sample_interval = value;
break;
case NM_ETHTOOL_ID_COALESCE_STATS_BLOCK_USECS:
state->stats_block_coalesce_usecs = value;
break;
case NM_ETHTOOL_ID_COALESCE_TX_FRAMES:
state->tx_max_coalesced_frames = value;
break;
case NM_ETHTOOL_ID_COALESCE_TX_FRAMES_HIGH:
state->tx_max_coalesced_frames_high = value;
break;
case NM_ETHTOOL_ID_COALESCE_TX_FRAMES_IRQ:
state->tx_max_coalesced_frames_irq = value;
break;
case NM_ETHTOOL_ID_COALESCE_TX_FRAMES_LOW:
state->tx_max_coalesced_frames_low = value;
break;
case NM_ETHTOOL_ID_COALESCE_TX_USECS:
state->tx_coalesce_usecs = value;
break;
case NM_ETHTOOL_ID_COALESCE_TX_USECS_HIGH:
state->tx_coalesce_usecs_high = value;
break;
case NM_ETHTOOL_ID_COALESCE_TX_USECS_IRQ:
state->tx_coalesce_usecs_irq = value;
break;
case NM_ETHTOOL_ID_COALESCE_TX_USECS_LOW:
state->tx_coalesce_usecs_low = value;
break;
default:
g_return_val_if_reached (FALSE);
}
return TRUE;
}
gboolean
nm_platform_ethtool_set_coalesce (NMPlatform *self,
int ifindex,
const NMEthtoolCoalesceStates *coalesce,
gboolean do_set)
{
_CHECK_SELF_NETNS (self, klass, netns, FALSE);
g_return_val_if_fail (ifindex > 0, FALSE);
return nmp_utils_ethtool_set_coalesce (ifindex, coalesce, do_set);
}
/*****************************************************************************/
const NMDedupMultiHeadEntry *

View file

@ -1952,6 +1952,21 @@ gboolean nm_platform_ethtool_set_features (NMPlatform *self,
const NMTernary *requested /* indexed by NMEthtoolID - _NM_ETHTOOL_ID_FEATURE_FIRST */,
gboolean do_set /* or reset */);
typedef struct _NMEthtoolCoalesceStates NMEthtoolCoalesceStates;
NMEthtoolCoalesceStates *nm_platform_ethtool_get_link_coalesce (NMPlatform *self,
int ifindex);
gboolean nm_platform_ethtool_init_coalesce (NMPlatform *self,
NMEthtoolCoalesceStates *coalesce,
const char *option_name,
guint32 value);
gboolean nm_platform_ethtool_set_coalesce (NMPlatform *self,
int ifindex,
const NMEthtoolCoalesceStates *coalesce,
gboolean do_set);
const char * nm_platform_link_duplex_type_to_string (NMPlatformLinkDuplexType duplex);
void nm_platform_ip4_dev_route_blacklist_set (NMPlatform *self,

View file

@ -3290,14 +3290,14 @@ test_ethtool_features_get (void)
g_ptr_array_add (gfree_keeper, requested);
if (i_run == 0) {
requested[NM_ETHTOOL_ID_FEATURE_RX] = NM_TERNARY_FALSE;
requested[NM_ETHTOOL_ID_FEATURE_TSO] = NM_TERNARY_FALSE;
requested[NM_ETHTOOL_ID_FEATURE_TX_TCP6_SEGMENTATION] = NM_TERNARY_FALSE;
requested[NM_ETHTOOL_ID_FEATURE_RX - _NM_ETHTOOL_ID_FEATURE_FIRST] = NM_TERNARY_FALSE;
requested[NM_ETHTOOL_ID_FEATURE_TSO - _NM_ETHTOOL_ID_FEATURE_FIRST] = NM_TERNARY_FALSE;
requested[NM_ETHTOOL_ID_FEATURE_TX_TCP6_SEGMENTATION - _NM_ETHTOOL_ID_FEATURE_FIRST] = NM_TERNARY_FALSE;
} else if (i_run == 1)
do_set = FALSE;
else if (i_run == 2) {
requested[NM_ETHTOOL_ID_FEATURE_TSO] = NM_TERNARY_FALSE;
requested[NM_ETHTOOL_ID_FEATURE_TX_TCP6_SEGMENTATION] = NM_TERNARY_TRUE;
requested[NM_ETHTOOL_ID_FEATURE_TSO - _NM_ETHTOOL_ID_FEATURE_FIRST] = NM_TERNARY_FALSE;
requested[NM_ETHTOOL_ID_FEATURE_TX_TCP6_SEGMENTATION - _NM_ETHTOOL_ID_FEATURE_FIRST] = NM_TERNARY_TRUE;
} else if (i_run == 3)
do_set = FALSE;

View file

@ -4288,7 +4288,8 @@ parse_ethtool_option (const char *value,
d = nms_ifcfg_rh_utils_get_ethtool_by_name (opt);
if (!d) {
if ( !d
|| !nm_ethtool_id_is_feature (d->id)) {
if (onoff != NM_TERNARY_DEFAULT) {
/* the next value is just the on/off argument. Skip it too. */
i++;
@ -4309,6 +4310,45 @@ parse_ethtool_option (const char *value,
d->optname,
onoff);
}
} else if (NM_IN_STRSET (words[0], "-C", "--coalesce")) {
if (!words[1]) {
/* first argument must be the interface name. This is invalid. */
return;
}
if (!*out_s_ethtool)
*out_s_ethtool = NM_SETTING_ETHTOOL (nm_setting_ethtool_new ());
for (i = 2; words[i]; ) {
const char *opt = words[i];
const char *opt_val = words[++i];
const NMEthtoolData *d = NULL;
gint64 i64;
i64 = _nm_utils_ascii_str_to_int64 (opt_val, 10, 0, G_MAXUINT32, -1);
d = nms_ifcfg_rh_utils_get_ethtool_by_name (opt);
if ( !d
|| !nm_ethtool_id_is_coalesce (d->id)) {
if (i64 != -1) {
/* the next value is just the argument. Skip it too. */
i++;
}
/* silently ignore unsupported coalesce settings. */
continue;
}
i++;
if (i64 == -1) {
PARSE_WARNING ("Expects integer argument for setting '%s'", opt);
continue;
}
nm_setting_ethtool_set_coalesce (*out_s_ethtool,
d->optname,
(guint32) i64);
}
}
return;
}

View file

@ -522,9 +522,30 @@ nms_ifcfg_rh_utils_user_key_decode (const char *name, GString *str_buffer)
/*****************************************************************************/
const char *const _nm_ethtool_ifcfg_names[] = {
#define ETHT_NAME(eid, ename) \
[eid - _NM_ETHTOOL_ID_FEATURE_FIRST] = ""ename""
/* indexed by NMEthtoolID - _NM_ETHTOOL_ID_FEATURE_FIRST */
#define ETHT_NAME(eid, ename) [eid] = ""ename""
/* indexed by NMEthtoolID */
ETHT_NAME (NM_ETHTOOL_ID_COALESCE_ADAPTIVE_RX, "adaptive-rx"),
ETHT_NAME (NM_ETHTOOL_ID_COALESCE_ADAPTIVE_TX, "adaptive-tx"),
ETHT_NAME (NM_ETHTOOL_ID_COALESCE_RX_FRAMES, "rx-frames"),
ETHT_NAME (NM_ETHTOOL_ID_COALESCE_RX_FRAMES_HIGH, "rx-frames-high"),
ETHT_NAME (NM_ETHTOOL_ID_COALESCE_RX_FRAMES_IRQ, "rx-frames-irq"),
ETHT_NAME (NM_ETHTOOL_ID_COALESCE_RX_FRAMES_LOW, "rx-frames-low"),
ETHT_NAME (NM_ETHTOOL_ID_COALESCE_PKT_RATE_HIGH, "pkt-rate-high"),
ETHT_NAME (NM_ETHTOOL_ID_COALESCE_PKT_RATE_LOW, "pkt-rate-low"),
ETHT_NAME (NM_ETHTOOL_ID_COALESCE_RX_USECS, "rx-usecs"),
ETHT_NAME (NM_ETHTOOL_ID_COALESCE_RX_USECS_HIGH, "rx-usecs-high"),
ETHT_NAME (NM_ETHTOOL_ID_COALESCE_RX_USECS_IRQ, "rx-usecs-irq"),
ETHT_NAME (NM_ETHTOOL_ID_COALESCE_RX_USECS_LOW, "rx-usecs-low"),
ETHT_NAME (NM_ETHTOOL_ID_COALESCE_SAMPLE_INTERVAL, "sample-interval"),
ETHT_NAME (NM_ETHTOOL_ID_COALESCE_STATS_BLOCK_USECS, "stats-block-usecs"),
ETHT_NAME (NM_ETHTOOL_ID_COALESCE_TX_FRAMES, "tx-frames"),
ETHT_NAME (NM_ETHTOOL_ID_COALESCE_TX_FRAMES_HIGH, "tx-frames-high"),
ETHT_NAME (NM_ETHTOOL_ID_COALESCE_TX_FRAMES_IRQ, "tx-frames-irq"),
ETHT_NAME (NM_ETHTOOL_ID_COALESCE_TX_FRAMES_LOW, "tx-frames-low"),
ETHT_NAME (NM_ETHTOOL_ID_COALESCE_TX_USECS, "tx-usecs"),
ETHT_NAME (NM_ETHTOOL_ID_COALESCE_TX_USECS_HIGH, "tx-usecs-high"),
ETHT_NAME (NM_ETHTOOL_ID_COALESCE_TX_USECS_IRQ, "tx-usecs-irq"),
ETHT_NAME (NM_ETHTOOL_ID_COALESCE_TX_USECS_LOW, "tx-usecs-low"),
ETHT_NAME (NM_ETHTOOL_ID_FEATURE_ESP_HW_OFFLOAD, "esp-hw-offload"),
ETHT_NAME (NM_ETHTOOL_ID_FEATURE_ESP_TX_CSUM_HW_OFFLOAD, "esp-tx-csum-hw-offload"),
ETHT_NAME (NM_ETHTOOL_ID_FEATURE_FCOE_MTU, "fcoe-mtu"),
@ -598,6 +619,8 @@ NM_UTILS_STRING_TABLE_LOOKUP_DEFINE (
* the case and if yes, map them to the corresponding NetworkManager's features.
*
* That is why there are duplicate IDs in this list. */
{ "adaptive-rx", NM_ETHTOOL_ID_COALESCE_ADAPTIVE_RX },
{ "adaptive-tx", NM_ETHTOOL_ID_COALESCE_ADAPTIVE_TX },
{ "esp-hw-offload", NM_ETHTOOL_ID_FEATURE_ESP_HW_OFFLOAD },
{ "esp-tx-csum-hw-offload", NM_ETHTOOL_ID_FEATURE_ESP_TX_CSUM_HW_OFFLOAD },
{ "fcoe-mtu", NM_ETHTOOL_ID_FEATURE_FCOE_MTU },
@ -609,23 +632,35 @@ NM_UTILS_STRING_TABLE_LOOKUP_DEFINE (
{ "loopback", NM_ETHTOOL_ID_FEATURE_LOOPBACK },
{ "lro", NM_ETHTOOL_ID_FEATURE_LRO },
{ "ntuple", NM_ETHTOOL_ID_FEATURE_NTUPLE },
{ "pkt-rate-high", NM_ETHTOOL_ID_COALESCE_PKT_RATE_HIGH },
{ "pkt-rate-low", NM_ETHTOOL_ID_COALESCE_PKT_RATE_LOW },
{ "rx", NM_ETHTOOL_ID_FEATURE_RX },
{ "rx-all", NM_ETHTOOL_ID_FEATURE_RX_ALL },
{ "rx-checksum", NM_ETHTOOL_ID_FEATURE_RX }, // kernel-only name
{ "rx-fcs", NM_ETHTOOL_ID_FEATURE_RX_FCS },
{ "rx-frames", NM_ETHTOOL_ID_COALESCE_RX_FRAMES },
{ "rx-frames-high", NM_ETHTOOL_ID_COALESCE_RX_FRAMES_HIGH },
{ "rx-frames-irq", NM_ETHTOOL_ID_COALESCE_RX_FRAMES_IRQ },
{ "rx-frames-low", NM_ETHTOOL_ID_COALESCE_RX_FRAMES_LOW },
{ "rx-gro", NM_ETHTOOL_ID_FEATURE_GRO }, // kernel-only name
{ "rx-gro-hw", NM_ETHTOOL_ID_FEATURE_RX_GRO_HW },
{ "rx-hashing", NM_ETHTOOL_ID_FEATURE_RXHASH }, // kernel-only name
{ "rx-lro", NM_ETHTOOL_ID_FEATURE_LRO }, // kernel-only name
{ "rx-ntuple-filter", NM_ETHTOOL_ID_FEATURE_NTUPLE }, // kernel-only name
{ "rx-udp_tunnel-port-offload", NM_ETHTOOL_ID_FEATURE_RX_UDP_TUNNEL_PORT_OFFLOAD },
{ "rx-usecs", NM_ETHTOOL_ID_COALESCE_RX_USECS },
{ "rx-usecs-high", NM_ETHTOOL_ID_COALESCE_RX_USECS_HIGH },
{ "rx-usecs-irq", NM_ETHTOOL_ID_COALESCE_RX_USECS_IRQ },
{ "rx-usecs-low", NM_ETHTOOL_ID_COALESCE_RX_USECS_LOW },
{ "rx-vlan-filter", NM_ETHTOOL_ID_FEATURE_RX_VLAN_FILTER },
{ "rx-vlan-hw-parse", NM_ETHTOOL_ID_FEATURE_RXVLAN }, // kernel-only name
{ "rx-vlan-stag-filter", NM_ETHTOOL_ID_FEATURE_RX_VLAN_STAG_FILTER },
{ "rx-vlan-stag-hw-parse", NM_ETHTOOL_ID_FEATURE_RX_VLAN_STAG_HW_PARSE },
{ "rxhash", NM_ETHTOOL_ID_FEATURE_RXHASH },
{ "rxvlan", NM_ETHTOOL_ID_FEATURE_RXVLAN },
{ "sample-interval", NM_ETHTOOL_ID_COALESCE_SAMPLE_INTERVAL },
{ "sg", NM_ETHTOOL_ID_FEATURE_SG },
{ "stats-block-usecs", NM_ETHTOOL_ID_COALESCE_STATS_BLOCK_USECS },
{ "tls-hw-record", NM_ETHTOOL_ID_FEATURE_TLS_HW_RECORD },
{ "tls-hw-tx-offload", NM_ETHTOOL_ID_FEATURE_TLS_HW_TX_OFFLOAD },
{ "tso", NM_ETHTOOL_ID_FEATURE_TSO },
@ -637,6 +672,10 @@ NM_UTILS_STRING_TABLE_LOOKUP_DEFINE (
{ "tx-checksum-sctp", NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_SCTP },
{ "tx-esp-segmentation", NM_ETHTOOL_ID_FEATURE_TX_ESP_SEGMENTATION },
{ "tx-fcoe-segmentation", NM_ETHTOOL_ID_FEATURE_TX_FCOE_SEGMENTATION },
{ "tx-frames", NM_ETHTOOL_ID_COALESCE_TX_FRAMES },
{ "tx-frames-high", NM_ETHTOOL_ID_COALESCE_TX_FRAMES_HIGH },
{ "tx-frames-irq", NM_ETHTOOL_ID_COALESCE_TX_FRAMES_IRQ },
{ "tx-frames-low", NM_ETHTOOL_ID_COALESCE_TX_FRAMES_LOW },
{ "tx-generic-segmentation", NM_ETHTOOL_ID_FEATURE_GSO }, // kernel-only name
{ "tx-gre-csum-segmentation", NM_ETHTOOL_ID_FEATURE_TX_GRE_CSUM_SEGMENTATION },
{ "tx-gre-segmentation", NM_ETHTOOL_ID_FEATURE_TX_GRE_SEGMENTATION },
@ -655,6 +694,10 @@ NM_UTILS_STRING_TABLE_LOOKUP_DEFINE (
{ "tx-udp-segmentation", NM_ETHTOOL_ID_FEATURE_TX_UDP_SEGMENTATION },
{ "tx-udp_tnl-csum-segmentation", NM_ETHTOOL_ID_FEATURE_TX_UDP_TNL_CSUM_SEGMENTATION },
{ "tx-udp_tnl-segmentation", NM_ETHTOOL_ID_FEATURE_TX_UDP_TNL_SEGMENTATION },
{ "tx-usecs", NM_ETHTOOL_ID_COALESCE_TX_USECS },
{ "tx-usecs-high", NM_ETHTOOL_ID_COALESCE_TX_USECS_HIGH },
{ "tx-usecs-irq", NM_ETHTOOL_ID_COALESCE_TX_USECS_IRQ },
{ "tx-usecs-low", NM_ETHTOOL_ID_COALESCE_TX_USECS_LOW },
{ "tx-vlan-hw-insert", NM_ETHTOOL_ID_FEATURE_TXVLAN }, // kernel-only name
{ "tx-vlan-stag-hw-insert", NM_ETHTOOL_ID_FEATURE_TX_VLAN_STAG_HW_INSERT },
{ "txvlan", NM_ETHTOOL_ID_FEATURE_TXVLAN },

View file

@ -141,16 +141,16 @@ const NMSIfcfgKeyTypeInfo *nms_ifcfg_rh_utils_is_well_known_key (const char *key
/*****************************************************************************/
extern const char *const _nm_ethtool_ifcfg_names[_NM_ETHTOOL_ID_FEATURE_NUM];
extern const char *const _nm_ethtool_ifcfg_names[_NM_ETHTOOL_ID_NUM];
static inline const char *
nms_ifcfg_rh_utils_get_ethtool_name (NMEthtoolID ethtool_id)
{
nm_assert (ethtool_id >= _NM_ETHTOOL_ID_FEATURE_FIRST && ethtool_id <= _NM_ETHTOOL_ID_FEATURE_LAST);
nm_assert ((ethtool_id - _NM_ETHTOOL_ID_FEATURE_FIRST) < G_N_ELEMENTS (_nm_ethtool_ifcfg_names));
nm_assert (_nm_ethtool_ifcfg_names[ethtool_id - _NM_ETHTOOL_ID_FEATURE_FIRST]);
nm_assert (ethtool_id >= _NM_ETHTOOL_ID_FIRST && ethtool_id <= _NM_ETHTOOL_ID_LAST);
nm_assert (ethtool_id < G_N_ELEMENTS (_nm_ethtool_ifcfg_names));
nm_assert (_nm_ethtool_ifcfg_names[ethtool_id]);
return _nm_ethtool_ifcfg_names[ethtool_id - _NM_ETHTOOL_ID_FEATURE_FIRST];
return _nm_ethtool_ifcfg_names[ethtool_id];
}
const NMEthtoolData *nms_ifcfg_rh_utils_get_ethtool_by_name (const char *name);

View file

@ -1195,6 +1195,23 @@ write_ethtool_setting (NMConnection *connection, shvarFile *ifcfg, GError **erro
g_string_append (str, nms_ifcfg_rh_utils_get_ethtool_name (ethtool_id));
g_string_append (str, val == NM_TERNARY_TRUE ? " on" : " off");
}
g_string_append (str, " ; -C ");
g_string_append (str, iface ?: "net0");
for (ethtool_id = _NM_ETHTOOL_ID_COALESCE_FIRST; ethtool_id <= _NM_ETHTOOL_ID_COALESCE_LAST; ethtool_id++) {
const NMEthtoolData *ed = nm_ethtool_data[ethtool_id];
guint32 val;
nm_assert (nms_ifcfg_rh_utils_get_ethtool_name (ethtool_id));
if (!nm_setting_ethtool_get_coalesce (s_ethtool, ed->optname, &val))
continue;
g_string_append_c (str, ' ');
g_string_append (str, nms_ifcfg_rh_utils_get_ethtool_name (ethtool_id));
g_string_append_printf (str, " %"G_GUINT32_FORMAT, val);
}
}
if (str) {

View file

@ -1,7 +1,7 @@
TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
ETHTOOL_OPTS="autoneg on ; -K net0 rxvlan off tx on"
ETHTOOL_OPTS="autoneg on ; -K net0 rxvlan off tx on ; -C net0"
BOOTPROTO=dhcp
DEFROUTE=yes
IPV4_FAILURE_FATAL=no

View file

@ -10368,18 +10368,16 @@ test_ethtool_names (void)
NMEthtoolID id;
int i;
for (id = _NM_ETHTOOL_ID_FEATURE_FIRST; id <= _NM_ETHTOOL_ID_FEATURE_LAST; id++) {
for (id = _NM_ETHTOOL_ID_FIRST; id <= _NM_ETHTOOL_ID_LAST; id++) {
const char *ifcfg_rh_name;
int idx;
idx = id - _NM_ETHTOOL_ID_FEATURE_FIRST;
g_assert (idx >= 0);
g_assert (idx < G_N_ELEMENTS (_nm_ethtool_ifcfg_names));
ifcfg_rh_name = _nm_ethtool_ifcfg_names[idx];
g_assert (id >= 0);
g_assert (id < G_N_ELEMENTS (_nm_ethtool_ifcfg_names));
ifcfg_rh_name = _nm_ethtool_ifcfg_names[id];
g_assert (ifcfg_rh_name && ifcfg_rh_name[0]);
for (i = 0; i < G_N_ELEMENTS (_nm_ethtool_ifcfg_names); i++) {
if (i != idx)
if (i != id)
g_assert_cmpstr (ifcfg_rh_name, !=, _nm_ethtool_ifcfg_names[i]);
}