libnm, cli, ifcfg-rh: add NMSettingEthtool setting

Note that in NetworkManager API (D-Bus, libnm, and nmcli),
the features are called "feature-xyz". The "feature-" prefix
is used, because NMSettingEthtool possibly will gain support
for options that are not only -K|--offload|--features, for
example -C|--coalesce.

The "xzy" suffix is either how ethtool utility calls the feature
("tso", "rx"). Or, if ethtool utility specifies no alias for that
feature, it's the name from kernel's ETH_SS_FEATURES ("tx-tcp6-segmentation").
If possible, we prefer ethtool utility's naming.

Also note, how the features "feature-sg", "feature-tso", and
"feature-tx" actually refer to multiple underlying kernel features
at once. This too follows what ethtool utility does.

The functionality is not yet implemented server-side.
This commit is contained in:
Thomas Haller 2018-07-16 23:37:55 +02:00
parent 4e0f1b16b9
commit df30651b89
29 changed files with 1235 additions and 85 deletions

View file

@ -453,6 +453,7 @@ libnm_core_lib_h_pub_real = \
libnm-core/nm-setting-connection.h \
libnm-core/nm-setting-dcb.h \
libnm-core/nm-setting-dummy.h \
libnm-core/nm-setting-ethtool.h \
libnm-core/nm-setting-generic.h \
libnm-core/nm-setting-gsm.h \
libnm-core/nm-setting-infiniband.h \
@ -502,6 +503,7 @@ libnm_core_lib_h_priv = \
shared/nm-utils/nm-shared-utils.h \
shared/nm-utils/nm-random-utils.h \
shared/nm-utils/nm-udev-utils.h \
shared/nm-ethtool-utils.h \
shared/nm-meta-setting.h \
libnm-core/crypto.h \
libnm-core/nm-connection-private.h \
@ -524,6 +526,7 @@ libnm_core_lib_c_settings_real = \
libnm-core/nm-setting-connection.c \
libnm-core/nm-setting-dcb.c \
libnm-core/nm-setting-dummy.c \
libnm-core/nm-setting-ethtool.c \
libnm-core/nm-setting-generic.c \
libnm-core/nm-setting-gsm.c \
libnm-core/nm-setting-infiniband.c \
@ -565,6 +568,7 @@ libnm_core_lib_c_real = \
shared/nm-utils/nm-shared-utils.c \
shared/nm-utils/nm-random-utils.c \
shared/nm-utils/nm-udev-utils.c \
shared/nm-ethtool-utils.c \
shared/nm-meta-setting.c \
libnm-core/crypto.c \
libnm-core/nm-connection.c \
@ -2390,6 +2394,7 @@ EXTRA_DIST += \
src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-write-unknown-3.expected \
src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-write-unknown-4 \
src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-write-unknown-4.expected \
src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_write_wired_auto_negotiate_on.cexpected \
src/settings/plugins/ifcfg-rh/tests/network-scripts/keys-test-wifi-dynamic-wep-leap \
src/settings/plugins/ifcfg-rh/tests/network-scripts/keys-test-wifi-leap \
src/settings/plugins/ifcfg-rh/tests/network-scripts/keys-test-wifi-wep \
@ -3425,6 +3430,9 @@ clients_common_libnmc_la_SOURCES = \
shared/nm-meta-setting.c \
shared/nm-meta-setting.h \
\
shared/nm-ethtool-utils.c \
shared/nm-ethtool-utils.h \
\
clients/common/nm-meta-setting-desc.c \
clients/common/nm-meta-setting-desc.h \
clients/common/nm-meta-setting-access.c \

View file

