diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c index 2df48493de..272c089d98 100644 --- a/clients/common/nm-meta-setting-desc.c +++ b/clients/common/nm-meta-setting-desc.c @@ -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, }; diff --git a/libnm-core/nm-setting-ethtool.c b/libnm-core/nm-setting-ethtool.c index a8976b69f5..6dc6d5d75a 100644 --- a/libnm-core/nm-setting-ethtool.c +++ b/libnm-core/nm-setting-ethtool.c @@ -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, diff --git a/libnm-core/nm-setting-ethtool.h b/libnm-core/nm-setting-ethtool.h index ba8c6a6e7e..a62a33159c 100644 --- a/libnm-core/nm-setting-ethtool.h +++ b/libnm-core/nm-setting-ethtool.h @@ -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__ */ diff --git a/libnm-core/tests/test-setting.c b/libnm-core/tests/test-setting.c index f77ba9fd17..1e82e245f9 100644 --- a/libnm-core/tests/test-setting.c +++ b/libnm-core/tests/test-setting.c @@ -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); diff --git a/libnm/libnm.ver b/libnm/libnm.ver index 59e7db4ff1..e8203f5b6e 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -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; diff --git a/shared/nm-keyfile/nm-keyfile.c b/shared/nm-keyfile/nm-keyfile.c index 0caef893e0..372ae202e3 100644 --- a/shared/nm-keyfile/nm-keyfile.c +++ b/shared/nm-keyfile/nm-keyfile.c @@ -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 diff --git a/shared/nm-libnm-core-intern/nm-ethtool-utils.c b/shared/nm-libnm-core-intern/nm-ethtool-utils.c index ace47680f5..3842e3122e 100644 --- a/shared/nm-libnm-core-intern/nm-ethtool-utils.c +++ b/shared/nm-libnm-core-intern/nm-ethtool-utils.c @@ -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, diff --git a/shared/nm-libnm-core-intern/nm-ethtool-utils.h b/shared/nm-libnm-core-intern/nm-ethtool-utils.h index b3413de2b7..0505328364 100644 --- a/shared/nm-libnm-core-intern/nm-ethtool-utils.h +++ b/shared/nm-libnm-core-intern/nm-ethtool-utils.h @@ -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__ */ diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index fb926c945d..de72b1d15a 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -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 (ðtool_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 (ðtool_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 (ðtool_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 (ðtool_state); } /*****************************************************************************/ diff --git a/src/platform/nm-platform-utils.c b/src/platform/nm-platform-utils.c index 98884cd717..c47d8476fc 100644 --- a/src/platform/nm-platform-utils.c +++ b/src/platform/nm-platform-utils.c @@ -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, + ð_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, + ð_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 diff --git a/src/platform/nm-platform-utils.h b/src/platform/nm-platform-utils.h index a62d828c89..56fdb5e4d3 100644 --- a/src/platform/nm-platform-utils.h +++ b/src/platform/nm-platform-utils.h @@ -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); diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 9bbc37453c..c17cd305dc 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -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 * diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 7edaaf58e3..931ab16391 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -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, diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c index ea4a2c5ab9..7398d2ee27 100644 --- a/src/platform/tests/test-link.c +++ b/src/platform/tests/test-link.c @@ -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; diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index 6b1f169563..11754e70fa 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -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; } diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c index 06d4928ae5..08700a8a2f 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c @@ -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 }, diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h index 805f1581f1..ed41a3eab0 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h @@ -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); diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index b9f8161b9c..64fdd8b182 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -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) { diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_write_wired_auto_negotiate_on.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_write_wired_auto_negotiate_on.cexpected index 426085765c..39fdce8683 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_write_wired_auto_negotiate_on.cexpected +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_write_wired_auto_negotiate_on.cexpected @@ -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 diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index d0b9ffb8d3..34d4061b1a 100644 --- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -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]); }