[v6,1/3] dts: add functions to testpmd shell

Message ID 20240710160136.9908-1-dmarx@iol.unh.edu (mailing list archive)
State Superseded
Delegated to: Thomas Monjalon
Headers
Series [v6,1/3] dts: add functions to testpmd shell |

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Dean Marx July 10, 2024, 4:01 p.m. UTC
  added set promisc, set verbose, and port stop
commands to testpmd shell.

Signed-off-by: Dean Marx <dmarx@iol.unh.edu>
---
 dts/framework/remote_session/testpmd_shell.py | 194 +++++++++++++++++-
 1 file changed, 193 insertions(+), 1 deletion(-)
  

Comments

Jeremy Spewock July 11, 2024, 1:59 p.m. UTC | #1
On Wed, Jul 10, 2024 at 12:01 PM Dean Marx <dmarx@iol.unh.edu> wrote:
>
> added set promisc, set verbose, and port stop
> commands to testpmd shell.
>
> Signed-off-by: Dean Marx <dmarx@iol.unh.edu>
> ---
>  dts/framework/remote_session/testpmd_shell.py | 194 +++++++++++++++++-
>  1 file changed, 193 insertions(+), 1 deletion(-)
<snip>
> -    def close(self) -> None:
<snip>
> +    def _close(self) -> None:

This looks like something that might have snuck into this diff from
the context manager series. This method is still called close() on
main, so it's probably better to switch the name back here to match in
the meantime.

>          """Overrides :meth:`~.interactive_shell.close`."""
>          self.send_command("quit", "")
>          return super().close()
> --
> 2.44.0
>
  

Patch

diff --git a/dts/framework/remote_session/testpmd_shell.py b/dts/framework/remote_session/testpmd_shell.py
index ec22f72221..71d2218672 100644
--- a/dts/framework/remote_session/testpmd_shell.py
+++ b/dts/framework/remote_session/testpmd_shell.py
@@ -541,6 +541,48 @@  class TestPmdPort(TextParser):
     )
 
 
+@dataclass
+class TestPmdPortQueue(TextParser):
+    """Dataclass representation of the common parts of the testpmd `show rxq/txq info` commands."""
+
+    #:
+    prefetch_threshold: int = field(metadata=TextParser.find_int(r"prefetch threshold: (\d+)"))
+    #:
+    host_threshold: int = field(metadata=TextParser.find_int(r"host threshold: (\d+)"))
+    #:
+    writeback_threshold: int = field(metadata=TextParser.find_int(r"writeback threshold: (\d+)"))
+    #:
+    free_threshold: int = field(metadata=TextParser.find_int(r"free threshold: (\d+)"))
+    #:
+    deferred_start: bool = field(metadata=TextParser.find("deferred start: on"))
+    #: The number of RXD/TXDs is just the ring size of the queue.
+    ring_size: int = field(metadata=TextParser.find_int(r"Number of (?:RXDs|TXDs): (\d+)"))
+    #:
+    is_queue_started: bool = field(metadata=TextParser.find("queue state: started"))
+    #:
+    burst_mode: str = field(metadata=TextParser.find(r"Burst mode: ([^\r\n]+)"))
+
+
+@dataclass
+class TestPmdTxPortQueue(TestPmdPortQueue):
+    """Dataclass representation for testpmd `show txq info` command."""
+
+    #:
+    rs_threshold: int = field(metadata=TextParser.find_int(r"RS threshold: (\d+)"))
+
+
+@dataclass
+class TestPmdRxPortQueue(TestPmdPortQueue):
+    """Dataclass representation for testpmd `show rxq info` command."""
+
+    #:
+    mempool: str = field(metadata=TextParser.find(r"Mempool: ([^\r\n]+)"))
+    #:
+    can_drop_packets: bool = field(metadata=TextParser.find(r"drop packets: on"))
+    #:
+    is_scattering_packets: bool = field(metadata=TextParser.find(r"scattered packets: on"))
+
+
 @dataclass
 class TestPmdPortStats(TextParser):
     """Port statistics."""
@@ -806,7 +848,157 @@  def show_port_stats(self, port_id: int) -> TestPmdPortStats:
 
         return TestPmdPortStats.parse(output)
 