@ -770,7 +770,8 @@ const NmcMetaGenericInfo *const metagen_con_active_vpn[_NMC_GENERIC_INFO_TYPE_CO
NM_SETTING_6LOWPAN_SETTING_NAME","\
NM_SETTING_PROXY_SETTING_NAME"," \
NM_SETTING_TC_CONFIG_SETTING_NAME"," \
NM_SETTING_SRIOV_SETTING_NAME
NM_SETTING_SRIOV_SETTING_NAME"," \
NM_SETTING_ETHTOOL_SETTING_NAME
// NM_SETTING_DUMMY_SETTING_NAME
// NM_SETTING_WIMAX_SETTING_NAME

View file

@ -59,7 +59,7 @@ libnmc = static_library(
sources: files(
'nm-meta-setting-access.c',
'nm-meta-setting-desc.c'
) + shared_nm_meta_setting_c + [settings_docs_source],
) + shared_nm_meta_setting_c + shared_nm_ethtool_utils_c + [settings_docs_source],
dependencies: deps,
c_args: cflags,
link_with: libnmc_base,

View file

@ -4823,6 +4823,84 @@ _validate_fcn_wireless_security_psk (const char *value, char **out_to_free, GErr
/*****************************************************************************/
static gconstpointer
_get_fcn_ethtool (ARGS_GET_FCN)
{
const char *s;
NMTernary val;
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 (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;
}
static gboolean
_set_fcn_ethtool (ARGS_SET_FCN)
{
gs_free char *value_clone = NULL;
NMTernary val;
NMEthtoolID ethtool_id = property_info->property_typ_data->subtype.ethtool.ethtool_id;
value = nm_strstrip_avoid_copy (value, &value_clone);
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;
}
nm_setting_ethtool_set_feature (NM_SETTING_ETHTOOL (setting),
nm_ethtool_data[ethtool_id]->optname,
val);
return TRUE;
}
static const char *const*
_complete_fcn_ethtool (ARGS_COMPLETE_FCN)
{
static const char *const v[] = {
"true",
"false",
"1",
"0",
"yes",
"no",
"default",
"on",
"off",
"ignore",
NULL,
};
if (!text || !text[0])
return &v[7];
return v;
}
/*****************************************************************************/
static const NMMetaPropertyInfo property_info_BOND_OPTIONS;
#define NESTED_PROPERTY_INFO_BOND(...) \
@ -4979,6 +5057,12 @@ static const NMMetaPropertyType _pt_gobject_devices = {
.complete_fcn = _complete_fcn_gobject_devices,
};
static const NMMetaPropertyType _pt_ethtool = {
.get_fcn = _get_fcn_ethtool,
.set_fcn = _set_fcn_ethtool,
.complete_fcn = _complete_fcn_ethtool,
};
/*****************************************************************************/
#include "settings-docs.h"
@ -5775,6 +5859,31 @@ static const NMMetaPropertyInfo *const property_infos_DCB[] = {
NULL
};
#define PROPERTY_INFO_ETHTOOL(xname) \
PROPERTY_INFO (NM_ETHTOOL_OPTNAME_##xname, NULL, \
.property_type = &_pt_ethtool, \
.property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (ethtool, \
.ethtool_id = NM_ETHTOOL_ID_##xname, \
), \
)
#undef _CURRENT_NM_META_SETTING_TYPE
#define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_ETHTOOL
static const NMMetaPropertyInfo *const property_infos_ETHTOOL[] = {
PROPERTY_INFO_ETHTOOL (FEATURE_GRO),
PROPERTY_INFO_ETHTOOL (FEATURE_GSO),
PROPERTY_INFO_ETHTOOL (FEATURE_LRO),
PROPERTY_INFO_ETHTOOL (FEATURE_NTUPLE),
PROPERTY_INFO_ETHTOOL (FEATURE_RX),
PROPERTY_INFO_ETHTOOL (FEATURE_RXHASH),
PROPERTY_INFO_ETHTOOL (FEATURE_RXVLAN),
PROPERTY_INFO_ETHTOOL (FEATURE_SG),
PROPERTY_INFO_ETHTOOL (FEATURE_TSO),
PROPERTY_INFO_ETHTOOL (FEATURE_TX),
PROPERTY_INFO_ETHTOOL (FEATURE_TXVLAN),
NULL,
};
#undef _CURRENT_NM_META_SETTING_TYPE
#define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_GSM
static const NMMetaPropertyInfo *const property_infos_GSM[] = {
@ -7740,6 +7849,7 @@ _setting_init_fcn_wireless (ARGS_SETTING_INIT_FCN)
#define SETTING_PRETTY_NAME_CONNECTION N_("General settings")
#define SETTING_PRETTY_NAME_DCB N_("DCB settings")
#define SETTING_PRETTY_NAME_DUMMY N_("Dummy settings")
#define SETTING_PRETTY_NAME_ETHTOOL N_("Ethtool settings")
#define SETTING_PRETTY_NAME_GENERIC N_("Generic settings")
#define SETTING_PRETTY_NAME_GSM N_("GSM mobile broadband connection")
#define SETTING_PRETTY_NAME_INFINIBAND N_("InfiniBand connection")
@ -7827,6 +7937,7 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = {
NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE),
NM_META_SETTING_VALID_PART_ITEM (BOND, TRUE),
NM_META_SETTING_VALID_PART_ITEM (WIRED, FALSE),
NM_META_SETTING_VALID_PART_ITEM (ETHTOOL, FALSE),
),
),
SETTING_INFO (BRIDGE,
@ -7834,6 +7945,7 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = {
NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE),
NM_META_SETTING_VALID_PART_ITEM (BRIDGE, TRUE),
NM_META_SETTING_VALID_PART_ITEM (WIRED, FALSE),
NM_META_SETTING_VALID_PART_ITEM (ETHTOOL, FALSE),
),
),
SETTING_INFO (BRIDGE_PORT),
@ -7848,11 +7960,13 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = {
),
SETTING_INFO (CONNECTION),
SETTING_INFO (DCB),
SETTING_INFO (ETHTOOL),
SETTING_INFO_EMPTY (DUMMY,
.valid_parts = NM_META_SETTING_VALID_PARTS (
NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE),
NM_META_SETTING_VALID_PART_ITEM (DUMMY, TRUE),
NM_META_SETTING_VALID_PART_ITEM (WIRED, FALSE),
NM_META_SETTING_VALID_PART_ITEM (ETHTOOL, FALSE),
),
),
SETTING_INFO_EMPTY (GENERIC,
@ -7875,6 +7989,7 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = {
NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE),
NM_META_SETTING_VALID_PART_ITEM (INFINIBAND, TRUE),
NM_META_SETTING_VALID_PART_ITEM (SRIOV, FALSE),
NM_META_SETTING_VALID_PART_ITEM (ETHTOOL, FALSE),
),
.setting_init_fcn = _setting_init_fcn_infiniband,
),
@ -7889,6 +8004,7 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = {
NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE),
NM_META_SETTING_VALID_PART_ITEM (IP_TUNNEL, TRUE),
NM_META_SETTING_VALID_PART_ITEM (WIRED, FALSE),
NM_META_SETTING_VALID_PART_ITEM (ETHTOOL, FALSE),
),
),
SETTING_INFO (MACSEC,
@ -7897,6 +8013,7 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = {
NM_META_SETTING_VALID_PART_ITEM (MACSEC, TRUE),
NM_META_SETTING_VALID_PART_ITEM (WIRED, FALSE),
NM_META_SETTING_VALID_PART_ITEM (802_1X, FALSE),
NM_META_SETTING_VALID_PART_ITEM (ETHTOOL, FALSE),
),
),
SETTING_INFO (MACVLAN,
@ -7904,6 +8021,7 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = {
NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE),
NM_META_SETTING_VALID_PART_ITEM (MACVLAN, TRUE),
NM_META_SETTING_VALID_PART_ITEM (WIRED, FALSE),
NM_META_SETTING_VALID_PART_ITEM (ETHTOOL, FALSE),
),
),
SETTING_INFO (OLPC_MESH,
@ -7928,6 +8046,7 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = {
NM_META_SETTING_VALID_PART_ITEM (IP4_CONFIG, FALSE),
NM_META_SETTING_VALID_PART_ITEM (IP6_CONFIG, FALSE),
NM_META_SETTING_VALID_PART_ITEM (WIRED, FALSE),
NM_META_SETTING_VALID_PART_ITEM (ETHTOOL, FALSE),
),
),
SETTING_INFO (OVS_PATCH),
@ -7947,6 +8066,7 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = {
NM_META_SETTING_VALID_PART_ITEM (WIRED, TRUE),
NM_META_SETTING_VALID_PART_ITEM (PPP, FALSE),
NM_META_SETTING_VALID_PART_ITEM (802_1X, FALSE),
NM_META_SETTING_VALID_PART_ITEM (ETHTOOL, FALSE),
),
),
SETTING_INFO (PPP),
@ -7961,6 +8081,7 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = {
NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE),
NM_META_SETTING_VALID_PART_ITEM (TEAM, TRUE),
NM_META_SETTING_VALID_PART_ITEM (WIRED, FALSE),
NM_META_SETTING_VALID_PART_ITEM (ETHTOOL, FALSE),
),
),
SETTING_INFO (TEAM_PORT),
@ -7969,6 +8090,7 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = {
NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE),
NM_META_SETTING_VALID_PART_ITEM (TUN, TRUE),
NM_META_SETTING_VALID_PART_ITEM (WIRED, FALSE),
NM_META_SETTING_VALID_PART_ITEM (ETHTOOL, FALSE),
),
.setting_init_fcn = _setting_init_fcn_tun,
),
@ -7978,6 +8100,7 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = {
NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE),
NM_META_SETTING_VALID_PART_ITEM (VLAN, TRUE),
NM_META_SETTING_VALID_PART_ITEM (WIRED, FALSE),
NM_META_SETTING_VALID_PART_ITEM (ETHTOOL, FALSE),
),
.setting_init_fcn = _setting_init_fcn_vlan,
),
@ -7992,6 +8115,7 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = {
NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE),
NM_META_SETTING_VALID_PART_ITEM (VXLAN, TRUE),
NM_META_SETTING_VALID_PART_ITEM (WIRED, FALSE),
NM_META_SETTING_VALID_PART_ITEM (ETHTOOL, FALSE),
),
),
SETTING_INFO (WIMAX,
@ -8008,6 +8132,7 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = {
NM_META_SETTING_VALID_PART_ITEM (802_1X, FALSE),
NM_META_SETTING_VALID_PART_ITEM (DCB, FALSE),
NM_META_SETTING_VALID_PART_ITEM (SRIOV, FALSE),
NM_META_SETTING_VALID_PART_ITEM (ETHTOOL, FALSE),
),
),
SETTING_INFO (WIRELESS,
@ -8017,6 +8142,7 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = {
NM_META_SETTING_VALID_PART_ITEM (WIRELESS, TRUE),
NM_META_SETTING_VALID_PART_ITEM (WIRELESS_SECURITY, FALSE),
NM_META_SETTING_VALID_PART_ITEM (802_1X, FALSE),
NM_META_SETTING_VALID_PART_ITEM (ETHTOOL, FALSE),
),
.setting_init_fcn = _setting_init_fcn_wireless,
),

View file

@ -22,6 +22,7 @@
#include "nm-utils/nm-obj.h"
#include "nm-meta-setting.h"
#include "nm-ethtool-utils.h"
struct _NMDevice;
@ -263,6 +264,9 @@ struct _NMMetaPropertyTypData {
struct {
NMMetaPropertyTypeMacMode mode;
} mac;
struct {
NMEthtoolID ethtool_id;
} ethtool;
} subtype;
const char *const*values_static;
const NMMetaPropertyTypDataNested *nested;

View file

