Add parsing for the show rxq info <port_id> <queue_id> tespmd command and add support for the Scattered Rx capability.
Signed-off-by: Juraj Linkeš <juraj.lin...@pantheon.tech> Reviewed-by: Dean Marx <dm...@iol.unh.edu> --- dts/framework/remote_session/testpmd_shell.py | 137 +++++++++++++++++- dts/framework/testbed_model/capability.py | 12 ++ dts/tests/TestSuite_pmd_buffer_scatter.py | 2 + 3 files changed, 150 insertions(+), 1 deletion(-) diff --git a/dts/framework/remote_session/testpmd_shell.py b/dts/framework/remote_session/testpmd_shell.py index 3401adcc28..3550734ebc 100644 --- a/dts/framework/remote_session/testpmd_shell.py +++ b/dts/framework/remote_session/testpmd_shell.py @@ -49,6 +49,10 @@ TestPmdShellDecorator: TypeAlias = Callable[[TestPmdShellMethod], TestPmdShellMethod] +TestPmdShellNicCapability = ( + TestPmdShellCapabilityMethod | tuple[TestPmdShellCapabilityMethod, TestPmdShellDecorator] +) + class TestPmdDevice: """The data of a device that testpmd can recognize. @@ -392,6 +396,81 @@ def _validate(info: str): return TextParser.wrap(TextParser.find(r"Device private info:\s+([\s\S]+)"), _validate) +class RxQueueState(StrEnum): + """RX queue states. + + References: + DPDK lib: ``lib/ethdev/rte_ethdev.h`` + testpmd display function: ``app/test-pmd/config.c:get_queue_state_name()`` + """ + + #: + stopped = auto() + #: + started = auto() + #: + hairpin = auto() + #: + unknown = auto() + + @classmethod + def make_parser(cls) -> ParserFn: + """Makes a parser function. + + Returns: + ParserFn: A dictionary for the `dataclasses.field` metadata argument containing a + parser function that makes an instance of this enum from text. + """ + return TextParser.wrap(TextParser.find(r"Rx queue state: ([^\r\n]+)"), cls) + + +@dataclass +class TestPmdRxqInfo(TextParser): + """Representation of testpmd's ``show rxq info <port_id> <queue_id>`` command. + + References: + testpmd command function: ``app/test-pmd/cmdline.c:cmd_showqueue()`` + testpmd display function: ``app/test-pmd/config.c:rx_queue_infos_display()`` + """ + + #: + port_id: int = field(metadata=TextParser.find_int(r"Infos for port (\d+)\b ?, RX queue \d+\b")) + #: + queue_id: int = field(metadata=TextParser.find_int(r"Infos for port \d+\b ?, RX queue (\d+)\b")) + #: Mempool used by that queue + mempool: str = field(metadata=TextParser.find(r"Mempool: ([^\r\n]+)")) + #: Ring prefetch threshold + rx_prefetch_threshold: int = field( + metadata=TextParser.find_int(r"RX prefetch threshold: (\d+)\b") + ) + #: Ring host threshold + rx_host_threshold: int = field(metadata=TextParser.find_int(r"RX host threshold: (\d+)\b")) + #: Ring writeback threshold + rx_writeback_threshold: int = field( + metadata=TextParser.find_int(r"RX writeback threshold: (\d+)\b") + ) + #: Drives the freeing of Rx descriptors + rx_free_threshold: int = field(metadata=TextParser.find_int(r"RX free threshold: (\d+)\b")) + #: Drop packets if no descriptors are available + rx_drop_packets: bool = field(metadata=TextParser.find(r"RX drop packets: on")) + #: Do not start queue with rte_eth_dev_start() + rx_deferred_start: bool = field(metadata=TextParser.find(r"RX deferred start: on")) + #: Scattered packets Rx enabled + rx_scattered_packets: bool = field(metadata=TextParser.find(r"RX scattered packets: on")) + #: The state of the queue + rx_queue_state: str = field(metadata=RxQueueState.make_parser()) + #: Configured number of RXDs + number_of_rxds: int = field(metadata=TextParser.find_int(r"Number of RXDs: (\d+)\b")) + #: Hardware receive buffer size + rx_buffer_size: int | None = field( + default=None, metadata=TextParser.find_int(r"RX buffer size: (\d+)\b") + ) + #: Burst mode information + burst_mode: str | None = field( + default=None, metadata=TextParser.find(r"Burst mode: ([^\r\n]+)") + ) + + @dataclass class TestPmdPort(TextParser): """Dataclass representing the result of testpmd's ``show port info`` command.""" @@ -635,6 +714,30 @@ def _wrapper(self: "TestPmdShell", *args: P.args, **kwargs: P.kwargs): return _wrapper +def add_remove_mtu(mtu: int = 1500) -> Callable[[TestPmdShellMethod], TestPmdShellMethod]: + """Configure MTU to `mtu` on all ports, run the decorated function, then revert. + + Args: + mtu: The MTU to configure all ports on. + + Returns: + The method decorated with setting and reverting MTU. + """ + + def decorator(func: TestPmdShellMethod) -> TestPmdShellMethod: + @functools.wraps(func) + def wrapper(self: "TestPmdShell", *args: P.args, **kwargs: P.kwargs): + original_mtu = self.ports[0].mtu + self.set_port_mtu_all(mtu=mtu, verify=False) + retval = func(self, *args, **kwargs) + self.set_port_mtu_all(original_mtu if original_mtu else 1500, verify=False) + return retval + + return wrapper + + return decorator + + class TestPmdShell(DPDKShell): """Testpmd interactive shell. @@ -999,6 +1102,30 @@ def _close(self) -> None: self.send_command("quit", "Bye...") return super()._close() + """ + ====== Capability retrieval methods ====== + """ + + @requires_started_ports + def get_capabilities_rxq_info( + self, + supported_capabilities: MutableSet["NicCapability"], + unsupported_capabilities: MutableSet["NicCapability"], + ) -> None: + """Get all rxq capabilities and divide them into supported and unsupported. + + Args: + supported_capabilities: Supported capabilities will be added to this set. + unsupported_capabilities: Unsupported capabilities will be added to this set. + """ + self._logger.debug("Getting rxq capabilities.") + command = f"show rxq info {self.ports[0].id} 0" + rxq_info = TestPmdRxqInfo.parse(self.send_command(command)) + if rxq_info.rx_scattered_packets: + supported_capabilities.add(NicCapability.SCATTERED_RX_ENABLED) + else: + unsupported_capabilities.add(NicCapability.SCATTERED_RX_ENABLED) + class NicCapability(NoAliasEnum): """A mapping between capability names and the associated :class:`TestPmdShell` methods. @@ -1020,9 +1147,17 @@ class NicCapability(NoAliasEnum): be added to `supported_capabilities` or `unsupported_capabilities` based on their support. The two dictionaries are shared across all capability discovery function calls in a given - test run so that we don't call the same function multiple times. + test run so that we don't call the same function multiple times. For example, when we find + :attr:`SCATTERED_RX_ENABLED` in :meth:`TestPmdShell.get_capabilities_rxq_info`, + we don't go looking for it again if a different test case also needs it. """ + #: Scattered packets Rx enabled + SCATTERED_RX_ENABLED: TestPmdShellNicCapability = ( + TestPmdShell.get_capabilities_rxq_info, + add_remove_mtu(9000), + ) + def __call__( self, testpmd_shell: TestPmdShell, diff --git a/dts/framework/testbed_model/capability.py b/dts/framework/testbed_model/capability.py index fceec4440e..6a7a6cdbee 100644 --- a/dts/framework/testbed_model/capability.py +++ b/dts/framework/testbed_model/capability.py @@ -10,6 +10,18 @@ The module also allows developers to mark test cases or suites as requiring certain hardware capabilities with the :func:`requires` decorator. + +Example: + .. code:: python + + from framework.test_suite import TestSuite, func_test + from framework.testbed_model.capability import NicCapability, requires + class TestPmdBufferScatter(TestSuite): + # only the test case requires the SCATTERED_RX_ENABLED capability + # other test cases may not require it + @requires(NicCapability.SCATTERED_RX_ENABLED) + @func_test + def test_scatter_mbuf_2048(self): """ from abc import ABC, abstractmethod diff --git a/dts/tests/TestSuite_pmd_buffer_scatter.py b/dts/tests/TestSuite_pmd_buffer_scatter.py index 178a40385e..c230bde36f 100644 --- a/dts/tests/TestSuite_pmd_buffer_scatter.py +++ b/dts/tests/TestSuite_pmd_buffer_scatter.py @@ -25,6 +25,7 @@ from framework.params.testpmd import SimpleForwardingModes from framework.remote_session.testpmd_shell import TestPmdShell from framework.test_suite import TestSuite, func_test +from framework.testbed_model.capability import NicCapability, requires class TestPmdBufferScatter(TestSuite): @@ -123,6 +124,7 @@ def pmd_scatter(self, mbsize: int) -> None: f"{offset}.", ) + @requires(NicCapability.SCATTERED_RX_ENABLED) @func_test def test_scatter_mbuf_2048(self) -> None: """Run the :meth:`pmd_scatter` test with `mbsize` set to 2048.""" -- 2.43.0