-    def close(self) -> None:
+    def show_port_queue_info(
+        self, port_id: int, queue_id: int, is_rx_queue: bool
+    ) -> TestPmdPortQueue:
+        """Get the info for a queue on a given port.
+
+        Args:
+            port_id: ID of the port where the queue resides.
+            queue_id: ID of the queue to query.
+            is_rx_queue: Whether to check an RX or TX queue. If :data:`True` an RX queue will be
+                queried, otherwise a TX queue will be queried.
+
+        Raises:
+            InteractiveCommandExecutionError: If there is a failure when getting the info for the
+                queue.
+
+        Returns:
+            Information about the queue on the given port.
+        """
+        queue_type = "rxq" if is_rx_queue else "txq"
+        queue_info = self.send_command(
+            f"show {queue_type} info {port_id} {queue_id}", skip_first_line=True
+        )
+        if queue_info.startswith("ETHDEV: Invalid"):
+            raise InteractiveCommandExecutionError(
+                f"Could not get the info for {queue_type} {queue_id} on port {port_id}"
+            )
+        return (
+            TestPmdRxPortQueue.parse(queue_info)
+            if is_rx_queue
+            else TestPmdTxPortQueue.parse(queue_info)
+        )
+
+    def stop_port_queue(
+        self, port_id: int, queue_id: int, is_rx_queue: bool, verify: bool = True
+    ) -> None:
+        """Stops a given queue on a port.
+
+        Args:
+            port_id: ID of the port that the queue belongs to.
+            queue_id: ID of the queue to stop.
+            is_rx_queue: Type of queue to stop. If :data:`True` an RX queue will be stopped,
+                otherwise a TX queue will be stopped.
+            verify: If :data:`True` an additional command will be sent to verify the queue stopped.
+                Defaults to :data:`True`.
+
+        Raises:
+            InteractiveCommandExecutionError: If `verify` is :data:`True` and the queue fails to
+                stop.
+        """
+        port_type = "rxq" if is_rx_queue else "txq"
+        stop_cmd_output = self.send_command(f"port {port_id} {port_type} {queue_id} stop")
+        if verify:
+            if self.show_port_queue_info(port_id, queue_id, is_rx_queue).is_queue_started:
+                self._logger.debug(
+                    f"Failed to stop {port_type} {queue_id} on port {port_id}:\n{stop_cmd_output}"
+                )
+                raise InteractiveCommandExecutionError(
+                    f"Test pmd failed to stop {port_type} {queue_id} on port {port_id}"
+                )
+
+    def start_port_queue(
+        self, port_id: int, queue_id: int, is_rx_queue: bool, verify: bool = True
+    ) -> None:
+        """Starts a given queue on a port.
+
+        First sets up the port queue, then starts it.
+
+        Args:
+            port_id: ID of the port that the queue belongs to.
+            queue_id: ID of the queue to start.
+            is_rx_queue: Type of queue to start. If :data:`True` an RX queue will be started,
+                otherwise a TX queue will be started.
+            verify: if :data:`True` an additional command will be sent to verify that the queue was
+                started. Defaults to :data:`True`.
+
+        Raises:
+            InteractiveCommandExecutionError: If `verify` is :data:`True` and the queue fails to
+                start.
+        """
+        port_type = "rxq" if is_rx_queue else "txq"
+        self.setup_port_queue(port_id, queue_id, is_rx_queue)
+        start_cmd_output = self.send_command(f"port {port_id} {port_type} {queue_id} start")
+        if verify:
+            if not self.show_port_queue_info(port_id, queue_id, is_rx_queue).is_queue_started:
+                self._logger.debug(
+                    f"Failed to start {port_type} {queue_id} on port {port_id}:\n{start_cmd_output}"
+                )
+                raise InteractiveCommandExecutionError(
+                    f"Test pmd failed to start {port_type} {queue_id} on port {port_id}"
+                )
+
+    def setup_port_queue(self, port_id: int, queue_id: int, is_rx_queue: bool) -> None:
+        """Setup a given queue on a port.
+
+        This functionality cannot be verified because the setup action only takes effect when the
+        queue is started.
+
+        Args:
+            port_id: ID of the port where the queue resides.
+            queue_id: ID of the queue to setup.
+            is_rx_queue: Type of queue to setup. If :data:`True` an RX queue will be setup,
+                otherwise a TX queue will be setup.
+        """
+        self.send_command(f"port {port_id} {'rxq' if is_rx_queue else 'txq'} {queue_id} setup")
+
+    def set_promisc(self, port: int, on: bool, verify: bool = True) -> None:
+        """Turns promiscuous mode on/off for the specified port.
+
+        Args:
+            port: Port number to use, should be within 0-32.
+            on: If :data:`True`, turn promisc mode on, otherwise turn off.
+            verify: If :data:`True` an additional command will be sent to verify that promisc mode
+                is properly set. Defaults to :data:`True`.
+
+        Raises:
+            InteractiveCommandExecutionError: If `verify` is :data:`True` and promisc mode
+                is not correctly set.
+        """
+        promisc_output = self.send_command(f"set promisc {port} {'on' if on else 'off'}")
+        if verify:
+            stats = self.show_port_info(port_id=port)
+            if on ^ stats.is_promiscuous_mode_enabled:
+                self._logger.debug(f"Failed to set promisc mode on port {port}: \n{promisc_output}")
+                raise InteractiveCommandExecutionError(
+                    f"Testpmd failed to set promisc mode on port {port}."
+                )
+
+    def set_verbose(self, level: int, verify: bool = True) -> None:
+        """Set debug verbosity level.
+
+        Args:
+            level: 0 - silent except for error
+                1 - fully verbose except for Tx packets
+                2 - fully verbose except for Rx packets
+                >2 - fully verbose
+            verify: if :data:`True` an additional command will be sent to verify that verbose level
+                is properly set. Defaults to :data:`True`.
+
+        Raises:
+            InteractiveCommandExecutionError: If `verify` is :data:`True` and verbose level
+            is not correctly set.
+        """
+        verbose_output = self.send_command(f"set verbose {level}")
+        if verify:
+            if "Change verbose level" not in verbose_output:
+                self._logger.debug(f"Failed to set verbose level to {level}: \n{verbose_output}")
+                raise InteractiveCommandExecutionError(
+                    f"Testpmd failed to set verbose level to {level}."
+                )
+
+    def _close(self) -> None:
         """Overrides :meth:`~.interactive_shell.close`."""
         self.send_command("quit", "")
         return super().close()