@ -202,6 +202,7 @@ print ("NetworkManager version " + client.get_version())]]></programlisting></in
<xi:include href="xml/nm-setting-cdma.xml"/>
<xi:include href="xml/nm-setting-dcb.xml"/>
<xi:include href="xml/nm-setting-dummy.xml"/>
<xi:include href="xml/nm-setting-ethtool.xml"/>
<xi:include href="xml/nm-setting-generic.xml"/>
<xi:include href="xml/nm-setting-gsm.xml"/>
<xi:include href="xml/nm-setting-infiniband.xml"/>

View file

@ -69,6 +69,7 @@ libnm_core_settings_sources = files(
'nm-setting-connection.c',
'nm-setting-dcb.c',
'nm-setting-dummy.c',
'nm-setting-ethtool.c',
'nm-setting-generic.c',
'nm-setting-gsm.c',
'nm-setting-infiniband.c',
@ -154,6 +155,7 @@ endif
libnm_core_sources_all = libnm_core_sources
libnm_core_sources_all += libnm_core_enum
libnm_core_sources_all += shared_nm_meta_setting_c
libnm_core_sources_all += shared_nm_ethtool_utils_c
libnm_core_sources_all += shared_files_libnm_core
libnm_core_sources_all += [version_header]

View file

@ -201,6 +201,11 @@ GVariant *const*nm_setting_gendata_get_all_values (NMSetting *setting);
/*****************************************************************************/
guint nm_setting_ethtool_init_features (NMSettingEthtool *setting,
NMTernary *requested /* indexed by NMEthtoolID - _NM_ETHTOOL_ID_FEATURE_FIRST */);
/*****************************************************************************/
#define NM_UTILS_HWADDR_LEN_MAX_STR (NM_UTILS_HWADDR_LEN_MAX * 3)
guint8 *_nm_utils_hwaddr_aton (const char *asc, gpointer buffer, gsize buffer_length, gsize *out_length);

View file

@ -40,6 +40,7 @@ typedef struct _NMSettingCdma NMSettingCdma;
typedef struct _NMSettingConnection NMSettingConnection;
typedef struct _NMSettingDcb NMSettingDcb;
typedef struct _NMSettingDummy NMSettingDummy;
typedef struct _NMSettingEthtool NMSettingEthtool;
typedef struct _NMSettingGeneric NMSettingGeneric;
typedef struct _NMSettingGsm NMSettingGsm;
typedef struct _NMSettingInfiniband NMSettingInfiniband;

View file

@ -0,0 +1,342 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* Copyright 2018 Red Hat, Inc.
*/
#include "nm-default.h"
#include "nm-setting-ethtool.h"
#include "nm-setting-private.h"
#include "nm-ethtool-utils.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.
**/
/*****************************************************************************/
/**
* nm_ethtool_optname_is_feature:
* @optname: 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.14
*/
gboolean
nm_ethtool_optname_is_feature (const char *optname)
{
return optname && nm_ethtool_id_is_feature (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)
/*****************************************************************************/
static void
_notify_attributes (NMSettingEthtool *self)
{
_nm_setting_gendata_notify (NM_SETTING (self), TRUE);
}
/*****************************************************************************/
/**
* 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.
*
* Returns: a #NMTernary value indicating whether the offload feature
* is enabled, disabled, or left untouched.
*
* Since: 1.14
*/
NMTernary
nm_setting_ethtool_get_feature (NMSettingEthtool *setting,
const char *optname)
{
GVariant *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);
v = nm_setting_gendata_get (NM_SETTING (setting), optname);
if ( v
&& g_variant_is_of_type (v, G_VARIANT_TYPE_BOOLEAN)) {
return g_variant_get_boolean (v)
? NM_TERNARY_TRUE
: NM_TERNARY_FALSE;
}
return NM_TERNARY_DEFAULT;
}
/**
* 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.
*
* Since: 1.14
*/
void
nm_setting_ethtool_set_feature (NMSettingEthtool *setting,
const char *optname,
NMTernary value)
{
GHashTable *hash;
GVariant *v;
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));
hash = _nm_setting_gendata_hash (NM_SETTING (setting),
value != NM_TERNARY_DEFAULT);
if (value == NM_TERNARY_DEFAULT) {
if (hash) {
if (g_hash_table_remove (hash, optname))
_notify_attributes (setting);
}
return;
}
v = g_hash_table_lookup (hash, optname);
if ( v
&& g_variant_is_of_type (v, G_VARIANT_TYPE_BOOLEAN)) {
if (g_variant_get_boolean (v)) {
if (value == NM_TERNARY_TRUE)
return;
} else {
if (value == NM_TERNARY_FALSE)
return;
}
}
v = g_variant_ref_sink (g_variant_new_boolean (value != NM_TERNARY_FALSE));
g_hash_table_insert (hash,
g_strdup (optname),
v);
_notify_attributes (setting);
}
/**
* nm_setting_ethtool_clear_features:
* @setting: the #NMSettingEthtool
*
* Clears all offload features settings
*
* Since: 1.14
*/
void
nm_setting_ethtool_clear_features (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_feature (name)) {
g_hash_table_iter_remove (&iter);
changed = TRUE;
}
}
if (changed)
_notify_attributes (setting);
}
guint
nm_setting_ethtool_init_features (NMSettingEthtool *setting,
NMTernary *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_TERNARY_DEFAULT;
hash = _nm_setting_gendata_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[ethtool_id - _NM_ETHTOOL_ID_FEATURE_FIRST] = g_variant_get_boolean (variant)
? NM_TERNARY_TRUE
: NM_TERNARY_FALSE;
n_req++;
}
return n_req;
}
/*****************************************************************************/
static gboolean
verify (NMSetting *setting, NMConnection *connection, GError **error)
{
GHashTable *hash;
GHashTableIter iter;
const char *optname;
GVariant *variant;
hash = _nm_setting_gendata_hash (setting, FALSE);
if (!hash)
goto out;
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)) {
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"));
g_prefix_error (error, "%s.%s: ", NM_SETTING_ETHTOOL_SETTING_NAME, optname);
return FALSE;
}
}
out:
return TRUE;
}
/*****************************************************************************/
static const GVariantType *
get_variant_type (const NMSettInfoSetting *sett_info,
const char *name,
GError **error)
{
if (nm_ethtool_optname_is_feature (name))
return G_VARIANT_TYPE_BOOLEAN;
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("unknown ethtool option '%s'"),
name);
return NULL;
}
/*****************************************************************************/
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);
}

View file

