diff options
Diffstat (limited to 'src/libnm-core-impl/nm-setting-ethtool.c')
-rw-r--r-- | src/libnm-core-impl/nm-setting-ethtool.c | 378 |
1 files changed, 378 insertions, 0 deletions
diff --git a/src/libnm-core-impl/nm-setting-ethtool.c b/src/libnm-core-impl/nm-setting-ethtool.c new file mode 100644 index 0000000000..db459697db --- /dev/null +++ b/src/libnm-core-impl/nm-setting-ethtool.c @@ -0,0 +1,378 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2018 Red Hat, Inc. + */ + +#include "libnm-core-impl/nm-default-libnm-core.h" + +#include "nm-setting-ethtool.h" + +#include "nm-setting-private.h" +#include "nm-base/nm-ethtool-base.h" + +/*****************************************************************************/ + +/** + * SECTION:nm-setting-ethtool + * @short_description: Describes connection properties for ethtool related options + * + * The #NMSettingEthtool object is a #NMSetting subclass that describes properties + * to control network driver and hardware settings. + **/ + +/*****************************************************************************/ + +static const GVariantType * +get_variant_type_from_ethtool_id(NMEthtoolID ethtool_id) +{ + if (nm_ethtool_id_is_feature(ethtool_id)) + return G_VARIANT_TYPE_BOOLEAN; + + if (nm_ethtool_id_is_coalesce(ethtool_id) || nm_ethtool_id_is_ring(ethtool_id)) + return G_VARIANT_TYPE_UINT32; + + return NULL; +} + +/*****************************************************************************/ + +/** + * nm_ethtool_optname_is_feature: + * @optname: (allow-none): the option name to check + * + * Checks whether @optname is a valid option name for an offload feature. + * + * %Returns: %TRUE, if @optname is valid + * + * Since: 1.20 + * + * Note that nm_ethtool_optname_is_feature() was first added to the libnm header files + * in 1.14.0 but forgot to actually add to the library. This happened belatedly in 1.20.0 and + * the stable versions 1.18.2, 1.16.4 and 1.14.8 (with linker version "libnm_1_14_8"). + */ +gboolean +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)); +} + +/** + * nm_ethtool_optname_is_ring: + * @optname: (allow-none): the option name to check + * + * Checks whether @optname is a valid option name for a ring setting. + * + * %Returns: %TRUE, if @optname is valid + * + * Since: 1.26 + */ +gboolean +nm_ethtool_optname_is_ring(const char *optname) +{ + return optname && nm_ethtool_id_is_ring(nm_ethtool_id_get_by_name(optname)); +} + +/*****************************************************************************/ + +/** + * NMSettingEthtool: + * + * Ethtool Ethernet Settings + * + * Since: 1.14 + */ +struct _NMSettingEthtool { + NMSetting parent; +}; + +struct _NMSettingEthtoolClass { + NMSettingClass parent; +}; + +G_DEFINE_TYPE(NMSettingEthtool, nm_setting_ethtool, NM_TYPE_SETTING) + +#define NM_SETTING_ETHTOOL_GET_PRIVATE(self) \ + _NM_GET_PRIVATE(self, NMSettingEthtool, NM_IS_SETTING_ETHTOOL, NMSetting) + +/*****************************************************************************/ + +/** + * nm_setting_ethtool_get_feature: + * @setting: the #NMSettingEthtool + * @optname: option name of the offload feature to get + * + * Gets and offload feature setting. Returns %NM_TERNARY_DEFAULT if the + * feature is not set. + * + * Note that @optname must be a valid name for a feature, according to + * nm_ethtool_optname_is_feature(). + * + * Returns: a #NMTernary value indicating whether the offload feature + * is enabled, disabled, or left untouched. + * + * Since: 1.14 + * + * Deprecated: 1.26: use nm_setting_option_get_boolean() instead. + */ +NMTernary +nm_setting_ethtool_get_feature(NMSettingEthtool *setting, const char *optname) +{ + gboolean v; + + g_return_val_if_fail(NM_IS_SETTING_ETHTOOL(setting), NM_TERNARY_DEFAULT); + g_return_val_if_fail(optname && nm_ethtool_optname_is_feature(optname), NM_TERNARY_DEFAULT); + + if (!nm_setting_option_get_boolean(NM_SETTING(setting), optname, &v)) + return NM_TERNARY_DEFAULT; + return v ? NM_TERNARY_TRUE : NM_TERNARY_FALSE; +} + +/** + * nm_setting_ethtool_set_feature: + * @setting: the #NMSettingEthtool + * @optname: option name of the offload feature to get + * @value: the new value to set. The special value %NM_TERNARY_DEFAULT + * means to clear the offload feature setting. + * + * Sets and offload feature setting. + * + * Note that @optname must be a valid name for a feature, according to + * nm_ethtool_optname_is_feature(). + * + * Since: 1.14 + * + * Deprecated: 1.26: use nm_setting_option_set() or nm_setting_option_set_boolean() instead. + */ +void +nm_setting_ethtool_set_feature(NMSettingEthtool *setting, const char *optname, NMTernary value) +{ + g_return_if_fail(NM_IS_SETTING_ETHTOOL(setting)); + g_return_if_fail(optname && nm_ethtool_optname_is_feature(optname)); + g_return_if_fail(NM_IN_SET(value, NM_TERNARY_DEFAULT, NM_TERNARY_FALSE, NM_TERNARY_TRUE)); + + if (value == NM_TERNARY_DEFAULT) + nm_setting_option_set(NM_SETTING(setting), optname, NULL); + else + nm_setting_option_set_boolean(NM_SETTING(setting), optname, (value != NM_TERNARY_FALSE)); +} + +/** + * nm_setting_ethtool_clear_features: + * @setting: the #NMSettingEthtool + * + * Clears all offload features settings + * + * Since: 1.14 + * + * Deprecated: 1.26: use nm_setting_option_clear_by_name() with nm_ethtool_optname_is_feature() predicate instead. + */ +void +nm_setting_ethtool_clear_features(NMSettingEthtool *setting) +{ + g_return_if_fail(NM_IS_SETTING_ETHTOOL(setting)); + + nm_setting_option_clear_by_name(NM_SETTING(setting), nm_ethtool_optname_is_feature); +} + +/*****************************************************************************/ + +guint +nm_setting_ethtool_init_features( + NMSettingEthtool *setting, + NMOptionBool * requested /* indexed by NMEthtoolID - _NM_ETHTOOL_ID_FEATURE_FIRST */) +{ + GHashTable * hash; + GHashTableIter iter; + guint i; + guint n_req = 0; + const char * name; + GVariant * variant; + + nm_assert(NM_IS_SETTING_ETHTOOL(setting)); + nm_assert(requested); + + for (i = 0; i < _NM_ETHTOOL_ID_FEATURE_NUM; i++) + requested[i] = NM_OPTION_BOOL_DEFAULT; + + hash = _nm_setting_option_hash(NM_SETTING(setting), FALSE); + if (!hash) + return 0; + + g_hash_table_iter_init(&iter, hash); + while (g_hash_table_iter_next(&iter, (gpointer *) &name, (gpointer *) &variant)) { + NMEthtoolID ethtool_id = nm_ethtool_id_get_by_name(name); + + if (!nm_ethtool_id_is_feature(ethtool_id)) + continue; + if (!g_variant_is_of_type(variant, G_VARIANT_TYPE_BOOLEAN)) + continue; + + requested[_NM_ETHTOOL_ID_FEATURE_AS_IDX(ethtool_id)] = + g_variant_get_boolean(variant) ? NM_OPTION_BOOL_TRUE : NM_OPTION_BOOL_FALSE; + n_req++; + } + + return n_req; +} + +/*****************************************************************************/ + +/** + * nm_setting_ethtool_get_optnames: + * @setting: the #NMSettingEthtool instance. + * @out_length: (out) (optional): return location for the number of keys returned, or %NULL + * + * This returns all options names that are set. This includes the feature names + * like %NM_ETHTOOL_OPTNAME_FEATURE_GRO. See nm_ethtool_optname_is_feature() to + * check whether the option name is valid for offload features. + * + * Returns: (array zero-terminated=1) (transfer container): list of set option + * names or %NULL if no options are set. The option names are still owned by + * @setting and may get invalidated when @setting gets modified. + * + * Since: 1.20 + * + * Deprecated: 1.26: use nm_setting_option_get_all_names() instead. + */ +const char ** +nm_setting_ethtool_get_optnames(NMSettingEthtool *setting, guint *out_length) +{ + const char *const *names; + guint len = 0; + + g_return_val_if_fail(NM_IS_SETTING_ETHTOOL(setting), NULL); + + names = nm_setting_option_get_all_names(NM_SETTING(setting), &len); + NM_SET_OUT(out_length, len); + return len > 0 ? nm_memdup(names, sizeof(names[0]) * (((gsize) len) + 1u)) : NULL; +} + +/*****************************************************************************/ + +static gboolean +verify(NMSetting *setting, NMConnection *connection, GError **error) +{ + const char *const *optnames; + GVariant *const * variants; + guint len; + guint i; + + len = _nm_setting_option_get_all(setting, &optnames, &variants); + + for (i = 0; i < len; i++) { + const char * optname = optnames[i]; + GVariant * variant = variants[i]; + const GVariantType *variant_type; + NMEthtoolID ethtool_id; + + ethtool_id = nm_ethtool_id_get_by_name(optname); + variant_type = get_variant_type_from_ethtool_id(ethtool_id); + + if (!variant_type) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("unsupported ethtool setting")); + g_prefix_error(error, "%s.%s: ", NM_SETTING_ETHTOOL_SETTING_NAME, optname); + return FALSE; + } + + if (!g_variant_is_of_type(variant, variant_type)) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("setting has invalid variant type")); + g_prefix_error(error, "%s.%s: ", NM_SETTING_ETHTOOL_SETTING_NAME, optname); + return FALSE; + } + + if (NM_IN_SET(ethtool_id, + NM_ETHTOOL_ID_COALESCE_ADAPTIVE_RX, + NM_ETHTOOL_ID_COALESCE_ADAPTIVE_TX)) { + if (!NM_IN_SET(g_variant_get_uint32(variant), 0, 1)) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("coalesce option must be either 0 or 1")); + g_prefix_error(error, "%s.%s: ", NM_SETTING_ETHTOOL_SETTING_NAME, optname); + return FALSE; + } + } + } + + return TRUE; +} + +/*****************************************************************************/ + +static const GVariantType * +get_variant_type(const NMSettInfoSetting *sett_info, const char *name, GError **error) +{ + const GVariantType *variant_type; + + variant_type = get_variant_type_from_ethtool_id(nm_ethtool_id_get_by_name(name)); + + if (!variant_type) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("unknown ethtool option '%s'"), + name); + return NULL; + } + + return variant_type; +} + +/*****************************************************************************/ + +static void +nm_setting_ethtool_init(NMSettingEthtool *setting) +{} + +/** + * nm_setting_ethtool_new: + * + * Creates a new #NMSettingEthtool object with default values. + * + * Returns: (transfer full): the new empty #NMSettingEthtool object + * + * Since: 1.14 + **/ +NMSetting * +nm_setting_ethtool_new(void) +{ + return g_object_new(NM_TYPE_SETTING_ETHTOOL, NULL); +} + +static void +nm_setting_ethtool_class_init(NMSettingEthtoolClass *klass) +{ + NMSettingClass *setting_class = NM_SETTING_CLASS(klass); + + setting_class->verify = verify; + + _nm_setting_class_commit_full( + setting_class, + NM_META_SETTING_TYPE_ETHTOOL, + NM_SETT_INFO_SETT_DETAIL(.gendata_info = + NM_SETT_INFO_SETT_GENDATA(.get_variant_type = + get_variant_type, ), ), + NULL); +} |