From patchwork Tue Aug 6 12:46:41 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luca Vizzarro X-Patchwork-Id: 142952 X-Patchwork-Delegate: juraj.linkes@pantheon.tech Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id D5B4C4574D; Tue, 6 Aug 2024 14:49:58 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 20A7F42F09; Tue, 6 Aug 2024 14:49:41 +0200 (CEST) Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by mails.dpdk.org (Postfix) with ESMTP id BE73F42EF5 for ; Tue, 6 Aug 2024 14:49:36 +0200 (CEST) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id EC5F11063; Tue, 6 Aug 2024 05:50:01 -0700 (PDT) Received: from localhost.localdomain (JR4XG4HTQC.cambridge.arm.com [10.1.36.46]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 65C8D3F766; Tue, 6 Aug 2024 05:49:35 -0700 (PDT) From: Luca Vizzarro To: dev@dpdk.org Cc: Jeremy Spewock , =?utf-8?q?Juraj_Linke=C5=A1?= , Honnappa Nagarahalli , Luca Vizzarro , Paul Szczepanek Subject: [PATCH v2 4/5] dts: add ability to start/stop testpmd ports Date: Tue, 6 Aug 2024 13:46:41 +0100 Message-Id: <20240806124642.2580828-5-luca.vizzarro@arm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240806124642.2580828-1-luca.vizzarro@arm.com> References: <20240806121417.2567708-1-Luca.Vizzarro@arm.com> <20240806124642.2580828-1-luca.vizzarro@arm.com> MIME-Version: 1.0 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Add testpmd commands to start and stop all the ports, so that they can be configured. Because there is a distinction of commands that require the ports to be stopped and started, also add decorators for commands that require a specific state, removing this logic from the test writer's duty. Signed-off-by: Luca Vizzarro Reviewed-by: Paul Szczepanek --- dts/framework/remote_session/testpmd_shell.py | 86 ++++++++++++++++++- 1 file changed, 84 insertions(+), 2 deletions(-) diff --git a/dts/framework/remote_session/testpmd_shell.py b/dts/framework/remote_session/testpmd_shell.py index 43e9f56517..ca24b28070 100644 --- a/dts/framework/remote_session/testpmd_shell.py +++ b/dts/framework/remote_session/testpmd_shell.py @@ -14,16 +14,17 @@ testpmd_shell.close() """ +import functools import re import time from dataclasses import dataclass, field from enum import Flag, auto from pathlib import PurePath -from typing import ClassVar +from typing import Any, Callable, ClassVar, Concatenate, ParamSpec from typing_extensions import Self, Unpack -from framework.exception import InteractiveCommandExecutionError +from framework.exception import InteractiveCommandExecutionError, InternalError from framework.params.testpmd import SimpleForwardingModes, TestPmdParams from framework.params.types import TestPmdParamsDict from framework.parser import ParserFn, TextParser @@ -33,6 +34,9 @@ from framework.testbed_model.sut_node import SutNode from framework.utils import StrEnum +P = ParamSpec("P") +TestPmdShellMethod = Callable[Concatenate["TestPmdShell", P], Any] + class TestPmdDevice: """The data of a device that testpmd can recognize. @@ -577,12 +581,51 @@ class TestPmdPortStats(TextParser): tx_bps: int = field(metadata=TextParser.find_int(r"Tx-bps:\s+(\d+)")) +def requires_stopped_ports(func: TestPmdShellMethod) -> TestPmdShellMethod: + """Decorator for :class:`TestPmdShell` commands methods that require stopped ports. + + If the decorated method is called while the ports are started, then these are stopped before + continuing. + """ + + @functools.wraps(func) + def _wrapper(self: "TestPmdShell", *args: P.args, **kwargs: P.kwargs): + if self.ports_started: + self._logger.debug("Ports need to be stopped to continue") + self.stop_all_ports() + + return func(self, *args, **kwargs) + + return _wrapper + + +def requires_started_ports(func: TestPmdShellMethod) -> TestPmdShellMethod: + """Decorator for :class:`TestPmdShell` commands methods that require started ports. + + If the decorated method is called while the ports are stopped, then these are started before + continuing. + """ + + @functools.wraps(func) + def _wrapper(self: "TestPmdShell", *args: P.args, **kwargs: P.kwargs): + if not self.ports_started: + self._logger.debug("Ports need to be started to continue") + self.start_all_ports() + + return func(self, *args, **kwargs) + + return _wrapper + + class TestPmdShell(DPDKShell): """Testpmd interactive shell. The testpmd shell users should never use the :meth:`~.interactive_shell.InteractiveShell.send_command` method directly, but rather call specialized methods. If there isn't one that satisfies a need, it should be added. + + Attributes: + ports_started: Indicates whether the ports are started. """ _app_params: TestPmdParams @@ -619,6 +662,9 @@ def __init__( name, ) + self.ports_started = not self._app_params.disable_device_start + + @requires_started_ports def start(self, verify: bool = True) -> None: """Start packet forwarding with the current configuration. @@ -723,6 +769,42 @@ def set_forward_mode(self, mode: SimpleForwardingModes, verify: bool = True): f"Test pmd failed to set fwd mode to {mode.value}" ) + def stop_all_ports(self, verify: bool = True) -> None: + """Stops all the ports. + + Args: + verify: If :data:`True`, the output of the command will be checked for a successful + execution. + + Raises: + InteractiveCommandExecutionError: If `verify` is :data:`True` and the ports were not + stopped successfully. + """ + self._logger.debug("Stopping all the ports...") + output = self.send_command("port stop all") + if verify and not output.strip().endswith("Done"): + raise InteractiveCommandExecutionError("Ports were not stopped successfully") + + self.ports_started = False + + def start_all_ports(self, verify: bool = True) -> None: + """Starts all the ports. + + Args: + verify: If :data:`True`, the output of the command will be checked for a successful + execution. + + Raises: + InteractiveCommandExecutionError: If `verify` is :data:`True` and the ports were not + started successfully. + """ + self._logger.debug("Starting all the ports...") + output = self.send_command("port start all") + if verify and not output.strip().endswith("Done"): + raise InteractiveCommandExecutionError("Ports were not started successfully") + + self.ports_started = True + def show_port_info_all(self) -> list[TestPmdPort]: """Returns the information of all the ports.