@ -0,0 +1,83 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* Copyright 2018 Red Hat, Inc.
*/
#ifndef __NM_SETTING_ETHTOOL_H__
#define __NM_SETTING_ETHTOOL_H__
#if !defined (__NETWORKMANAGER_H_INSIDE__) && !defined (NETWORKMANAGER_COMPILATION)
#error "Only <NetworkManager.h> can be included directly."
#endif
#include "nm-setting.h"
G_BEGIN_DECLS
/*****************************************************************************/
#define NM_ETHTOOL_OPTNAME_FEATURE_GRO "feature-gro"
#define NM_ETHTOOL_OPTNAME_FEATURE_GSO "feature-gso"
#define NM_ETHTOOL_OPTNAME_FEATURE_LRO "feature-lro"
#define NM_ETHTOOL_OPTNAME_FEATURE_NTUPLE "feature-ntuple"
#define NM_ETHTOOL_OPTNAME_FEATURE_RX "feature-rx"
#define NM_ETHTOOL_OPTNAME_FEATURE_RXHASH "feature-rxhash"
#define NM_ETHTOOL_OPTNAME_FEATURE_RXVLAN "feature-rxvlan"
#define NM_ETHTOOL_OPTNAME_FEATURE_SG "feature-sg"
#define NM_ETHTOOL_OPTNAME_FEATURE_TSO "feature-tso"
#define NM_ETHTOOL_OPTNAME_FEATURE_TX "feature-tx"
#define NM_ETHTOOL_OPTNAME_FEATURE_TXVLAN "feature-txvlan"
gboolean nm_ethtool_optname_is_feature (const char *optname);
/*****************************************************************************/
#define NM_TYPE_SETTING_ETHTOOL (nm_setting_ethtool_get_type ())
#define NM_SETTING_ETHTOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTING_ETHTOOL, NMSettingEthtool))
#define NM_SETTING_ETHTOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SETTING_ETHTOOL, NMSettingEthtoolClass))
#define NM_IS_SETTING_ETHTOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SETTING_ETHTOOL))
#define NM_IS_SETTING_ETHTOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SETTING_ETHTOOL))
#define NM_SETTING_ETHTOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SETTING_ETHTOOL, NMSettingEthtoolClass))
#define NM_SETTING_ETHTOOL_SETTING_NAME "ethtool"
/*****************************************************************************/
typedef struct _NMSettingEthtoolClass NMSettingEthtoolClass;
NM_AVAILABLE_IN_1_14
GType nm_setting_ethtool_get_type (void);
NM_AVAILABLE_IN_1_14
NMSetting *nm_setting_ethtool_new (void);
/*****************************************************************************/
NM_AVAILABLE_IN_1_14
NMTernary nm_setting_ethtool_get_feature (NMSettingEthtool *setting,
const char *optname);
NM_AVAILABLE_IN_1_14
void nm_setting_ethtool_set_feature (NMSettingEthtool *setting,
const char *optname,
NMTernary value);
NM_AVAILABLE_IN_1_14
void nm_setting_ethtool_clear_features (NMSettingEthtool *setting);
G_END_DECLS
#endif /* __NM_SETTING_ETHTOOL_H__ */

View file

@ -2095,6 +2095,20 @@ _nm_setting_gendata_notify (NMSetting *setting,
* values cache. Otherwise, the names cache must be invalidated too. */
nm_clear_g_free (&gendata->names);
}
/* Note, that currently there is now way to notify the subclass when gendata changed.
* gendata is only changed in two situations:
* 1) from within NMSetting itself, for example when creating a NMSetting instance
* from keyfile or a D-Bus GVariant.
* 2) actively from the subclass itself
* For 2), we don't need the notification, because the subclass knows that something
* changed.
* For 1), we currently don't need the notification either, because all that the subclass
* currently would do, is emit a g_object_notify() signal. However, 1) only happens when
* the setting instance is newly created, at that point, nobody listens to the signal.
*
* If we ever need it, then we would need to call a virtual function to notify the subclass
* that gendata changed. */
}
GVariant *

View file

@ -43,6 +43,7 @@
#include "nm-setting-bridge-port.h"
#include "nm-setting-cdma.h"
#include "nm-setting-connection.h"
#include "nm-setting-ethtool.h"
#include "nm-setting-generic.h"
#include "nm-setting-gsm.h"
#include "nm-setting-infiniband.h"
@ -65,6 +66,7 @@
#include "nm-simple-connection.h"
#include "nm-keyfile-internal.h"
#include "nm-utils/nm-dedup-multi.h"
#include "nm-ethtool-utils.h"
#include "test-general-enums.h"
@ -7058,6 +7060,22 @@ test_nm_va_args_macros (void)
/*****************************************************************************/
static void
test_ethtool_offload (void)
{
const NMEthtoolData *d;
g_assert_cmpint (nm_ethtool_id_get_by_name ("invalid"), ==, NM_ETHTOOL_ID_UNKNOWN);
g_assert_cmpint (nm_ethtool_id_get_by_name ("feature-rx"), ==, NM_ETHTOOL_ID_FEATURE_RX);
d = nm_ethtool_data_get_by_optname (NM_ETHTOOL_OPTNAME_FEATURE_RXHASH);
g_assert (d);
g_assert_cmpint (d->id, ==, NM_ETHTOOL_ID_FEATURE_RXHASH);
g_assert_cmpstr (d->optname, ==, NM_ETHTOOL_OPTNAME_FEATURE_RXHASH);
}
/*****************************************************************************/
NMTST_DEFINE ();
int main (int argc, char **argv)
@ -7212,8 +7230,8 @@ int main (int argc, char **argv)
g_test_add_func ("/core/general/route_attributes/format", test_route_attributes_format);
g_test_add_func ("/core/general/get_start_time_for_pid", test_get_start_time_for_pid);
g_test_add_func ("/core/general/test_nm_va_args_macros", test_nm_va_args_macros);
g_test_add_func ("/core/general/test_ethtool_offload", test_ethtool_offload);
return g_test_run ();
}

View file

