ethtool: Add support of ring
Example: ```yml --- interfaces: - name: enp7s0 state: up ethtool: ring: rx: 256 rx-jumbo: 4096 rx-mini: 4096 tx: 256 ``` The netdevsim in fedora 34 support ring, but will lose ring info after making changes via NM(the reason is unknown yet). Integration test case included, but require user to define `TEST_REAL_NIC` variable to run it. Tested on `virtio_net` NIC. Unit test case included. Signed-off-by: Gris Ge <fge@redhat.com>
This commit is contained in:
parent
411cd6a5ab
commit
1ea97bfddc
@ -36,6 +36,11 @@ class IfaceEthtool:
|
||||
self._feature = IfaceEthtoolFeature(
|
||||
self._info[Ethtool.Feature.CONFIG_SUBTREE]
|
||||
)
|
||||
self._ring = None
|
||||
if self._info.get(Ethtool.Ring.CONFIG_SUBTREE):
|
||||
self._ring = IfaceEthtoolRing(
|
||||
self._info[Ethtool.Ring.CONFIG_SUBTREE]
|
||||
)
|
||||
|
||||
@property
|
||||
def pause(self):
|
||||
@ -45,6 +50,10 @@ class IfaceEthtool:
|
||||
def feature(self):
|
||||
return self._feature
|
||||
|
||||
@property
|
||||
def ring(self):
|
||||
return self._ring
|
||||
|
||||
def canonicalize(self, original_desire):
|
||||
if self.pause:
|
||||
self.pause.canonicalize(
|
||||
@ -54,6 +63,10 @@ class IfaceEthtool:
|
||||
self.feature.canonicalize(
|
||||
original_desire.get(Ethtool.Feature.CONFIG_SUBTREE, {})
|
||||
)
|
||||
if self.ring:
|
||||
self.ring.canonicalize(
|
||||
original_desire.get(Ethtool.Ring.CONFIG_SUBTREE, {})
|
||||
)
|
||||
|
||||
def to_dict(self):
|
||||
info = {}
|
||||
@ -61,6 +74,8 @@ class IfaceEthtool:
|
||||
info[Ethtool.Pause.CONFIG_SUBTREE] = self.pause.to_dict()
|
||||
if self.feature:
|
||||
info[Ethtool.Feature.CONFIG_SUBTREE] = self.feature.to_dict()
|
||||
if self.ring:
|
||||
info[Ethtool.Ring.CONFIG_SUBTREE] = self.ring.to_dict()
|
||||
return info
|
||||
|
||||
|
||||
@ -147,3 +162,14 @@ class IfaceEthtoolFeature:
|
||||
|
||||
def to_dict(self):
|
||||
return deepcopy(self._info)
|
||||
|
||||
|
||||
class IfaceEthtoolRing:
|
||||
def __init__(self, ring_info):
|
||||
self._info = ring_info
|
||||
|
||||
def canonicalize(self, _original_desire):
|
||||
pass
|
||||
|
||||
def to_dict(self):
|
||||
return deepcopy(self._info)
|
||||
|
@ -185,4 +185,22 @@ class EthtoolInfo:
|
||||
np_features = self._np_ethtool.features
|
||||
if np_features:
|
||||
info[Ethtool.Feature.CONFIG_SUBTREE] = np_features.changeable
|
||||
|
||||
np_ring = self._np_ethtool.ring
|
||||
if np_ring:
|
||||
ring_info = {}
|
||||
if np_ring.tx is not None:
|
||||
ring_info[Ethtool.Ring.TX] = np_ring.tx
|
||||
|
||||
if np_ring.rx is not None:
|
||||
ring_info[Ethtool.Ring.RX] = np_ring.rx
|
||||
|
||||
if np_ring.rx_jumbo is not None:
|
||||
ring_info[Ethtool.Ring.RX_JUMBO] = np_ring.rx_jumbo
|
||||
|
||||
if np_ring.rx_mini is not None:
|
||||
ring_info[Ethtool.Ring.RX_MINI] = np_ring.rx_mini
|
||||
|
||||
if ring_info:
|
||||
info[Ethtool.Ring.CONFIG_SUBTREE] = ring_info
|
||||
return info
|
||||
|
@ -22,6 +22,16 @@ from libnmstate.error import NmstateValueError
|
||||
from .common import NM
|
||||
from .common import GLib
|
||||
|
||||
from libnmstate.schema import Ethtool
|
||||
|
||||
|
||||
_NM_RING_OPT_NAME_MAP = {
|
||||
Ethtool.Ring.RX: NM.ETHTOOL_OPTNAME_RING_RX,
|
||||
Ethtool.Ring.RX_JUMBO: NM.ETHTOOL_OPTNAME_RING_RX_JUMBO,
|
||||
Ethtool.Ring.RX_MINI: NM.ETHTOOL_OPTNAME_RING_RX_MINI,
|
||||
Ethtool.Ring.TX: NM.ETHTOOL_OPTNAME_RING_TX,
|
||||
}
|
||||
|
||||
|
||||
def create_ethtool_setting(iface_ethtool, base_con_profile):
|
||||
nm_setting = None
|
||||
@ -51,6 +61,15 @@ def create_ethtool_setting(iface_ethtool, base_con_profile):
|
||||
for kernel_feature_name, value in iface_ethtool.feature.items():
|
||||
nm_set_feature(nm_setting, kernel_feature_name, value)
|
||||
|
||||
if iface_ethtool.ring:
|
||||
ring_info = iface_ethtool.ring.to_dict()
|
||||
for prop_name, nm_prop_name in _NM_RING_OPT_NAME_MAP.items():
|
||||
if prop_name in ring_info:
|
||||
nm_setting.option_set(
|
||||
nm_prop_name,
|
||||
GLib.Variant.new_uint32(ring_info[prop_name]),
|
||||
)
|
||||
|
||||
return nm_setting
|
||||
|
||||
|
||||
|
@ -473,3 +473,10 @@ class Ethtool:
|
||||
|
||||
class Feature:
|
||||
CONFIG_SUBTREE = "feature"
|
||||
|
||||
class Ring:
|
||||
CONFIG_SUBTREE = "ring"
|
||||
RX = "rx"
|
||||
RX_JUMBO = "rx-jumbo"
|
||||
RX_MINI = "rx-mini"
|
||||
TX = "tx"
|
||||
|
@ -640,6 +640,21 @@ definitions:
|
||||
type: object
|
||||
additionalProperties:
|
||||
type: boolean
|
||||
ring:
|
||||
type: object
|
||||
properties:
|
||||
tx:
|
||||
type: integer
|
||||
minimum: 0
|
||||
rx:
|
||||
type: integer
|
||||
minimum: 0
|
||||
rx-jumbo:
|
||||
type: integer
|
||||
minimum: 0
|
||||
rx-mini:
|
||||
type: integer
|
||||
minimum: 0
|
||||
interface-team:
|
||||
rw:
|
||||
properties:
|
||||
|
@ -125,3 +125,19 @@ def test_ethtool_invalid_feature(eth1_up):
|
||||
}
|
||||
with pytest.raises(NmstateValueError):
|
||||
libnmstate.apply({Interface.KEY: [desire_iface_state]})
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
not os.environ.get("TEST_REAL_NIC"),
|
||||
reason="Need to define TEST_REAL_NIC for ethtool ring test",
|
||||
)
|
||||
def test_ethtool_ring_set_rx():
|
||||
desire_iface_state = {
|
||||
Interface.NAME: os.environ.get("TEST_REAL_NIC"),
|
||||
Ethtool.CONFIG_SUBTREE: {
|
||||
Ethtool.Ring.CONFIG_SUBTREE: {Ethtool.Ring.RX: 256}
|
||||
},
|
||||
}
|
||||
libnmstate.apply({Interface.KEY: [desire_iface_state]})
|
||||
|
||||
assertlib.assert_state_match({Interface.KEY: [desire_iface_state]})
|
||||
|
@ -90,3 +90,31 @@ def test_create_setting_pause_autoneg_off(nm_mock):
|
||||
],
|
||||
any_order=False,
|
||||
)
|
||||
|
||||
|
||||
def test_create_setting_ring(nm_mock):
|
||||
iface_ethtool = IfaceEthtool(
|
||||
{
|
||||
Ethtool.Ring.CONFIG_SUBTREE: {
|
||||
Ethtool.Ring.RX: 256,
|
||||
Ethtool.Ring.TX: 1024,
|
||||
}
|
||||
}
|
||||
)
|
||||
nm_ethtool_setting_mock = nm_mock.SettingEthtool.new.return_value
|
||||
|
||||
nm_ethtool.create_ethtool_setting(iface_ethtool, base_con_profile=None)
|
||||
|
||||
nm_ethtool_setting_mock.option_set.assert_has_calls(
|
||||
[
|
||||
mock.call(
|
||||
"ring-rx",
|
||||
GLib.Variant.new_uint32(256),
|
||||
),
|
||||
mock.call(
|
||||
"ring-tx",
|
||||
GLib.Variant.new_uint32(1024),
|
||||
),
|
||||
],
|
||||
any_order=True,
|
||||
)
|
||||
|
@ -1068,3 +1068,44 @@ class TestEthtool:
|
||||
)
|
||||
with pytest.raises(js.ValidationError):
|
||||
libnmstate.validator.schema_validate(default_data)
|
||||
|
||||
def test_valid_ethtool_ring(self, default_data):
|
||||
default_data[Interface.KEY][0].update(
|
||||
{
|
||||
Ethtool.CONFIG_SUBTREE: {
|
||||
Ethtool.Ring.CONFIG_SUBTREE: {
|
||||
Ethtool.Ring.RX: 256,
|
||||
Ethtool.Ring.RX_JUMBO: 4096,
|
||||
Ethtool.Ring.RX_MINI: 256,
|
||||
Ethtool.Ring.TX: 256,
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
libnmstate.validator.schema_validate(default_data)
|
||||
|
||||
def test_invalid_ethtool_ring_out_of_range(self, default_data):
|
||||
default_data[Interface.KEY][0].update(
|
||||
{
|
||||
Ethtool.CONFIG_SUBTREE: {
|
||||
Ethtool.Ring.CONFIG_SUBTREE: {
|
||||
Ethtool.Ring.RX: -1,
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
with pytest.raises(js.ValidationError):
|
||||
libnmstate.validator.schema_validate(default_data)
|
||||
|
||||
def test_invalid_ethtool_ring_not_integer(self, default_data):
|
||||
default_data[Interface.KEY][0].update(
|
||||
{
|
||||
Ethtool.CONFIG_SUBTREE: {
|
||||
Ethtool.Ring.CONFIG_SUBTREE: {
|
||||
Ethtool.Ring.RX: False,
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
with pytest.raises(js.ValidationError):
|
||||
libnmstate.validator.schema_validate(default_data)
|
||||
|
Loading…
x
Reference in New Issue
Block a user