nm-device: apply ethtool coalesce settings when activating a connection

nm-device now applies ethtool coalesce settings during stage 2 "device
config" of the connection activation.

Coalesce settings will be then restored (according to what the state
was before the connection got activated on the device) when the
connection is deactivated during the device cleanup.

One thing to be noted is that unset coalesce settings (in the profile)
will not be touched at all by NetworkManager so that if the NIC driver
sets some default values these will be preserved unless specifically
overridden by the connection profile.

https://bugzilla.redhat.com/show_bug.cgi?id=1614700
This commit is contained in:
Antonio Cardace 2020-05-07 17:13:46 +02:00
parent d8f551cf4a
commit e2be41cbbe
No known key found for this signature in database
GPG key ID: 6BF80ABD43E377D3

View file

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