@ -28,6 +28,7 @@
#include "nm-setting-8021x.h"
#include "nm-setting-bond.h"
#include "nm-setting-dcb.h"
#include "nm-setting-ethtool.h"
#include "nm-setting-team.h"
#include "nm-setting-team-port.h"
#include "nm-setting-tc-config.h"
@ -36,6 +37,7 @@
#include "nm-simple-connection.h"
#include "nm-setting-connection.h"
#include "nm-errors.h"
#include "nm-keyfile-internal.h"
#include "nm-utils/nm-test-utils.h"
@ -1264,6 +1266,79 @@ test_team_port_full_config (void)
/*****************************************************************************/
static void
test_ethtool_1 (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;
con = nmtst_create_minimal_connection ("ethtool-1",
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_feature (s_ethtool,
NM_ETHTOOL_OPTNAME_FEATURE_RX,
NM_TERNARY_TRUE);
nm_setting_ethtool_set_feature (s_ethtool,
NM_ETHTOOL_OPTNAME_FEATURE_LRO,
NM_TERNARY_FALSE);
g_assert_cmpint (nm_setting_ethtool_get_feature (s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_RX), ==, NM_TERNARY_TRUE);
g_assert_cmpint (nm_setting_ethtool_get_feature (s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_LRO), ==, NM_TERNARY_FALSE);
g_assert_cmpint (nm_setting_ethtool_get_feature (s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_SG), ==, NM_TERNARY_DEFAULT);
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_cmpint (nm_setting_ethtool_get_feature (s_ethtool2, NM_ETHTOOL_OPTNAME_FEATURE_RX), ==, NM_TERNARY_TRUE);
g_assert_cmpint (nm_setting_ethtool_get_feature (s_ethtool2, NM_ETHTOOL_OPTNAME_FEATURE_LRO), ==, NM_TERNARY_FALSE);
g_assert_cmpint (nm_setting_ethtool_get_feature (s_ethtool2, NM_ETHTOOL_OPTNAME_FEATURE_SG), ==, NM_TERNARY_DEFAULT);
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,
"ethtool-keyfile-name",
NULL,
NULL,
NULL,
&error);
nmtst_assert_success (con3, error);
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_cmpint (nm_setting_ethtool_get_feature (s_ethtool3, NM_ETHTOOL_OPTNAME_FEATURE_RX), ==, NM_TERNARY_TRUE);
g_assert_cmpint (nm_setting_ethtool_get_feature (s_ethtool3, NM_ETHTOOL_OPTNAME_FEATURE_LRO), ==, NM_TERNARY_FALSE);
g_assert_cmpint (nm_setting_ethtool_get_feature (s_ethtool3, NM_ETHTOOL_OPTNAME_FEATURE_SG), ==, NM_TERNARY_DEFAULT);
}
/*****************************************************************************/
static void
test_sriov_vf (void)
{
@ -1899,6 +1974,8 @@ main (int argc, char **argv)
g_test_add_func ("/libnm/settings/dcb/priorities", test_dcb_priorities_valid);
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/sriov/vf", test_sriov_vf);
g_test_add_func ("/libnm/settings/sriov/vf-dup", test_sriov_vf_dup);
g_test_add_func ("/libnm/settings/sriov/vf-vlan", test_sriov_vf_vlan);

View file

@ -72,6 +72,7 @@
#include "nm-setting-connection.h"
#include "nm-setting-dcb.h"
#include "nm-setting-dummy.h"
#include "nm-setting-ethtool.h"
#include "nm-setting-generic.h"
#include "nm-setting-gsm.h"
#include "nm-setting-infiniband.h"

View file

@ -1394,6 +1394,11 @@ global:
nm_device_wpan_get_type;
nm_setting_6lowpan_get_type;
nm_setting_connection_get_multi_connect;
nm_setting_ethtool_clear_features;
nm_setting_ethtool_get_feature;
nm_setting_ethtool_get_type;
nm_setting_ethtool_new;
nm_setting_ethtool_set_feature;
nm_setting_sriov_add_vf;
nm_setting_sriov_clear_vfs;
nm_setting_sriov_get_autoprobe_drivers;

View file

@ -47,6 +47,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (NMSettingCdma, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (NMSettingConnection, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (NMSettingDcb, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (NMSettingDummy, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (NMSettingEthtool, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (NMSettingGeneric, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (NMSettingGsm, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (NMSettingInfiniband, g_object_unref)

View file

@ -67,6 +67,7 @@ libnm-core/nm-setting-bridge.c
libnm-core/nm-setting-cdma.c
libnm-core/nm-setting-connection.c
libnm-core/nm-setting-dcb.c
libnm-core/nm-setting-ethtool.c
libnm-core/nm-setting-gsm.c
libnm-core/nm-setting-infiniband.c
libnm-core/nm-setting-ip-config.c

View file

@ -36,6 +36,8 @@ version_header = configure_file(
configuration: version_conf,
)
shared_nm_ethtool_utils_c = files('nm-ethtool-utils.c')
shared_nm_meta_setting_c = files('nm-meta-setting.c')
shared_nm_test_utils_impl_c = files('nm-test-utils-impl.c')

143
shared/nm-ethtool-utils.c Normal file
View file

@ -0,0 +1,143 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* Copyright 2018 Red Hat, Inc.
*/
#include "nm-default.h"
#include "nm-ethtool-utils.h"
#include "nm-setting-ethtool.h"
/*****************************************************************************/
#define ETHT_DATA(xname) \
[NM_ETHTOOL_ID_##xname] = (&((const NMEthtoolData) { \
.optname = NM_ETHTOOL_OPTNAME_##xname, \
.id = NM_ETHTOOL_ID_##xname, \
}))
const NMEthtoolData *const nm_ethtool_data[_NM_ETHTOOL_ID_NUM + 1] = {
/* indexed by NMEthtoolID */
ETHT_DATA (FEATURE_GRO),
ETHT_DATA (FEATURE_GSO),
ETHT_DATA (FEATURE_LRO),
ETHT_DATA (FEATURE_NTUPLE),
ETHT_DATA (FEATURE_RX),
ETHT_DATA (FEATURE_RXHASH),
ETHT_DATA (FEATURE_RXVLAN),
ETHT_DATA (FEATURE_SG),
ETHT_DATA (FEATURE_TSO),
ETHT_DATA (FEATURE_TX),
ETHT_DATA (FEATURE_TXVLAN),
[_NM_ETHTOOL_ID_NUM] = NULL,
};
const guint8 const _by_name[_NM_ETHTOOL_ID_NUM] = {
/* sorted by optname. */
NM_ETHTOOL_ID_FEATURE_GRO,
NM_ETHTOOL_ID_FEATURE_GSO,
NM_ETHTOOL_ID_FEATURE_LRO,
NM_ETHTOOL_ID_FEATURE_NTUPLE,
NM_ETHTOOL_ID_FEATURE_RX,
NM_ETHTOOL_ID_FEATURE_RXHASH,
NM_ETHTOOL_ID_FEATURE_RXVLAN,
NM_ETHTOOL_ID_FEATURE_SG,
NM_ETHTOOL_ID_FEATURE_TSO,
NM_ETHTOOL_ID_FEATURE_TX,
NM_ETHTOOL_ID_FEATURE_TXVLAN,
};
/*****************************************************************************/
static void
_ASSERT_data (void)
{
#if NM_MORE_ASSERTS > 10
int i;
G_STATIC_ASSERT_EXPR (_NM_ETHTOOL_ID_FIRST == 0);
G_STATIC_ASSERT_EXPR (_NM_ETHTOOL_ID_LAST == _NM_ETHTOOL_ID_NUM - 1);
G_STATIC_ASSERT_EXPR (_NM_ETHTOOL_ID_NUM > 0);
nm_assert (NM_PTRARRAY_LEN (nm_ethtool_data) == _NM_ETHTOOL_ID_NUM);
nm_assert (G_N_ELEMENTS (_by_name) == _NM_ETHTOOL_ID_NUM);
nm_assert (G_N_ELEMENTS (nm_ethtool_data) == _NM_ETHTOOL_ID_NUM + 1);
for (i = 0; i < _NM_ETHTOOL_ID_NUM; i++) {
const NMEthtoolData *d = nm_ethtool_data[i];
nm_assert (d);
nm_assert (d->id == (NMEthtoolID) i);
nm_assert (d->optname && d->optname[0]);
}
for (i = 0; i < _NM_ETHTOOL_ID_NUM; i++) {
NMEthtoolID id = _by_name[i];
const NMEthtoolData *d;
nm_assert (id >= 0);
nm_assert (id < _NM_ETHTOOL_ID_NUM);
d = nm_ethtool_data[id];
if (i > 0) {
/* since we assert that all optnames are sorted strictly monotonically increasing,
* it also follows that there are no duplicates in the _by_name.
* It also follows, that all names in nm_ethtool_data are unique. */
if (strcmp (nm_ethtool_data[_by_name[i - 1]]->optname, d->optname) >= 0) {
g_error ("nm_ethtool_data is not sorted asciibetically: %u/%s should be after %u/%s",
i - 1, nm_ethtool_data[_by_name[i - 1]]->optname,
i, d->optname);
}
}
}
#endif
}
static int
_by_name_cmp (gconstpointer a,
gconstpointer b,
gpointer user_data)
{
const guint8 *p_id = a;
const char *optname = b;
nm_assert (p_id && p_id >= _by_name && p_id <= &_by_name[_NM_ETHTOOL_ID_NUM]);
nm_assert (*p_id < _NM_ETHTOOL_ID_NUM);
return strcmp (nm_ethtool_data[*p_id]->optname, optname);
}
const NMEthtoolData *
nm_ethtool_data_get_by_optname (const char *optname)
{
gssize idx;
nm_assert (optname);
_ASSERT_data ();
idx = nm_utils_array_find_binary_search ((gconstpointer *) _by_name,
sizeof (_by_name[0]),
_NM_ETHTOOL_ID_NUM,
optname,
_by_name_cmp,
NULL);
return (idx < 0) ? NULL : nm_ethtool_data[_by_name[idx]];
}

79
shared/nm-ethtool-utils.h Normal file
View file

@ -0,0 +1,79 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* Copyright 2018 Red Hat, Inc.
*/
#ifndef __NM_ETHTOOL_UTILS_H__
#define __NM_ETHTOOL_UTILS_H__
/*****************************************************************************/
typedef enum {
NM_ETHTOOL_ID_UNKNOWN = -1,
_NM_ETHTOOL_ID_FIRST = 0,
_NM_ETHTOOL_ID_FEATURE_FIRST = _NM_ETHTOOL_ID_FIRST,
NM_ETHTOOL_ID_FEATURE_GRO = _NM_ETHTOOL_ID_FEATURE_FIRST,
NM_ETHTOOL_ID_FEATURE_GSO,
NM_ETHTOOL_ID_FEATURE_LRO,
NM_ETHTOOL_ID_FEATURE_NTUPLE,
NM_ETHTOOL_ID_FEATURE_RX,
NM_ETHTOOL_ID_FEATURE_RXHASH,
NM_ETHTOOL_ID_FEATURE_RXVLAN,
NM_ETHTOOL_ID_FEATURE_SG,
NM_ETHTOOL_ID_FEATURE_TSO,
NM_ETHTOOL_ID_FEATURE_TX,
NM_ETHTOOL_ID_FEATURE_TXVLAN,
_NM_ETHTOOL_ID_FEATURE_LAST = NM_ETHTOOL_ID_FEATURE_TXVLAN,
_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_NUM = (_NM_ETHTOOL_ID_LAST - _NM_ETHTOOL_ID_FIRST + 1),
} NMEthtoolID;
typedef struct {
const char *optname;
NMEthtoolID id;
} NMEthtoolData;
extern const NMEthtoolData *const nm_ethtool_data[/*_NM_ETHTOOL_ID_NUM + NULL-terminated*/];
const NMEthtoolData *nm_ethtool_data_get_by_optname (const char *optname);
/****************************************************************************/
static inline NMEthtoolID
nm_ethtool_id_get_by_name (const char *optname)
{
const NMEthtoolData *d;
d = nm_ethtool_data_get_by_optname (optname);
return d ? d->id : NM_ETHTOOL_ID_UNKNOWN;
}
static inline gboolean
nm_ethtool_id_is_feature (NMEthtoolID id)
{
return id >= _NM_ETHTOOL_ID_FEATURE_FIRST && id <= _NM_ETHTOOL_ID_FEATURE_LAST;
}
/****************************************************************************/
#endif /* __NM_ETHTOOL_UTILS_H__ */

View file

@ -34,6 +34,7 @@
#include "nm-setting-connection.h"
#include "nm-setting-dcb.h"
#include "nm-setting-dummy.h"
#include "nm-setting-ethtool.h"
#include "nm-setting-generic.h"
#include "nm-setting-gsm.h"
#include "nm-setting-infiniband.h"
@ -213,6 +214,12 @@ const NMMetaSettingInfo nm_meta_setting_infos[] = {
.setting_name = NM_SETTING_DUMMY_SETTING_NAME,
.get_setting_gtype = nm_setting_dummy_get_type,
},
[NM_META_SETTING_TYPE_ETHTOOL] = {
.meta_type = NM_META_SETTING_TYPE_ETHTOOL,
.setting_priority = NM_SETTING_PRIORITY_AUX,
.setting_name = NM_SETTING_ETHTOOL_SETTING_NAME,
.get_setting_gtype = nm_setting_ethtool_get_type,
},
[NM_META_SETTING_TYPE_GENERIC] = {
.meta_type = NM_META_SETTING_TYPE_GENERIC,
.setting_priority = NM_SETTING_PRIORITY_HW_BASE,

View file

@ -118,6 +118,7 @@ typedef enum {
NM_META_SETTING_TYPE_CONNECTION,
NM_META_SETTING_TYPE_DCB,
NM_META_SETTING_TYPE_DUMMY,
NM_META_SETTING_TYPE_ETHTOOL,
NM_META_SETTING_TYPE_GENERIC,
NM_META_SETTING_TYPE_GSM,
NM_META_SETTING_TYPE_INFINIBAND,

View file

@ -41,6 +41,7 @@
#include "nm-setting-ip6-config.h"
#include "nm-setting-wired.h"
#include "nm-setting-wireless.h"
#include "nm-setting-ethtool.h"
#include "nm-setting-8021x.h"
#include "nm-setting-bond.h"
#include "nm-setting-team.h"
@ -53,6 +54,7 @@
#include "nm-setting-generic.h"
#include "nm-core-internal.h"
#include "nm-utils.h"
#include "nm-ethtool-utils.h"
#include "platform/nm-platform.h"
#include "NetworkManagerUtils.h"
@ -4051,15 +4053,66 @@ parse_ethtool_option (const char *value,
char **out_password,
gboolean *out_autoneg,
guint32 *out_speed,
const char **out_duplex)
const char **out_duplex,
NMSettingEthtool **out_s_ethtool)
{
gs_free const char **words = NULL;
guint i;
words = nm_utils_strsplit_set (value, "\t \n");
words = nm_utils_strsplit_set (value, NULL);
if (!words)
return;
if (words[0] && words[0][0] == '-') {
/* /sbin/ethtool $opts */
if (NM_IN_STRSET (words[0], "-K", "--features", "--offload")) {
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;
NMTernary onoff = NM_TERNARY_DEFAULT;
if (nm_streq0 (opt_val, "on"))
onoff = NM_TERNARY_TRUE;
else if (nm_streq0 (opt_val, "off"))
onoff = NM_TERNARY_FALSE;
d = nms_ifcfg_rh_utils_get_ethtool_by_name (opt);
if (!d) {
if (onoff != NM_TERNARY_DEFAULT) {
/* the next value is just the on/off argument. Skip it too. */
i++;
}
/* silently ignore unsupported offloading features. */
continue;
}
i++;
if (onoff == NM_TERNARY_DEFAULT) {
PARSE_WARNING ("Expects on/off argument for feature '%s'", opt);
continue;
}
nm_setting_ethtool_set_feature (*out_s_ethtool,
d->optname,
onoff);
}
}
return;
}
/* /sbin/ethtool -s ${REALDEVICE} $opts */
for (i = 0; words[i]; ) {
const char *opt = words[i];
const char *opt_val = words[++i];
@ -4176,54 +4229,72 @@ parse_ethtool_option (const char *value,
}
static void
parse_ethtool_options (shvarFile *ifcfg, NMSettingWired *s_wired, const char *value)
parse_ethtool_options (shvarFile *ifcfg, NMConnection *connection)
{
NMSettingWired *s_wired;
gs_unref_object NMSettingEthtool *s_ethtool = NULL;
NMSettingWiredWakeOnLan wol_flags = NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT;
gs_free char *ethtool_opts_free = NULL;
const char *ethtool_opts;
gs_free char *wol_password = NULL;
gs_free char *wol_value = NULL;
gboolean ignore_wol_password = FALSE;
gs_free char *wol_value_free = NULL;
const char *tmp;
gboolean autoneg = FALSE;
guint32 speed = 0;
const char *duplex = NULL;
if (value) {
gs_free const char **opts = NULL;
const char *const *iter;
ethtool_opts = svGetValue (ifcfg, "ETHTOOL_OPTS", &ethtool_opts_free);
if (ethtool_opts) {
/* WAKE_ON_LAN_IGNORE is inferred from a specified but empty ETHTOOL_OPTS */
if (!value[0])
if (!ethtool_opts[0])
wol_flags = NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE;
else {
gs_free const char **opts = NULL;
const char *const *iter;
opts = nm_utils_strsplit_set (value, ";");
for (iter = opts; iter && iter[0]; iter++) {
/* in case of repeated wol_passwords, parse_ethtool_option()
* will do the right thing and clear wol_password before resetting. */
parse_ethtool_option (iter[0], &wol_flags, &wol_password, &autoneg, &speed, &duplex);
opts = nm_utils_strsplit_set (ethtool_opts, ";");
for (iter = opts; iter && iter[0]; iter++) {
/* in case of repeated wol_passwords, parse_ethtool_option()
* will do the right thing and clear wol_password before resetting. */
parse_ethtool_option (iter[0],
&wol_flags,
&wol_password,
&autoneg,
&speed,
&duplex,
&s_ethtool);
}
}
}
/* ETHTOOL_WAKE_ON_LAN = ignore overrides WoL settings in ETHTOOL_OPTS */
wol_value = svGetValueStr_cp (ifcfg, "ETHTOOL_WAKE_ON_LAN");
if (wol_value) {
if (strcmp (wol_value, "ignore") == 0)
wol_flags = NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE;
else
PARSE_WARNING ("invalid ETHTOOL_WAKE_ON_LAN value '%s'", wol_value);
}
tmp = svGetValueStr (ifcfg, "ETHTOOL_WAKE_ON_LAN", &wol_value_free);
if (nm_streq0 (tmp, "ignore"))
wol_flags = NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE;
else if (tmp)
PARSE_WARNING ("invalid ETHTOOL_WAKE_ON_LAN value '%s'", tmp);
if ( wol_password
&& !NM_FLAGS_HAS (wol_flags, NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC)) {
PARSE_WARNING ("Wake-on-LAN password not expected");
ignore_wol_password = TRUE;
nm_clear_g_free (&wol_password);
}
g_object_set (s_wired,
NM_SETTING_WIRED_WAKE_ON_LAN, wol_flags,
NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD, ignore_wol_password ? NULL : wol_password,
NM_SETTING_WIRED_AUTO_NEGOTIATE, autoneg,
NM_SETTING_WIRED_SPEED, speed,
NM_SETTING_WIRED_DUPLEX, duplex,
NULL);
s_wired = nm_connection_get_setting_wired (connection);
if (s_wired) {
g_object_set (s_wired,
NM_SETTING_WIRED_WAKE_ON_LAN, wol_flags,
NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD, wol_password,
NM_SETTING_WIRED_AUTO_NEGOTIATE, autoneg,
NM_SETTING_WIRED_SPEED, speed,
NM_SETTING_WIRED_DUPLEX, duplex,
NULL);
}
if (s_ethtool) {
nm_connection_add_setting (connection,
NM_SETTING (g_steal_pointer (&s_ethtool)));
}
}
static NMSetting *
@ -4365,10 +4436,6 @@ make_wired_setting (shvarFile *ifcfg,
nm_clear_g_free (&value);
}
parse_ethtool_options (ifcfg, s_wired,
svGetValue (ifcfg, "ETHTOOL_OPTS", &value));
nm_clear_g_free (&value);
return (NMSetting *) g_steal_pointer (&s_wired);
}
@ -5595,6 +5662,8 @@ connection_from_file_full (const char *filename,
if (!connection)
return NULL;
parse_ethtool_options (parsed, connection);
has_complex_routes_v4 = utils_has_complex_routes (filename, AF_INET);
has_complex_routes_v6 = utils_has_complex_routes (filename, AF_INET6);

View file

@ -470,3 +470,63 @@ nms_ifcfg_rh_utils_user_key_decode (const char *name, GString *str_buffer)
return TRUE;
}
/*****************************************************************************/
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 */
ETHT_NAME (NM_ETHTOOL_ID_FEATURE_GRO, "gro"),
ETHT_NAME (NM_ETHTOOL_ID_FEATURE_GSO, "gso"),
ETHT_NAME (NM_ETHTOOL_ID_FEATURE_LRO, "lro"),
ETHT_NAME (NM_ETHTOOL_ID_FEATURE_NTUPLE, "ntuple"),
ETHT_NAME (NM_ETHTOOL_ID_FEATURE_RX, "rx"),
ETHT_NAME (NM_ETHTOOL_ID_FEATURE_RXHASH, "rxhash"),
ETHT_NAME (NM_ETHTOOL_ID_FEATURE_RXVLAN, "rxvlan"),
ETHT_NAME (NM_ETHTOOL_ID_FEATURE_SG, "sg"),
ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TSO, "tso"),
ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TX, "tx"),
ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TXVLAN, "txvlan"),
};
const NMEthtoolData *
nms_ifcfg_rh_utils_get_ethtool_by_name (const char *name)
{
static const struct {
NMEthtoolID ethtool_id;
const char *kernel_name;
} kernel_names[] = {
{ NM_ETHTOOL_ID_FEATURE_GRO, "rx-gro" },
{ NM_ETHTOOL_ID_FEATURE_GSO, "tx-generic-segmentation" },
{ NM_ETHTOOL_ID_FEATURE_LRO, "rx-lro" },
{ NM_ETHTOOL_ID_FEATURE_NTUPLE, "rx-ntuple-filter" },
{ NM_ETHTOOL_ID_FEATURE_RX, "rx-checksum" },
{ NM_ETHTOOL_ID_FEATURE_RXHASH, "rx-hashing" },
{ NM_ETHTOOL_ID_FEATURE_RXVLAN, "rx-vlan-hw-parse" },
{ NM_ETHTOOL_ID_FEATURE_TXVLAN, "tx-vlan-hw-insert" },
};
guint i;
for (i = 0; i < G_N_ELEMENTS (_nm_ethtool_ifcfg_names); i++) {
if (nm_streq (name, _nm_ethtool_ifcfg_names[i]))
return nm_ethtool_data[i];
}
/* Option not found. Note that ethtool utility has built-in features and
* NetworkManager's API follows the naming of these built-in features, whenever
* they exist.
* For example, NM's "ethtool.feature-ntuple" corresponds to ethtool utility's "ntuple"
* feature. However the underlying kernel feature is called "rx-ntuple-filter" (as reported
* for ETH_SS_FEATURES).
*
* With ethtool utility, whose command line we attempt to parse here, the user can also
* specify the name of the underlying kernel feature directly. So, check whether that is
* the case and if yes, map them to the corresponding NetworkManager's features. */
for (i = 0; i < G_N_ELEMENTS (kernel_names); i++) {
if (nm_streq (name, kernel_names[i].kernel_name))
return nm_ethtool_data[kernel_names[i].ethtool_id];
}
return NULL;
}

View file

@ -22,6 +22,7 @@
#define _UTILS_H_
#include "nm-connection.h"
#include "nm-ethtool-utils.h"
#include "shvar.h"
@ -80,4 +81,20 @@ _nms_ifcfg_rh_utils_numbered_tag (char *buf, gsize buf_len, const char *tag_name
_nms_ifcfg_rh_utils_numbered_tag (buf, sizeof (buf), ""tag_name"", (which)); \
})
/*****************************************************************************/
extern const char *const _nm_ethtool_ifcfg_names[_NM_ETHTOOL_ID_FEATURE_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]);
return _nm_ethtool_ifcfg_names[ethtool_id - _NM_ETHTOOL_ID_FEATURE_FIRST];
}
const NMEthtoolData *nms_ifcfg_rh_utils_get_ethtool_by_name (const char *name);
#endif /* _UTILS_H_ */

View file

@ -37,6 +37,7 @@
#include "nm-setting-connection.h"
#include "nm-setting-wired.h"
#include "nm-setting-wireless.h"
#include "nm-setting-ethtool.h"
#include "nm-setting-8021x.h"
#include "nm-setting-proxy.h"
#include "nm-setting-ip4-config.h"
@ -50,6 +51,7 @@
#include "nm-core-internal.h"
#include "NetworkManagerUtils.h"
#include "nm-meta-setting.h"
#include "nm-ethtool-utils.h"
#include "nms-ifcfg-rh-common.h"
#include "nms-ifcfg-rh-reader.h"
@ -1135,6 +1137,7 @@ static gboolean
write_ethtool_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
{
NMSettingWired *s_wired;
NMSettingEthtool *s_ethtool;
const char *duplex;
guint32 speed;
GString *str = NULL;
@ -1143,65 +1146,112 @@ write_ethtool_setting (NMConnection *connection, shvarFile *ifcfg, GError **erro
const char *wol_password;
s_wired = nm_connection_get_setting_wired (connection);
s_ethtool = NM_SETTING_ETHTOOL (nm_connection_get_setting (connection, NM_TYPE_SETTING_ETHTOOL));
if (!s_wired)
if (!s_wired && !s_ethtool) {
svUnsetValue (ifcfg, "ETHTOOL_WAKE_ON_LAN");
svUnsetValue (ifcfg, "ETHTOOL_OPTS");
return TRUE;
auto_negotiate = nm_setting_wired_get_auto_negotiate (s_wired);
speed = nm_setting_wired_get_speed (s_wired);
duplex = nm_setting_wired_get_duplex (s_wired);
/* autoneg off + speed 0 + duplex NULL, means we want NM
* to skip link configuration which is default. So write
* down link config only if we have auto-negotiate true or
* a valid value for one among speed and duplex.
*/
if (auto_negotiate) {
str = g_string_sized_new (64);
g_string_printf (str, "autoneg on");
} else if (speed || duplex) {
str = g_string_sized_new (64);
g_string_printf (str, "autoneg off");
}
if (speed)
g_string_append_printf (str, " speed %u", speed);
if (duplex)
g_string_append_printf (str, " duplex %s", duplex);
wol = nm_setting_wired_get_wake_on_lan (s_wired);
wol_password = nm_setting_wired_get_wake_on_lan_password (s_wired);
if (s_wired) {
auto_negotiate = nm_setting_wired_get_auto_negotiate (s_wired);
speed = nm_setting_wired_get_speed (s_wired);
duplex = nm_setting_wired_get_duplex (s_wired);
/* autoneg off + speed 0 + duplex NULL, means we want NM
* to skip link configuration which is default. So write
* down link config only if we have auto-negotiate true or
* a valid value for one among speed and duplex.
*/
if (auto_negotiate) {
str = g_string_sized_new (64);
g_string_printf (str, "autoneg on");
} else if (speed || duplex) {
str = g_string_sized_new (64);
g_string_printf (str, "autoneg off");
}
if (speed)
g_string_append_printf (str, " speed %u", speed);
if (duplex)
g_string_append_printf (str, " duplex %s", duplex);
wol = nm_setting_wired_get_wake_on_lan (s_wired);
wol_password = nm_setting_wired_get_wake_on_lan_password (s_wired);
svSetValue (ifcfg, "ETHTOOL_WAKE_ON_LAN",
wol == NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE
? "ignore"
: NULL);
if (!NM_IN_SET (wol, NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE,
NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT)) {
if (!str)
str = g_string_sized_new (30);
else
g_string_append (str, " ");
g_string_append (str, "wol ");
if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_PHY))
g_string_append (str, "p");
if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST))
g_string_append (str, "u");
if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST))
g_string_append (str, "m");
if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_BROADCAST))
g_string_append (str, "b");
if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_ARP))
g_string_append (str, "a");
if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC))
g_string_append (str, "g");
if (!NM_FLAGS_ANY (wol, NM_SETTING_WIRED_WAKE_ON_LAN_ALL))
g_string_append (str, "d");
if (wol_password && NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC))
g_string_append_printf (str, "s sopass %s", wol_password);
}
} else
svUnsetValue (ifcfg, "ETHTOOL_WAKE_ON_LAN");
if (s_ethtool) {
NMEthtoolID ethtool_id;
NMSettingConnection *s_con;
const char *iface = NULL;
s_con = nm_connection_get_setting_connection (connection);
if (s_con) {
iface = nm_setting_connection_get_interface_name (s_con);
if ( iface
&& ( !iface[0]
|| !NM_STRCHAR_ALL (iface, ch, (ch >= 'a' && ch <= 'z')
|| (ch >= 'A' && ch <= 'Z')
|| (ch >= '0' && ch <= '9')
|| NM_IN_SET (ch, '_'))))
iface = NULL;
}
svSetValue (ifcfg, "ETHTOOL_WAKE_ON_LAN",
wol == NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE
? "ignore"
: NULL);
if (!NM_IN_SET (wol, NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE,
NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT)) {
if (!str)
str = g_string_sized_new (30);
else
g_string_append (str, " ");
g_string_append (str, " ; ");
g_string_append (str, "-K ");
g_string_append (str, iface ?: "net0");
g_string_append (str, "wol ");
for (ethtool_id = _NM_ETHTOOL_ID_FEATURE_FIRST; ethtool_id <= _NM_ETHTOOL_ID_FEATURE_LAST; ethtool_id++) {
const NMEthtoolData *ed = nm_ethtool_data[ethtool_id];
NMTernary val;
if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_PHY))
g_string_append (str, "p");
if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST))
g_string_append (str, "u");
if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST))
g_string_append (str, "m");
if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_BROADCAST))
g_string_append (str, "b");
if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_ARP))
g_string_append (str, "a");
if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC))
g_string_append (str, "g");
nm_assert (nms_ifcfg_rh_utils_get_ethtool_name (ethtool_id));
if (!NM_FLAGS_ANY (wol, NM_SETTING_WIRED_WAKE_ON_LAN_ALL))
g_string_append (str, "d");
val = nm_setting_ethtool_get_feature (s_ethtool, ed->optname);
if (val == NM_TERNARY_DEFAULT)
continue;
if (wol_password && NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC))
g_string_append_printf (str, "s sopass %s", wol_password);
g_string_append_c (str, ' ');
g_string_append (str, nms_ifcfg_rh_utils_get_ethtool_name (ethtool_id));
g_string_append (str, val == NM_TERNARY_TRUE ? " on" : " off");
}
}
if (str) {

View file

@ -0,0 +1,15 @@
TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
ETHTOOL_OPTS="autoneg on ; -K net0 rxvlan off tx on"
BOOTPROTO=dhcp
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
IPV6_ADDR_GEN_MODE=stable-privacy
NAME="Test Write Wired Auto-Negotiate"
UUID=${UUID}
ONBOOT=yes

View file

@ -43,12 +43,14 @@
#include "nm-setting-pppoe.h"
#include "nm-setting-ppp.h"
#include "nm-setting-vpn.h"
#include "nm-setting-ethtool.h"
#include "nm-setting-gsm.h"
#include "nm-setting-cdma.h"
#include "nm-setting-serial.h"
#include "nm-setting-vlan.h"
#include "nm-setting-dcb.h"
#include "nm-core-internal.h"
#include "nm-ethtool-utils.h"
#include "NetworkManagerUtils.h"
@ -3726,6 +3728,7 @@ test_write_wired_auto_negotiate_on (void)
gs_unref_object NMConnection *connection = NULL;
gs_unref_object NMConnection *reread = NULL;
NMSettingWired *s_wired;
NMSettingEthtool *s_ethtool;
char *val;
shvarFile *f;
@ -3735,8 +3738,14 @@ test_write_wired_auto_negotiate_on (void)
NM_SETTING_WIRED_AUTO_NEGOTIATE, TRUE,
NULL);
_writer_new_connection (connection,
s_ethtool = NM_SETTING_ETHTOOL (nm_setting_ethtool_new ());
nm_setting_ethtool_set_feature (s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_TX, NM_TERNARY_TRUE);
nm_setting_ethtool_set_feature (s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_RXVLAN, NM_TERNARY_FALSE);
nm_connection_add_setting (connection, NM_SETTING (s_ethtool));
_writer_new_connec_exp (connection,
TEST_SCRATCH_DIR,
TEST_IFCFG_DIR"/ifcfg-test_write_wired_auto_negotiate_on.cexpected",
&testfile);
f = _svOpenFile (testfile);
@ -3750,7 +3759,15 @@ test_write_wired_auto_negotiate_on (void)
reread = _connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL);
nmtst_assert_connection_verifies_without_normalization (reread);
nmtst_assert_connection_equals (connection, TRUE, reread, FALSE);
s_ethtool = NM_SETTING_ETHTOOL (nm_connection_get_setting (reread, NM_TYPE_SETTING_ETHTOOL));
g_assert (s_ethtool);
g_assert_cmpint (nm_setting_ethtool_get_feature (s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_TX), ==, NM_TERNARY_TRUE);
g_assert_cmpint (nm_setting_ethtool_get_feature (s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_RXVLAN), ==, NM_TERNARY_FALSE);
g_assert_cmpint (nm_setting_ethtool_get_feature (s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_TXVLAN), ==, NM_TERNARY_DEFAULT);
}
static void