DPDK patches and discussions
 help / color / mirror / Atom feed
* [PATCH v2 0/3] dts: queue start/stop suite
@ 2024-06-17 19:46 Dean Marx
  2024-06-17 19:46 ` [PATCH v2 1/3] dts: initial queue start/stop suite implementation Dean Marx
                   ` (9 more replies)
  0 siblings, 10 replies; 51+ messages in thread
From: Dean Marx @ 2024-06-17 19:46 UTC (permalink / raw)
  To: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, jspewock, bruce.richardson, luca.vizzarro
  Cc: dev, Dean Marx

Queue start/stop suite ensures the Poll Mode Driver can functionally
enable and disable Rx/Tx queues on ports. The suite contains two test
cases:

1. All queues enabled - verifies that packets are received when all
queues on all ports are enabled.
2. Queue start/stop - verifies that packets are not received when the Rx
queue on port 0 is disabled, and then again when the Tx queue on port 1
is disabled.

An important aspect of DPDK is queueing packets for transmission to 
bypass the kernel, which makes this test suite necessary to ensure
performance.

Dean Marx (3):
  dts: initial queue start/stop suite implementation
  dts: added promisc/verbose func to testpmd shell
  dts: queue suite conf schema

 dts/framework/config/conf_yaml_schema.json    |   3 +-
 dts/framework/remote_session/testpmd_shell.py | 179 +++++++++++++++++-
 dts/tests/TestSuite_queue_start_stop.py       |  79 ++++++++
 3 files changed, 259 insertions(+), 2 deletions(-)
 create mode 100644 dts/tests/TestSuite_queue_start_stop.py

-- 
2.44.0


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v2 1/3] dts: initial queue start/stop suite implementation
  2024-06-17 19:46 [PATCH v2 0/3] dts: queue start/stop suite Dean Marx
@ 2024-06-17 19:46 ` Dean Marx
  2024-06-21 21:27   ` Jeremy Spewock
  2024-06-17 19:46 ` [PATCH v2 2/3] dts: added promisc/verbose func to testpmd shell Dean Marx
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 51+ messages in thread
From: Dean Marx @ 2024-06-17 19:46 UTC (permalink / raw)
  To: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, jspewock, bruce.richardson, luca.vizzarro
  Cc: dev, Dean Marx

This suite tests the ability of the Poll Mode Driver to enable and disable
Rx/Tx queues on a port.

Signed-off-by: Dean Marx <dmarx@iol.unh.edu>
---
 dts/tests/TestSuite_queue_start_stop.py | 79 +++++++++++++++++++++++++
 1 file changed, 79 insertions(+)
 create mode 100644 dts/tests/TestSuite_queue_start_stop.py

diff --git a/dts/tests/TestSuite_queue_start_stop.py b/dts/tests/TestSuite_queue_start_stop.py
new file mode 100644
index 0000000000..e180b916e8
--- /dev/null
+++ b/dts/tests/TestSuite_queue_start_stop.py
@@ -0,0 +1,79 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2024 University of New Hampshire
+
+"""Rx/Tx queue start and stop functionality suite.
+
+This suite tests the ability of the poll mode driver to start and
+stop either the Rx or Tx queue (depending on the port) during runtime,
+and verify that packets are not received when one is disabled.
+
+Given a paired port topology, the Rx queue will be disabled on port 0,
+and the Tx queue will be disabled on port 1.
+
+"""
+
+from scapy.layers.inet import IP  # type: ignore[import]
+from scapy.layers.l2 import Ether  # type: ignore[import]
+from scapy.packet import Raw  # type: ignore[import]
+
+from framework.remote_session.testpmd_shell import TestPmdForwardingModes, TestPmdShell
+from framework.test_suite import TestSuite
+
+class TestQueueStartStop(TestSuite):
+    """DPDK Queue start/stop test suite.
+
+    Ensures Rx/Tx queue on a port can be disabled and enabled.
+    Verifies packets are not received when either queue is disabled.
+    """
+
+    def set_up_suite(self) -> None:
+        """Set up the test suite.
+
+        Setup:
+            Create a testpmd session and set up tg nodes
+            verify that at least two ports are open for session
+        """
+        self.verify(len(self._port_links) > 1, "Not enough ports")
+
+    def send_packet_and_verify(self, should_receive: bool = True):
+        """Generate a packet, send to the DUT, and verify it is forwarded back.
+
+        Args:
+            should_receive: indicate whether the packet should be received
+        """
+        packet = Ether()/IP()/Raw(load="xxxxx")
+        received = self.send_packet_and_capture(packet)
+        test_packet = None
+        for packet in received:
+            if packet.haslayer(Raw) and packet[Raw].load == b'xxxxx':
+                test_packet = packet
+                break
+        if should_receive:
+            self.verify(test_packet is not None, "Packet was dropped when it should have been received")
+        else:
+            self.verify(test_packet is None, "Packet was received when it should have been dropped")
+
+    def test_all_queues_enabled(self) -> None:
+        """Ensure packets are received when both Tx and Rx queues are enabled.
+
+        Test:
+            Create an interactive testpmd session, stop Rx queue on port 0, verify
+            packets are dropped. Then start port 0 Rx queue, stop port 1 Tx queue, and
+            verify packets are dropped."""
+        testpmd = self.sut_node.create_interactive_shell(TestPmdShell, privileged=True)
+        testpmd.set_forward_mode(TestPmdForwardingModes.mac)
+        testpmd.stop_port_queue(0, 0, True)
+
+        testpmd.start()
+        self.send_packet_and_verify(False)
+        testpmd.stop()
+
+        testpmd.start_port_queue(0, 0, True)
+        testpmd.stop_port_queue(1, 0, False)
+
+        testpmd.start()
+        self.send_packet_and_verify(False)
+        testpmd.close()
+
+    def tear_down_suite(self) -> None:
+        """Tear down the suite."""
-- 
2.44.0


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v2 2/3] dts: added promisc/verbose func to testpmd shell
  2024-06-17 19:46 [PATCH v2 0/3] dts: queue start/stop suite Dean Marx
  2024-06-17 19:46 ` [PATCH v2 1/3] dts: initial queue start/stop suite implementation Dean Marx
@ 2024-06-17 19:46 ` Dean Marx
  2024-06-21 21:28   ` Jeremy Spewock
  2024-06-17 19:46 ` [PATCH v2 3/3] dts: queue suite conf schema Dean Marx
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 51+ messages in thread
From: Dean Marx @ 2024-06-17 19:46 UTC (permalink / raw)
  To: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, jspewock, bruce.richardson, luca.vizzarro
  Cc: dev, Dean Marx

Setting the verbose mode and promiscuous mode is a common
command in test suites, these additions will allow the dev
to set both modes from the testpmd shell module.

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

diff --git a/dts/framework/remote_session/testpmd_shell.py b/dts/framework/remote_session/testpmd_shell.py
index cb2ab6bd00..425f3ec220 100644
--- a/dts/framework/remote_session/testpmd_shell.py
+++ b/dts/framework/remote_session/testpmd_shell.py
@@ -147,7 +147,7 @@ def start(self, verify: bool = True) -> None:
                         "Not all ports came up after starting packet forwarding in testpmd."
                     )
 
-    def stop(self, verify: bool = True) -> None:
+    def stop(self, verify: bool = True) -> str:
         """Stop packet forwarding.
 
         Args:
@@ -155,6 +155,9 @@ def stop(self, verify: bool = True) -> None:
                 forwarding was stopped successfully or not started. If neither is found, it is
                 considered an error.
 
+        Returns:
+            Output gathered from sending the stop command.
+
         Raises:
             InteractiveCommandExecutionError: If `verify` is :data:`True` and the command to stop
                 forwarding results in an error.
@@ -167,6 +170,7 @@ def stop(self, verify: bool = True) -> None:
             ):
                 self._logger.debug(f"Failed to stop packet forwarding: \n{stop_cmd_output}")
                 raise InteractiveCommandExecutionError("Testpmd failed to stop packet forwarding.")
+        return stop_cmd_output
 
     def get_devices(self) -> list[TestPmdDevice]:
         """Get a list of device names that are known to testpmd.
@@ -225,6 +229,179 @@ def set_forward_mode(self, mode: TestPmdForwardingModes, verify: bool = True):
                 f"Test pmd failed to set fwd mode to {mode.value}"
             )
 
+    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 (
+                # Rx/Tx queue state: ...
+                f"{port_type.capitalize()[:-1]} queue state: stopped" not in
+                self.send_command(f"show {port_type} info {port_id} {queue_id}")
+            ):
+                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 RX queue on a port.
+
+        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, port_type)
+        start_cmd_output = self.send_command(f"port {port_id} {port_type} {queue_id} start")
+        if verify:
+            if (
+                # Rx/Tx queue state: ...
+                f"{port_type.capitalize()[:-1]} queue state: started" not in
+                self.send_command(f"show {port_type} info {port_id} {queue_id}")
+            ):
+                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 change_queue_ring_size(
+            self,
+            port_id: int,
+            queue_id: int,
+            size: int,
+            is_rx_queue: bool,
+            verify: bool = True,
+        ) -> None:
+            """Update the ring size of an RX/TX queue on a given port.
+
+            Args:
+                port_id: The port that the queue resides on.
+                queue_id: The ID of the queue on the port.
+                size: The size to update the ring size to.
+                is_rx_queue: Whether to modify an RX or TX queue. If :data:`True` an RX queue will be
+                    updated, otherwise a TX queue will be updated.
+                verify: If :data:`True` an additional command will be sent to check the ring size of
+                    the queue in an attempt to validate that the size was changes properly.
+
+            Raises:
+                InteractiveCommandExecutionError: If `verify` is :data:`True` and there is a failure
+                    when updating ring size.
+            """
+            queue_type = "rxq" if is_rx_queue else "txq"
+            self.send_command(f"port config {port_id} {queue_type} {queue_id} ring_size {size}")
+            self.setup_port_queue(port_id, queue_id, is_rx_queue)
+            if verify:
+                queue_info = self.send_command(f"show {queue_type} info {port_id} {queue_id}")
+                if f"Number of RXDs: {size}" not in queue_info:
+                    self._logger.debug(
+                        f"Failed up update ring size of queue {queue_id} on port {port_id}:"
+                        f"\n{queue_info}"
+                    )
+                    raise InteractiveCommandExecutionError(
+                        f"Failed to update ring size of queue {queue_id} on port {port_id}"
+                    )
+
+    def set_promisc_on(self, port: int, on: bool, verify: bool = True):
+        """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.
+        """
+        if on:
+            promisc_output = self.send_command(f"set promisc {port} on")
+        else:
+            promisc_output = self.send_command(f"set promisc {port} off")
+        if verify:
+            if (on and "Promiscuous mode: enabled" not in
+            self.send_command(f"show port info {port}")):
+                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}.")
+            elif (not on and "Promiscuous mode: disabled" not in
+            self.send_command(f"show port info {port}")):
+                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):
+        """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", "")
-- 
2.44.0


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v2 3/3] dts: queue suite conf schema
  2024-06-17 19:46 [PATCH v2 0/3] dts: queue start/stop suite Dean Marx
  2024-06-17 19:46 ` [PATCH v2 1/3] dts: initial queue start/stop suite implementation Dean Marx
  2024-06-17 19:46 ` [PATCH v2 2/3] dts: added promisc/verbose func to testpmd shell Dean Marx
@ 2024-06-17 19:46 ` Dean Marx
  2024-06-21 21:28   ` Jeremy Spewock
  2024-06-21 21:27 ` [PATCH v2 0/3] dts: queue start/stop suite Jeremy Spewock
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 51+ messages in thread
From: Dean Marx @ 2024-06-17 19:46 UTC (permalink / raw)
  To: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, jspewock, bruce.richardson, luca.vizzarro
  Cc: dev, Dean Marx

Configuration schema for the queue_start_stop suite.

Signed-off-by: Dean Marx <dmarx@iol.unh.edu>
---
 dts/framework/config/conf_yaml_schema.json | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/dts/framework/config/conf_yaml_schema.json b/dts/framework/config/conf_yaml_schema.json
index 4731f4511d..226f43e846 100644
--- a/dts/framework/config/conf_yaml_schema.json
+++ b/dts/framework/config/conf_yaml_schema.json
@@ -187,7 +187,8 @@
       "enum": [
         "hello_world",
         "os_udp",
-        "pmd_buffer_scatter"
+        "pmd_buffer_scatter",
+        "queue_start_stop"
       ]
     },
     "test_target": {
-- 
2.44.0


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 0/3] dts: queue start/stop suite
  2024-06-17 19:46 [PATCH v2 0/3] dts: queue start/stop suite Dean Marx
                   ` (2 preceding siblings ...)
  2024-06-17 19:46 ` [PATCH v2 3/3] dts: queue suite conf schema Dean Marx
@ 2024-06-21 21:27 ` Jeremy Spewock
  2024-06-26 13:51 ` [PATCH v3 1/3] dts: initial queue start/stop suite implementation Dean Marx
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 51+ messages in thread
From: Jeremy Spewock @ 2024-06-21 21:27 UTC (permalink / raw)
  To: Dean Marx
  Cc: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, bruce.richardson, luca.vizzarro, dev

Hey Dean,

One thing I think might make sense in this series is switching the
order of the commits so that the additions to the testpmd shell come
before the test suite. Since the test suite relies on these methods,
if they aren't implemented anywhere that commit would actually be
broken until the testpmd shell commit is applied. Putting the testpmd
shell patch first shows that the test suite should actually be added
after the methods are added to testpmd.


On Mon, Jun 17, 2024 at 3:47 PM Dean Marx <dmarx@iol.unh.edu> wrote:
>
> Queue start/stop suite ensures the Poll Mode Driver can functionally
> enable and disable Rx/Tx queues on ports. The suite contains two test
> cases:
>
> 1. All queues enabled - verifies that packets are received when all
> queues on all ports are enabled.
> 2. Queue start/stop - verifies that packets are not received when the Rx
> queue on port 0 is disabled, and then again when the Tx queue on port 1
> is disabled.
>
> An important aspect of DPDK is queueing packets for transmission to
> bypass the kernel, which makes this test suite necessary to ensure
> performance.
>
> Dean Marx (3):
>   dts: initial queue start/stop suite implementation
>   dts: added promisc/verbose func to testpmd shell
>   dts: queue suite conf schema
>
>  dts/framework/config/conf_yaml_schema.json    |   3 +-
>  dts/framework/remote_session/testpmd_shell.py | 179 +++++++++++++++++-
>  dts/tests/TestSuite_queue_start_stop.py       |  79 ++++++++
>  3 files changed, 259 insertions(+), 2 deletions(-)
>  create mode 100644 dts/tests/TestSuite_queue_start_stop.py
>
> --
> 2.44.0
>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 1/3] dts: initial queue start/stop suite implementation
  2024-06-17 19:46 ` [PATCH v2 1/3] dts: initial queue start/stop suite implementation Dean Marx
@ 2024-06-21 21:27   ` Jeremy Spewock
  0 siblings, 0 replies; 51+ messages in thread
From: Jeremy Spewock @ 2024-06-21 21:27 UTC (permalink / raw)
  To: Dean Marx
  Cc: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, bruce.richardson, luca.vizzarro, dev

On Mon, Jun 17, 2024 at 3:47 PM Dean Marx <dmarx@iol.unh.edu> wrote:
>
> This suite tests the ability of the Poll Mode Driver to enable and disable
> Rx/Tx queues on a port.
>
> Signed-off-by: Dean Marx <dmarx@iol.unh.edu>
> ---
>  dts/tests/TestSuite_queue_start_stop.py | 79 +++++++++++++++++++++++++
>  1 file changed, 79 insertions(+)
>  create mode 100644 dts/tests/TestSuite_queue_start_stop.py
>
> diff --git a/dts/tests/TestSuite_queue_start_stop.py b/dts/tests/TestSuite_queue_start_stop.py
> new file mode 100644
> index 0000000000..e180b916e8
> --- /dev/null
> +++ b/dts/tests/TestSuite_queue_start_stop.py
> @@ -0,0 +1,79 @@
> +# SPDX-License-Identifier: BSD-3-Clause
> +# Copyright(c) 2024 University of New Hampshire
> +
> +"""Rx/Tx queue start and stop functionality suite.
> +
> +This suite tests the ability of the poll mode driver to start and
> +stop either the Rx or Tx queue (depending on the port) during runtime,
> +and verify that packets are not received when one is disabled.

I wonder if there is instead a way to validate that either packets
aren't received on the port if Rx is disabled, or packets aren't sent
if Tx is disabled rather than just showing that the full flow doesn't
happen. I'm not sure the test really calls for it, but it might better
show how the individual cases interact.

> +
> +Given a paired port topology, the Rx queue will be disabled on port 0,
> +and the Tx queue will be disabled on port 1.
> +
> +"""
> +
> +from scapy.layers.inet import IP  # type: ignore[import]
> +from scapy.layers.l2 import Ether  # type: ignore[import]
> +from scapy.packet import Raw  # type: ignore[import]
> +
> +from framework.remote_session.testpmd_shell import TestPmdForwardingModes, TestPmdShell
> +from framework.test_suite import TestSuite
> +
> +class TestQueueStartStop(TestSuite):
> +    """DPDK Queue start/stop test suite.
> +
> +    Ensures Rx/Tx queue on a port can be disabled and enabled.
> +    Verifies packets are not received when either queue is disabled.
> +    """

I think this doc-string would benefit from some more in-depth
information about how the individual cases are tested and what they
are.

> +
> +    def set_up_suite(self) -> None:
> +        """Set up the test suite.
> +
> +        Setup:
> +            Create a testpmd session and set up tg nodes

We don't seem to be creating a testpmd shell or touching the TG in
this setup method, so we should probably not include this line.

> +            verify that at least two ports are open for session

Missing period at the end of this line.

> +        """
> +        self.verify(len(self._port_links) > 1, "Not enough ports")
> +
> +    def send_packet_and_verify(self, should_receive: bool = True):
> +        """Generate a packet, send to the DUT, and verify it is forwarded back.
> +
> +        Args:
> +            should_receive: indicate whether the packet should be received
> +        """
> +        packet = Ether()/IP()/Raw(load="xxxxx")
> +        received = self.send_packet_and_capture(packet)
> +        test_packet = None
> +        for packet in received:
> +            if packet.haslayer(Raw) and packet[Raw].load == b'xxxxx':
> +                test_packet = packet
> +                break

This feels very similar to what is happening in the VLAN test suite
and if probably a good reason to sooner address this bugzilla ticket:
https://bugs.dpdk.org/show_bug.cgi?id=1372

That's probably better done in another patch though.

Regardless, I still think this could be done using the any() method
that's built into python and it might be more concise.

> +        if should_receive:
> +            self.verify(test_packet is not None, "Packet was dropped when it should have been received")
> +        else:
> +            self.verify(test_packet is None, "Packet was received when it should have been dropped")
> +
> +    def test_all_queues_enabled(self) -> None:
> +        """Ensure packets are received when both Tx and Rx queues are enabled.

This method name and doc-string are confusing as it seems you are
testing more than if it can receive traffic when the queues are
enabled. It looks like you're actually also testing that the Rx and Tx
don't function when they are stopped. These could also probably be
different test cases as they are really testing two different things
(Rx functionality vs Tx).

> +
> +        Test:
> +            Create an interactive testpmd session, stop Rx queue on port 0, verify
> +            packets are dropped. Then start port 0 Rx queue, stop port 1 Tx queue, and
> +            verify packets are dropped."""
> +        testpmd = self.sut_node.create_interactive_shell(TestPmdShell, privileged=True)
> +        testpmd.set_forward_mode(TestPmdForwardingModes.mac)
> +        testpmd.stop_port_queue(0, 0, True)
> +
> +        testpmd.start()
> +        self.send_packet_and_verify(False)
> +        testpmd.stop()
> +
> +        testpmd.start_port_queue(0, 0, True)
> +        testpmd.stop_port_queue(1, 0, False)
> +
> +        testpmd.start()
> +        self.send_packet_and_verify(False)
> +        testpmd.close()
> +
> +    def tear_down_suite(self) -> None:
> +        """Tear down the suite."""

This method stub isn't needed since it isn't extended here.


> --
> 2.44.0
>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 2/3] dts: added promisc/verbose func to testpmd shell
  2024-06-17 19:46 ` [PATCH v2 2/3] dts: added promisc/verbose func to testpmd shell Dean Marx
@ 2024-06-21 21:28   ` Jeremy Spewock
  0 siblings, 0 replies; 51+ messages in thread
From: Jeremy Spewock @ 2024-06-21 21:28 UTC (permalink / raw)
  To: Dean Marx
  Cc: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, bruce.richardson, luca.vizzarro, dev

On Mon, Jun 17, 2024 at 3:48 PM Dean Marx <dmarx@iol.unh.edu> wrote:
>
> Setting the verbose mode and promiscuous mode is a common
> command in test suites, these additions will allow the dev
> to set both modes from the testpmd shell module.

It looks like you're also adding the ability to start and stop ports
here as well, we should add that to the commit body and subject.

>
> Signed-off-by: Dean Marx <dmarx@iol.unh.edu>
> ---
>  dts/framework/remote_session/testpmd_shell.py | 179 +++++++++++++++++-
>  1 file changed, 178 insertions(+), 1 deletion(-)
>
> diff --git a/dts/framework/remote_session/testpmd_shell.py b/dts/framework/remote_session/testpmd_shell.py
> index cb2ab6bd00..425f3ec220 100644
> --- a/dts/framework/remote_session/testpmd_shell.py
> +++ b/dts/framework/remote_session/testpmd_shell.py
> @@ -147,7 +147,7 @@ def start(self, verify: bool = True) -> None:
>                          "Not all ports came up after starting packet forwarding in testpmd."
>                      )
>
> -    def stop(self, verify: bool = True) -> None:
> +    def stop(self, verify: bool = True) -> str:
>          """Stop packet forwarding.
>
>          Args:
> @@ -155,6 +155,9 @@ def stop(self, verify: bool = True) -> None:
>                  forwarding was stopped successfully or not started. If neither is found, it is
>                  considered an error.
>
> +        Returns:
> +            Output gathered from sending the stop command.
> +
>          Raises:
>              InteractiveCommandExecutionError: If `verify` is :data:`True` and the command to stop
>                  forwarding results in an error.
> @@ -167,6 +170,7 @@ def stop(self, verify: bool = True) -> None:
>              ):
>                  self._logger.debug(f"Failed to stop packet forwarding: \n{stop_cmd_output}")
>                  raise InteractiveCommandExecutionError("Testpmd failed to stop packet forwarding.")
> +        return stop_cmd_output

I know these are changes coming from us both using the same port start
and stop methods, but you don't seem to use the changes to the stop
method so we should probably omit them.

>
>      def get_devices(self) -> list[TestPmdDevice]:
>          """Get a list of device names that are known to testpmd.
<snip>
> +
> +    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 change_queue_ring_size(
> +            self,
> +            port_id: int,
> +            queue_id: int,
> +            size: int,
> +            is_rx_queue: bool,
> +            verify: bool = True,
> +        ) -> None:
> +            """Update the ring size of an RX/TX queue on a given port.
> +
> +            Args:
> +                port_id: The port that the queue resides on.
> +                queue_id: The ID of the queue on the port.
> +                size: The size to update the ring size to.
> +                is_rx_queue: Whether to modify an RX or TX queue. If :data:`True` an RX queue will be
> +                    updated, otherwise a TX queue will be updated.
> +                verify: If :data:`True` an additional command will be sent to check the ring size of
> +                    the queue in an attempt to validate that the size was changes properly.
> +
> +            Raises:
> +                InteractiveCommandExecutionError: If `verify` is :data:`True` and there is a failure
> +                    when updating ring size.
> +            """
> +            queue_type = "rxq" if is_rx_queue else "txq"
> +            self.send_command(f"port config {port_id} {queue_type} {queue_id} ring_size {size}")
> +            self.setup_port_queue(port_id, queue_id, is_rx_queue)
> +            if verify:
> +                queue_info = self.send_command(f"show {queue_type} info {port_id} {queue_id}")
> +                if f"Number of RXDs: {size}" not in queue_info:
> +                    self._logger.debug(
> +                        f"Failed up update ring size of queue {queue_id} on port {port_id}:"
> +                        f"\n{queue_info}"
> +                    )
> +                    raise InteractiveCommandExecutionError(
> +                        f"Failed to update ring size of queue {queue_id} on port {port_id}"
> +                    )

Same thing here, it doesn't seem like you use this method for changing
the ring size or the previous for setting up ports, it's probably
better to omit them.

> +
<snip>

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

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v2 3/3] dts: queue suite conf schema
  2024-06-17 19:46 ` [PATCH v2 3/3] dts: queue suite conf schema Dean Marx
@ 2024-06-21 21:28   ` Jeremy Spewock
  0 siblings, 0 replies; 51+ messages in thread
From: Jeremy Spewock @ 2024-06-21 21:28 UTC (permalink / raw)
  To: Dean Marx
  Cc: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, bruce.richardson, luca.vizzarro, dev

On Mon, Jun 17, 2024 at 3:48 PM Dean Marx <dmarx@iol.unh.edu> wrote:
>
> Configuration schema for the queue_start_stop suite.
>
> Signed-off-by: Dean Marx <dmarx@iol.unh.edu>

Reviewed-by: Jeremy Spewock <jspewock@iol.unh.edu>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v3 1/3] dts: initial queue start/stop suite implementation
  2024-06-17 19:46 [PATCH v2 0/3] dts: queue start/stop suite Dean Marx
                   ` (3 preceding siblings ...)
  2024-06-21 21:27 ` [PATCH v2 0/3] dts: queue start/stop suite Jeremy Spewock
@ 2024-06-26 13:51 ` Dean Marx
  2024-06-26 13:51   ` [PATCH v3 2/3] dts: add functions to testpmd shell Dean Marx
                     ` (2 more replies)
  2024-06-28 16:19 ` [PATCH v4 1/3] dts: add functions to testpmd shell Dean Marx
                   ` (4 subsequent siblings)
  9 siblings, 3 replies; 51+ messages in thread
From: Dean Marx @ 2024-06-26 13:51 UTC (permalink / raw)
  To: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, jspewock, bruce.richardson, luca.vizzarro
  Cc: dev, Dean Marx

This suite tests the ability of the Poll Mode Driver to enable and disable
Rx/Tx queues on a port.

Signed-off-by: Dean Marx <dmarx@iol.unh.edu>
---
 dts/tests/TestSuite_queue_start_stop.py | 88 +++++++++++++++++++++++++
 1 file changed, 88 insertions(+)
 create mode 100644 dts/tests/TestSuite_queue_start_stop.py

diff --git a/dts/tests/TestSuite_queue_start_stop.py b/dts/tests/TestSuite_queue_start_stop.py
new file mode 100644
index 0000000000..5708586038
--- /dev/null
+++ b/dts/tests/TestSuite_queue_start_stop.py
@@ -0,0 +1,88 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2024 University of New Hampshire
+
+"""Rx/Tx queue start and stop functionality suite.
+
+This suite tests the ability of the poll mode driver to start and
+stop either the Rx or Tx queue (depending on the port) during runtime,
+and verify that packets are not received when one is disabled.
+
+Given a paired port topology, the Rx queue will be disabled on port 0,
+and the Tx queue will be disabled on port 1.
+
+"""
+
+from scapy.layers.inet import IP  # type: ignore[import]
+from scapy.layers.l2 import Ether  # type: ignore[import]
+from scapy.packet import Raw  # type: ignore[import]
+
+from framework.remote_session.testpmd_shell import SimpleForwardingModes, TestPmdShell, TestPmdPortStats
+from framework.test_suite import TestSuite
+
+class TestQueueStartStop(TestSuite):
+    """DPDK Queue start/stop test suite.
+
+    Ensures Rx/Tx queue on a port can be disabled and enabled.
+    Verifies packets are not received when either queue is disabled.
+    The suite contains two test cases, Rx queue start/stop and
+    Tx queue start/stop, which each disable the corresponding
+    queue and verify that packets are not received/forwarded.
+    """
+
+    def set_up_suite(self) -> None:
+        """Set up the test suite.
+
+        Setup:
+            Verify that at least two ports are open for session.
+        """
+        self.verify(len(self._port_links) > 1, "Not enough ports")
+
+    def send_packet_and_verify(self, should_receive: bool = True):
+        """Generate a packet, send to the DUT, and verify it is forwarded back.
+
+        Args:
+            should_receive: Indicate whether the packet should be received.
+            queue_type: Indicate which port should be verified (True for Rx, False for Tx.)
+        """
+        packet = Ether()/IP()/Raw(load="xxxxx")
+        received = self.send_packet_and_capture(packet)
+        contains_packet = any(packet in received and hasattr(packet, 'Raw') and
+                              b'xxxxx' in packet.load for packet in received)
+        if should_receive:
+            self.verify(contains_packet, "Packet was dropped when it should have been received")
+        else:
+            self.verify(not contains_packet, "Packet was received when it should have been dropped")
+
+
+    def test_rx_queue_start_stop(self) -> None:
+        """Verify packets are not received by port 0 when Rx queue is disabled.
+
+        Test:
+            Create an interactive testpmd session, stop Rx queue on port 0, verify
+            packets are not received.
+        """
+        testpmd = TestPmdShell(node=self.sut_node)
+        testpmd.set_forward_mode(SimpleForwardingModes.mac)
+        testpmd.stop_port_queue(0, 0, True)
+
+        testpmd.start()
+        self.send_packet_and_verify(should_receive=False)
+        stats = testpmd.show_port_stats(port_id=0)
+        self.verify(stats.rx_packets == 0, "Packets were received on Rx queue when it should've been disabled")
+        testpmd.close()
+
+    def test_tx_queue_start_stop(self) -> None:
+        """Verify packets are not forwarded by port 1 when Tx queue is disabled.
+
+        Test:
+            Create an interactive testpmd session, stop Tx queue on port 1, verify
+            packets are not forwarded.
+        """
+        testpmd = TestPmdShell(node=self.sut_node)
+        testpmd.set_forward_mode(SimpleForwardingModes.mac)
+        testpmd.stop_port_queue(1, 0, False)
+        testpmd.start()
+        self.send_packet_and_verify(should_receive=False)
+        stats = testpmd.show_port_stats(port_id=1)
+        self.verify(stats.tx_packets == 0, "Packets were forwarded on Tx queue when it should've been disabled")
+        testpmd.close()
-- 
2.44.0


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v3 2/3] dts: add functions to testpmd shell
  2024-06-26 13:51 ` [PATCH v3 1/3] dts: initial queue start/stop suite implementation Dean Marx
@ 2024-06-26 13:51   ` Dean Marx
  2024-06-26 19:51     ` Jeremy Spewock
  2024-06-26 13:51   ` [PATCH v3 3/3] dts: queue suite conf schema Dean Marx
  2024-06-26 19:50   ` [PATCH v3 1/3] dts: initial queue start/stop suite implementation Jeremy Spewock
  2 siblings, 1 reply; 51+ messages in thread
From: Dean Marx @ 2024-06-26 13:51 UTC (permalink / raw)
  To: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, jspewock, bruce.richardson, luca.vizzarro
  Cc: dev, Dean Marx

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 | 157 +++++++++++++++---
 1 file changed, 136 insertions(+), 21 deletions(-)

diff --git a/dts/framework/remote_session/testpmd_shell.py b/dts/framework/remote_session/testpmd_shell.py
index ec22f72221..a1928b2cec 100644
--- a/dts/framework/remote_session/testpmd_shell.py
+++ b/dts/framework/remote_session/testpmd_shell.py
@@ -645,27 +645,6 @@ def start(self, verify: bool = True) -> None:
                         "Not all ports came up after starting packet forwarding in testpmd."
                     )
 
-    def stop(self, verify: bool = True) -> None:
-        """Stop packet forwarding.
-
-        Args:
-            verify: If :data:`True` , the output of the stop command is scanned to verify that
-                forwarding was stopped successfully or not started. If neither is found, it is
-                considered an error.
-
-        Raises:
-            InteractiveCommandExecutionError: If `verify` is :data:`True` and the command to stop
-                forwarding results in an error.
-        """
-        stop_cmd_output = self.send_command("stop")
-        if verify:
-            if (
-                "Done." not in stop_cmd_output
-                and "Packet forwarding not started" not in stop_cmd_output
-            ):
-                self._logger.debug(f"Failed to stop packet forwarding: \n{stop_cmd_output}")
-                raise InteractiveCommandExecutionError("Testpmd failed to stop packet forwarding.")
-
     def get_devices(self) -> list[TestPmdDevice]:
         """Get a list of device names that are known to testpmd.
 
@@ -806,6 +785,142 @@ def show_port_stats(self, port_id: int) -> TestPmdPortStats:
 
         return TestPmdPortStats.parse(output)
 
+    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 (
+                # Rx/Tx queue state: ...
+                f"{port_type.capitalize()[:-1]} queue state: stopped" not in
+                self.send_command(f"show {port_type} info {port_id} {queue_id}")
+            ):
+                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 RX queue on a port.
+
+        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, port_type)
+        start_cmd_output = self.send_command(f"port {port_id} {port_type} {queue_id} start")
+        if verify:
+            if (
+                # Rx/Tx queue state: ...
+                f"{port_type.capitalize()[:-1]} queue state: started" not in
+                self.send_command(f"show {port_type} info {port_id} {queue_id}")
+            ):
+                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_on(self, port: int, on: bool, verify: bool = True):
+        """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.
+        """
+        if on:
+            promisc_output = self.send_command(f"set promisc {port} on")
+        else:
+            promisc_output = self.send_command(f"set promisc {port} off")
+        if verify:
+            if (on and "Promiscuous mode: enabled" not in
+            self.send_command(f"show port info {port}")):
+                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}.")
+            elif (not on and "Promiscuous mode: disabled" not in
+            self.send_command(f"show port info {port}")):
+                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):
+        """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", "")
-- 
2.44.0


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v3 3/3] dts: queue suite conf schema
  2024-06-26 13:51 ` [PATCH v3 1/3] dts: initial queue start/stop suite implementation Dean Marx
  2024-06-26 13:51   ` [PATCH v3 2/3] dts: add functions to testpmd shell Dean Marx
@ 2024-06-26 13:51   ` Dean Marx
  2024-06-26 19:51     ` Jeremy Spewock
  2024-06-26 19:50   ` [PATCH v3 1/3] dts: initial queue start/stop suite implementation Jeremy Spewock
  2 siblings, 1 reply; 51+ messages in thread
From: Dean Marx @ 2024-06-26 13:51 UTC (permalink / raw)
  To: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, jspewock, bruce.richardson, luca.vizzarro
  Cc: dev, Dean Marx

Configuration schema for the queue_start_stop suite.

Signed-off-by: Dean Marx <dmarx@iol.unh.edu>
---
 dts/framework/config/conf_yaml_schema.json | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/dts/framework/config/conf_yaml_schema.json b/dts/framework/config/conf_yaml_schema.json
index f02a310bb5..9882ddb3d8 100644
--- a/dts/framework/config/conf_yaml_schema.json
+++ b/dts/framework/config/conf_yaml_schema.json
@@ -187,7 +187,8 @@
       "enum": [
         "hello_world",
         "os_udp",
-        "pmd_buffer_scatter"
+        "pmd_buffer_scatter",
+        "queue_start_stop"
       ]
     },
     "test_target": {
-- 
2.44.0


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v3 1/3] dts: initial queue start/stop suite implementation
  2024-06-26 13:51 ` [PATCH v3 1/3] dts: initial queue start/stop suite implementation Dean Marx
  2024-06-26 13:51   ` [PATCH v3 2/3] dts: add functions to testpmd shell Dean Marx
  2024-06-26 13:51   ` [PATCH v3 3/3] dts: queue suite conf schema Dean Marx
@ 2024-06-26 19:50   ` Jeremy Spewock
  2 siblings, 0 replies; 51+ messages in thread
From: Jeremy Spewock @ 2024-06-26 19:50 UTC (permalink / raw)
  To: Dean Marx
  Cc: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, bruce.richardson, luca.vizzarro, dev

Overall, this looks good to me. I just left some small comments,
mostly about documentation, but a few about logic.

I still think however that this commit should come after the testpmd
changes in the order of the patches.

Also, it looks like this series is throwing some warnings/errors with
the formatting script (devtools/dts-check-format.sh). Please fix those
as well for the next version.

On Wed, Jun 26, 2024 at 9:52 AM Dean Marx <dmarx@iol.unh.edu> wrote:
>
> This suite tests the ability of the Poll Mode Driver to enable and disable
> Rx/Tx queues on a port.
>
> Signed-off-by: Dean Marx <dmarx@iol.unh.edu>
> ---
<snip>
> +
> +from scapy.layers.inet import IP  # type: ignore[import]
> +from scapy.layers.l2 import Ether  # type: ignore[import]
> +from scapy.packet import Raw  # type: ignore[import]
> +
> +from framework.remote_session.testpmd_shell import SimpleForwardingModes, TestPmdShell, TestPmdPortStats
> +from framework.test_suite import TestSuite
> +
> +class TestQueueStartStop(TestSuite):
> +    """DPDK Queue start/stop test suite.
> +
> +    Ensures Rx/Tx queue on a port can be disabled and enabled.
> +    Verifies packets are not received when either queue is disabled.
> +    The suite contains two test cases, Rx queue start/stop and
> +    Tx queue start/stop, which each disable the corresponding
> +    queue and verify that packets are not received/forwarded.
> +    """
> +
> +    def set_up_suite(self) -> None:
> +        """Set up the test suite.
> +
> +        Setup:
> +            Verify that at least two ports are open for session.
> +        """
> +        self.verify(len(self._port_links) > 1, "Not enough ports")
> +
> +    def send_packet_and_verify(self, should_receive: bool = True):
> +        """Generate a packet, send to the DUT, and verify it is forwarded back.
> +
> +        Args:
> +            should_receive: Indicate whether the packet should be received.
> +            queue_type: Indicate which port should be verified (True for Rx, False for Tx.)

It looks like this arg got removed from the function, we should remove
it from the doc-string as well.

> +        """
> +        packet = Ether()/IP()/Raw(load="xxxxx")
> +        received = self.send_packet_and_capture(packet)
> +        contains_packet = any(packet in received and hasattr(packet, 'Raw') and
> +                              b'xxxxx' in packet.load for packet in received)

The first part of this any() call "packet in received" is redundant.
Since this statement loops through the elements in `received`, it will
always be true that `packet` is in `receieved`.

> +        if should_receive:
> +            self.verify(contains_packet, "Packet was dropped when it should have been received")
> +        else:
> +            self.verify(not contains_packet, "Packet was received when it should have been dropped")

Maybe it's more clear to break these out in an if-else, but, just as a
thought, you could also do:
self.verify(should_receive == contains_packet, f"Packet was {'dropped'
if should_receive else 'received'}")

Although this method is less verbose so I'm not sure it's really better.


> +
> +
> +    def test_rx_queue_start_stop(self) -> None:
> +        """Verify packets are not received by port 0 when Rx queue is disabled.
> +
> +        Test:
> +            Create an interactive testpmd session, stop Rx queue on port 0, verify
> +            packets are not received.
> +        """
> +        testpmd = TestPmdShell(node=self.sut_node)
> +        testpmd.set_forward_mode(SimpleForwardingModes.mac)
> +        testpmd.stop_port_queue(0, 0, True)
> +
> +        testpmd.start()
> +        self.send_packet_and_verify(should_receive=False)
> +        stats = testpmd.show_port_stats(port_id=0)
> +        self.verify(stats.rx_packets == 0, "Packets were received on Rx queue when it should've been disabled")
> +        testpmd.close()
> +
> +    def test_tx_queue_start_stop(self) -> None:
> +        """Verify packets are not forwarded by port 1 when Tx queue is disabled.
> +
> +        Test:
> +            Create an interactive testpmd session, stop Tx queue on port 1, verify
> +            packets are not forwarded.
> +        """
> +        testpmd = TestPmdShell(node=self.sut_node)
> +        testpmd.set_forward_mode(SimpleForwardingModes.mac)
> +        testpmd.stop_port_queue(1, 0, False)
> +        testpmd.start()
> +        self.send_packet_and_verify(should_receive=False)
> +        stats = testpmd.show_port_stats(port_id=1)
> +        self.verify(stats.tx_packets == 0, "Packets were forwarded on Tx queue when it should've been disabled")
> +        testpmd.close()
> --
> 2.44.0
>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v3 2/3] dts: add functions to testpmd shell
  2024-06-26 13:51   ` [PATCH v3 2/3] dts: add functions to testpmd shell Dean Marx
@ 2024-06-26 19:51     ` Jeremy Spewock
  0 siblings, 0 replies; 51+ messages in thread
From: Jeremy Spewock @ 2024-06-26 19:51 UTC (permalink / raw)
  To: Dean Marx
  Cc: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, bruce.richardson, luca.vizzarro, dev

On Wed, Jun 26, 2024 at 9:52 AM 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 | 157 +++++++++++++++---
>  1 file changed, 136 insertions(+), 21 deletions(-)
>
> diff --git a/dts/framework/remote_session/testpmd_shell.py b/dts/framework/remote_session/testpmd_shell.py
> index ec22f72221..a1928b2cec 100644
> --- a/dts/framework/remote_session/testpmd_shell.py
> +++ b/dts/framework/remote_session/testpmd_shell.py
> @@ -645,27 +645,6 @@ def start(self, verify: bool = True) -> None:
>                          "Not all ports came up after starting packet forwarding in testpmd."
>                      )
>
> -    def stop(self, verify: bool = True) -> None:
> -        """Stop packet forwarding.
> -
> -        Args:
> -            verify: If :data:`True` , the output of the stop command is scanned to verify that
> -                forwarding was stopped successfully or not started. If neither is found, it is
> -                considered an error.
> -
> -        Raises:
> -            InteractiveCommandExecutionError: If `verify` is :data:`True` and the command to stop
> -                forwarding results in an error.
> -        """
> -        stop_cmd_output = self.send_command("stop")
> -        if verify:
> -            if (
> -                "Done." not in stop_cmd_output
> -                and "Packet forwarding not started" not in stop_cmd_output
> -            ):
> -                self._logger.debug(f"Failed to stop packet forwarding: \n{stop_cmd_output}")
> -                raise InteractiveCommandExecutionError("Testpmd failed to stop packet forwarding.")
> -

Apologies, I didn't mean to remove the entire method from testpmd
shell, I just mean the changes that were made to it in the last
version. This method is still required since the scatter test suite
uses it on main currently. The version that is on main should be fine
though.

>      def get_devices(self) -> list[TestPmdDevice]:
>          """Get a list of device names that are known to testpmd.
>
<snip>
> +    def set_promisc_on(self, port: int, on: bool, verify: bool = True):

I had some comments on this method in your VLAN series that still
apply here. Seems like this method if needed in quite a few places,
definitely good we're getting it added.

> +        """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.
> +        """
> +        if on:
> +            promisc_output = self.send_command(f"set promisc {port} on")
> +        else:
> +            promisc_output = self.send_command(f"set promisc {port} off")
> +        if verify:
> +            if (on and "Promiscuous mode: enabled" not in
> +            self.send_command(f"show port info {port}")):
> +                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}.")
> +            elif (not on and "Promiscuous mode: disabled" not in
> +            self.send_command(f"show port info {port}")):
> +                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):
> +        """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

I think in the VLAN suite series these lines got indented, we should
probably also update this method to match what is there.



> +            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", "")
> --
> 2.44.0
>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v3 3/3] dts: queue suite conf schema
  2024-06-26 13:51   ` [PATCH v3 3/3] dts: queue suite conf schema Dean Marx
@ 2024-06-26 19:51     ` Jeremy Spewock
  0 siblings, 0 replies; 51+ messages in thread
From: Jeremy Spewock @ 2024-06-26 19:51 UTC (permalink / raw)
  To: Dean Marx
  Cc: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, bruce.richardson, luca.vizzarro, dev

On Wed, Jun 26, 2024 at 9:52 AM Dean Marx <dmarx@iol.unh.edu> wrote:
>
> Configuration schema for the queue_start_stop suite.
>
> Signed-off-by: Dean Marx <dmarx@iol.unh.edu>

Reviewed-by: Jeremy Spewock <jspewock@iol.unh.edu>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v4 1/3] dts: add functions to testpmd shell
  2024-06-17 19:46 [PATCH v2 0/3] dts: queue start/stop suite Dean Marx
                   ` (4 preceding siblings ...)
  2024-06-26 13:51 ` [PATCH v3 1/3] dts: initial queue start/stop suite implementation Dean Marx
@ 2024-06-28 16:19 ` Dean Marx
  2024-06-28 16:19   ` [PATCH v4 2/3] dts: initial queue start/stop suite implementation Dean Marx
                     ` (2 more replies)
  2024-07-03 18:08 ` [PATCH v5 " Dean Marx
                   ` (3 subsequent siblings)
  9 siblings, 3 replies; 51+ messages in thread
From: Dean Marx @ 2024-06-28 16:19 UTC (permalink / raw)
  To: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, jspewock, bruce.richardson, luca.vizzarro
  Cc: dev, Dean Marx

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 | 124 ++++++++++++++++++
 1 file changed, 124 insertions(+)

diff --git a/dts/framework/remote_session/testpmd_shell.py b/dts/framework/remote_session/testpmd_shell.py
index ec22f72221..56e0ef13fe 100644
--- a/dts/framework/remote_session/testpmd_shell.py
+++ b/dts/framework/remote_session/testpmd_shell.py
@@ -806,6 +806,130 @@ def show_port_stats(self, port_id: int) -> TestPmdPortStats:
 
         return TestPmdPortStats.parse(output)
 
+    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 (
+                # Rx/Tx queue state: ...
+                f"{port_type.capitalize()[:-1]} queue state: stopped"
+                not in self.send_command(f"show {port_type} info {port_id} {queue_id}")
+            ):
+                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 RX queue on a port.
+
+        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, port_type)
+        start_cmd_output = self.send_command(f"port {port_id} {port_type} {queue_id} start")
+        if verify:
+            if (
+                # Rx/Tx queue state: ...
+                f"{port_type.capitalize()[:-1]} queue state: started"
+                not in self.send_command(f"show {port_type} info {port_id} {queue_id}")
+            ):
+                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):
+        """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):
+        """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", "")
-- 
2.44.0


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v4 2/3] dts: initial queue start/stop suite implementation
  2024-06-28 16:19 ` [PATCH v4 1/3] dts: add functions to testpmd shell Dean Marx
@ 2024-06-28 16:19   ` Dean Marx
  2024-07-01 20:17     ` Jeremy Spewock
  2024-06-28 16:19   ` [PATCH v4 3/3] dts: queue suite conf schema Dean Marx
  2024-07-01 20:17   ` [PATCH v4 1/3] dts: add functions to testpmd shell Jeremy Spewock
  2 siblings, 1 reply; 51+ messages in thread
From: Dean Marx @ 2024-06-28 16:19 UTC (permalink / raw)
  To: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, jspewock, bruce.richardson, luca.vizzarro
  Cc: dev, Dean Marx

This suite tests the ability of the Poll Mode Driver to enable
and disable Rx/Tx queues on a port.

Signed-off-by: Dean Marx <dmarx@iol.unh.edu>
---
 dts/tests/TestSuite_queue_start_stop.py | 95 +++++++++++++++++++++++++
 1 file changed, 95 insertions(+)
 create mode 100644 dts/tests/TestSuite_queue_start_stop.py

diff --git a/dts/tests/TestSuite_queue_start_stop.py b/dts/tests/TestSuite_queue_start_stop.py
new file mode 100644
index 0000000000..48306cf03c
--- /dev/null
+++ b/dts/tests/TestSuite_queue_start_stop.py
@@ -0,0 +1,95 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2024 University of New Hampshire
+
+"""Rx/Tx queue start and stop functionality suite.
+
+This suite tests the ability of the poll mode driver to start and
+stop either the Rx or Tx queue (depending on the port) during runtime,
+and verify that packets are not received when one is disabled.
+
+Given a paired port topology, the Rx queue will be disabled on port 0,
+and the Tx queue will be disabled on port 1.
+
+"""
+
+from scapy.layers.inet import IP  # type: ignore[import]
+from scapy.layers.l2 import Ether  # type: ignore[import]
+from scapy.packet import Raw  # type: ignore[import]
+
+from framework.remote_session.testpmd_shell import SimpleForwardingModes, TestPmdShell
+from framework.test_suite import TestSuite
+
+
+class TestQueueStartStop(TestSuite):
+    """DPDK Queue start/stop test suite.
+
+    Ensures Rx/Tx queue on a port can be disabled and enabled.
+    Verifies packets are not received when either queue is disabled.
+    The suite contains two test cases, Rx queue start/stop and
+    Tx queue start/stop, which each disable the corresponding
+    queue and verify that packets are not received/forwarded.
+    """
+
+    def set_up_suite(self) -> None:
+        """Set up the test suite.
+
+        Setup:
+            Verify that at least two ports are open for session.
+        """
+        self.verify(len(self._port_links) > 1, "Not enough ports")
+
+    def send_packet_and_verify(self, should_receive: bool = True):
+        """Generate a packet, send to the DUT, and verify it is forwarded back.
+
+        Args:
+            should_receive: Indicate whether the packet should be received.
+            queue_type: Indicate which port should be verified (True for Rx, False for Tx.)
+        """
+        packet = Ether() / IP() / Raw(load="xxxxx")
+        received = self.send_packet_and_capture(packet)
+        contains_packet = any(
+            packet.haslayer(Raw) and b"xxxxx" in packet.load for packet in received
+        )
+        self.verify(
+            should_receive == contains_packet,
+            f"Packet was {'dropped' if should_receive else 'received'}",
+        )
+
+    def test_rx_queue_start_stop(self) -> None:
+        """Verify packets are not received by port 0 when Rx queue is disabled.
+
+        Test:
+            Create an interactive testpmd session, stop Rx queue on port 0, verify
+            packets are not received.
+        """
+        testpmd = TestPmdShell(node=self.sut_node)
+        testpmd.set_forward_mode(SimpleForwardingModes.mac)
+        testpmd.stop_port_queue(0, 0, True)
+
+        testpmd.start()
+        self.send_packet_and_verify(should_receive=False)
+        stats = testpmd.show_port_stats(port_id=0)
+        self.verify(
+            stats.rx_packets == 0,
+            "Packets were received on Rx queue when it should've been disabled",
+        )
+        testpmd.close()
+
+    def test_tx_queue_start_stop(self) -> None:
+        """Verify packets are not forwarded by port 1 when Tx queue is disabled.
+
+        Test:
+            Create an interactive testpmd session, stop Tx queue on port 1, verify
+            packets are not forwarded.
+        """
+        testpmd = TestPmdShell(node=self.sut_node)
+        testpmd.set_forward_mode(SimpleForwardingModes.mac)
+        testpmd.stop_port_queue(1, 0, False)
+        testpmd.start()
+        self.send_packet_and_verify(should_receive=False)
+        stats = testpmd.show_port_stats(port_id=1)
+        self.verify(
+            stats.tx_packets == 0,
+            "Packets were forwarded on Tx queue when it should've been disabled",
+        )
+        testpmd.close()
-- 
2.44.0


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v4 3/3] dts: queue suite conf schema
  2024-06-28 16:19 ` [PATCH v4 1/3] dts: add functions to testpmd shell Dean Marx
  2024-06-28 16:19   ` [PATCH v4 2/3] dts: initial queue start/stop suite implementation Dean Marx
@ 2024-06-28 16:19   ` Dean Marx
  2024-07-01 20:17   ` [PATCH v4 1/3] dts: add functions to testpmd shell Jeremy Spewock
  2 siblings, 0 replies; 51+ messages in thread
From: Dean Marx @ 2024-06-28 16:19 UTC (permalink / raw)
  To: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, jspewock, bruce.richardson, luca.vizzarro
  Cc: dev, Dean Marx

Configuration schema for the queue_start_stop suite.

Signed-off-by: Dean Marx <dmarx@iol.unh.edu>
---
 dts/framework/config/conf_yaml_schema.json | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/dts/framework/config/conf_yaml_schema.json b/dts/framework/config/conf_yaml_schema.json
index f02a310bb5..9882ddb3d8 100644
--- a/dts/framework/config/conf_yaml_schema.json
+++ b/dts/framework/config/conf_yaml_schema.json
@@ -187,7 +187,8 @@
       "enum": [
         "hello_world",
         "os_udp",
-        "pmd_buffer_scatter"
+        "pmd_buffer_scatter",
+        "queue_start_stop"
       ]
     },
     "test_target": {
-- 
2.44.0


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v4 1/3] dts: add functions to testpmd shell
  2024-06-28 16:19 ` [PATCH v4 1/3] dts: add functions to testpmd shell Dean Marx
  2024-06-28 16:19   ` [PATCH v4 2/3] dts: initial queue start/stop suite implementation Dean Marx
  2024-06-28 16:19   ` [PATCH v4 3/3] dts: queue suite conf schema Dean Marx
@ 2024-07-01 20:17   ` Jeremy Spewock
  2 siblings, 0 replies; 51+ messages in thread
From: Jeremy Spewock @ 2024-07-01 20:17 UTC (permalink / raw)
  To: Dean Marx
  Cc: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, bruce.richardson, luca.vizzarro, dev

Hey Dean,

Thanks for the new series. One thing I noted for the series as a whole
is that there are a few small errors being thrown by the formatting
script. One of the errors is on a method I wrote and gave you so I
apologize for that, it looks like I changed a parameter to a method
but didn't switch what I passed in when I called it.

Outside of the formatting issues I just had a few small comments,
otherwise it looks good to me. I did also update some of the methods
used in this series in my dynamic queue suite, but the functionality
should still be the same as what you have here so I'm unsure if it is
worth pulling in my other changes or keeping what you have and
resolving it at the time of merge.

On Fri, Jun 28, 2024 at 12:20 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>
> ---
<snip>
> +    def set_verbose(self, level: int, verify: bool = True):
> +        """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

We should probably indent these 3 lines like they are in the VLAN test suite.



> +            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", "")
> --
> 2.44.0
>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v4 2/3] dts: initial queue start/stop suite implementation
  2024-06-28 16:19   ` [PATCH v4 2/3] dts: initial queue start/stop suite implementation Dean Marx
@ 2024-07-01 20:17     ` Jeremy Spewock
  0 siblings, 0 replies; 51+ messages in thread
From: Jeremy Spewock @ 2024-07-01 20:17 UTC (permalink / raw)
  To: Dean Marx
  Cc: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, bruce.richardson, luca.vizzarro, dev

On Fri, Jun 28, 2024 at 12:20 PM Dean Marx <dmarx@iol.unh.edu> wrote:
>
> This suite tests the ability of the Poll Mode Driver to enable
> and disable Rx/Tx queues on a port.
>
> Signed-off-by: Dean Marx <dmarx@iol.unh.edu>
> ---
>  dts/tests/TestSuite_queue_start_stop.py | 95 +++++++++++++++++++++++++
>  1 file changed, 95 insertions(+)
>  create mode 100644 dts/tests/TestSuite_queue_start_stop.py
>
> diff --git a/dts/tests/TestSuite_queue_start_stop.py b/dts/tests/TestSuite_queue_start_stop.py
> new file mode 100644
> index 0000000000..48306cf03c
> --- /dev/null
> +++ b/dts/tests/TestSuite_queue_start_stop.py
> @@ -0,0 +1,95 @@
> +# SPDX-License-Identifier: BSD-3-Clause
> +# Copyright(c) 2024 University of New Hampshire
> +
> +"""Rx/Tx queue start and stop functionality suite.
> +
> +This suite tests the ability of the poll mode driver to start and
> +stop either the Rx or Tx queue (depending on the port) during runtime,
> +and verify that packets are not received when one is disabled.
> +
> +Given a paired port topology, the Rx queue will be disabled on port 0,
> +and the Tx queue will be disabled on port 1.
> +
> +"""
> +
> +from scapy.layers.inet import IP  # type: ignore[import]
> +from scapy.layers.l2 import Ether  # type: ignore[import]
> +from scapy.packet import Raw  # type: ignore[import]
> +
> +from framework.remote_session.testpmd_shell import SimpleForwardingModes, TestPmdShell
> +from framework.test_suite import TestSuite
> +
> +
> +class TestQueueStartStop(TestSuite):
> +    """DPDK Queue start/stop test suite.
> +
> +    Ensures Rx/Tx queue on a port can be disabled and enabled.
> +    Verifies packets are not received when either queue is disabled.
> +    The suite contains two test cases, Rx queue start/stop and
> +    Tx queue start/stop, which each disable the corresponding
> +    queue and verify that packets are not received/forwarded.
> +    """
> +
> +    def set_up_suite(self) -> None:
> +        """Set up the test suite.
> +
> +        Setup:
> +            Verify that at least two ports are open for session.
> +        """
> +        self.verify(len(self._port_links) > 1, "Not enough ports")
> +
> +    def send_packet_and_verify(self, should_receive: bool = True):
> +        """Generate a packet, send to the DUT, and verify it is forwarded back.
> +
> +        Args:
> +            should_receive: Indicate whether the packet should be received.
> +            queue_type: Indicate which port should be verified (True for Rx, False for Tx.)

This arg doesn't seem to be part of this method anymore, we should
pull it from the documentation too.

> +        """
> +        packet = Ether() / IP() / Raw(load="xxxxx")
> +        received = self.send_packet_and_capture(packet)
> +        contains_packet = any(
> +            packet.haslayer(Raw) and b"xxxxx" in packet.load for packet in received
> +        )
> +        self.verify(
> +            should_receive == contains_packet,
> +            f"Packet was {'dropped' if should_receive else 'received'}",
> +        )
> +
<snip>


> --
> 2.44.0
>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v5 1/3] dts: add functions to testpmd shell
  2024-06-17 19:46 [PATCH v2 0/3] dts: queue start/stop suite Dean Marx
                   ` (5 preceding siblings ...)
  2024-06-28 16:19 ` [PATCH v4 1/3] dts: add functions to testpmd shell Dean Marx
@ 2024-07-03 18:08 ` Dean Marx
  2024-07-03 18:08   ` [PATCH v5 2/3] dts: initial queue start/stop suite implementation Dean Marx
                     ` (2 more replies)
  2024-07-10 16:01 ` [PATCH v6 " Dean Marx
                   ` (2 subsequent siblings)
  9 siblings, 3 replies; 51+ messages in thread
From: Dean Marx @ 2024-07-03 18:08 UTC (permalink / raw)
  To: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, jspewock, bruce.richardson, luca.vizzarro
  Cc: dev, Dean Marx

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 | 192 ++++++++++++++++++
 1 file changed, 192 insertions(+)

diff --git a/dts/framework/remote_session/testpmd_shell.py b/dts/framework/remote_session/testpmd_shell.py
index ec22f72221..d744031857 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,6 +848,156 @@ def show_port_stats(self, port_id: int) -> TestPmdPortStats:
 
         return TestPmdPortStats.parse(output)
 
+    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):
+        """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):
+        """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", "")
-- 
2.44.0


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v5 2/3] dts: initial queue start/stop suite implementation
  2024-07-03 18:08 ` [PATCH v5 " Dean Marx
@ 2024-07-03 18:08   ` Dean Marx
  2024-07-10 15:36     ` Jeremy Spewock
  2024-07-03 18:08   ` [PATCH v5 3/3] dts: queue suite conf schema Dean Marx
  2024-07-10 15:36   ` [PATCH v5 1/3] dts: add functions to testpmd shell Jeremy Spewock
  2 siblings, 1 reply; 51+ messages in thread
From: Dean Marx @ 2024-07-03 18:08 UTC (permalink / raw)
  To: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, jspewock, bruce.richardson, luca.vizzarro
  Cc: dev, Dean Marx

This suite tests the ability of the Poll Mode Driver to enable
and disable Rx/Tx queues on a port.

Signed-off-by: Dean Marx <dmarx@iol.unh.edu>
---
 dts/tests/TestSuite_queue_start_stop.py | 94 +++++++++++++++++++++++++
 1 file changed, 94 insertions(+)
 create mode 100644 dts/tests/TestSuite_queue_start_stop.py

diff --git a/dts/tests/TestSuite_queue_start_stop.py b/dts/tests/TestSuite_queue_start_stop.py
new file mode 100644
index 0000000000..644e2113fd
--- /dev/null
+++ b/dts/tests/TestSuite_queue_start_stop.py
@@ -0,0 +1,94 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2024 University of New Hampshire
+
+"""Rx/Tx queue start and stop functionality suite.
+
+This suite tests the ability of the poll mode driver to start and
+stop either the Rx or Tx queue (depending on the port) during runtime,
+and verify that packets are not received when one is disabled.
+
+Given a paired port topology, the Rx queue will be disabled on port 0,
+and the Tx queue will be disabled on port 1.
+
+"""
+
+from scapy.layers.inet import IP  # type: ignore[import-untyped]
+from scapy.layers.l2 import Ether  # type: ignore[import-untyped]
+from scapy.packet import Raw  # type: ignore[import-untyped]
+
+from framework.remote_session.testpmd_shell import SimpleForwardingModes, TestPmdShell
+from framework.test_suite import TestSuite
+
+
+class TestQueueStartStop(TestSuite):
+    """DPDK Queue start/stop test suite.
+
+    Ensures Rx/Tx queue on a port can be disabled and enabled.
+    Verifies packets are not received when either queue is disabled.
+    The suite contains two test cases, Rx queue start/stop and
+    Tx queue start/stop, which each disable the corresponding
+    queue and verify that packets are not received/forwarded.
+    """
+
+    def set_up_suite(self) -> None:
+        """Set up the test suite.
+
+        Setup:
+            Verify that at least two ports are open for session.
+        """
+        self.verify(len(self._port_links) > 1, "Not enough ports")
+
+    def send_packet_and_verify(self, should_receive: bool = True):
+        """Generate a packet, send to the DUT, and verify it is forwarded back.
+
+        Args:
+            should_receive: Indicate whether the packet should be received.
+        """
+        packet = Ether() / IP() / Raw(load="xxxxx")
+        received = self.send_packet_and_capture(packet)
+        contains_packet = any(
+            packet.haslayer(Raw) and b"xxxxx" in packet.load for packet in received
+        )
+        self.verify(
+            should_receive == contains_packet,
+            f"Packet was {'dropped' if should_receive else 'received'}",
+        )
+
+    def test_rx_queue_start_stop(self) -> None:
+        """Verify packets are not received by port 0 when Rx queue is disabled.
+
+        Test:
+            Create an interactive testpmd session, stop Rx queue on port 0, verify
+            packets are not received.
+        """
+        testpmd = TestPmdShell(node=self.sut_node)
+        testpmd.set_forward_mode(SimpleForwardingModes.mac)
+        testpmd.stop_port_queue(0, 0, True)
+
+        testpmd.start()
+        self.send_packet_and_verify(should_receive=False)
+        stats = testpmd.show_port_stats(port_id=0)
+        self.verify(
+            stats.rx_packets == 0,
+            "Packets were received on Rx queue when it should've been disabled",
+        )
+        testpmd.close()
+
+    def test_tx_queue_start_stop(self) -> None:
+        """Verify packets are not forwarded by port 1 when Tx queue is disabled.
+
+        Test:
+            Create an interactive testpmd session, stop Tx queue on port 1, verify
+            packets are not forwarded.
+        """
+        testpmd = TestPmdShell(node=self.sut_node)
+        testpmd.set_forward_mode(SimpleForwardingModes.mac)
+        testpmd.stop_port_queue(1, 0, False)
+        testpmd.start()
+        self.send_packet_and_verify(should_receive=False)
+        stats = testpmd.show_port_stats(port_id=1)
+        self.verify(
+            stats.tx_packets == 0,
+            "Packets were forwarded on Tx queue when it should've been disabled",
+        )
+        testpmd.close()
-- 
2.44.0


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v5 3/3] dts: queue suite conf schema
  2024-07-03 18:08 ` [PATCH v5 " Dean Marx
  2024-07-03 18:08   ` [PATCH v5 2/3] dts: initial queue start/stop suite implementation Dean Marx
@ 2024-07-03 18:08   ` Dean Marx
  2024-07-10 15:37     ` Jeremy Spewock
  2024-07-10 15:36   ` [PATCH v5 1/3] dts: add functions to testpmd shell Jeremy Spewock
  2 siblings, 1 reply; 51+ messages in thread
From: Dean Marx @ 2024-07-03 18:08 UTC (permalink / raw)
  To: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, jspewock, bruce.richardson, luca.vizzarro
  Cc: dev, Dean Marx

Configuration schema for the queue_start_stop suite.

Signed-off-by: Dean Marx <dmarx@iol.unh.edu>
---
 dts/framework/config/conf_yaml_schema.json | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/dts/framework/config/conf_yaml_schema.json b/dts/framework/config/conf_yaml_schema.json
index f02a310bb5..9882ddb3d8 100644
--- a/dts/framework/config/conf_yaml_schema.json
+++ b/dts/framework/config/conf_yaml_schema.json
@@ -187,7 +187,8 @@
       "enum": [
         "hello_world",
         "os_udp",
-        "pmd_buffer_scatter"
+        "pmd_buffer_scatter",
+        "queue_start_stop"
       ]
     },
     "test_target": {
-- 
2.44.0


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v5 1/3] dts: add functions to testpmd shell
  2024-07-03 18:08 ` [PATCH v5 " Dean Marx
  2024-07-03 18:08   ` [PATCH v5 2/3] dts: initial queue start/stop suite implementation Dean Marx
  2024-07-03 18:08   ` [PATCH v5 3/3] dts: queue suite conf schema Dean Marx
@ 2024-07-10 15:36   ` Jeremy Spewock
  2 siblings, 0 replies; 51+ messages in thread
From: Jeremy Spewock @ 2024-07-10 15:36 UTC (permalink / raw)
  To: Dean Marx
  Cc: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, bruce.richardson, luca.vizzarro, dev

All of the code here looks good to me, if you end up putting in a new
version for adding the comment that I mentioned on the other commit it
might be worth changing the name of this commit again to something
like add queue functions to testpmd, but I'm not sure this is super
critical since you explain them in the body of the commit. Otherwise:

Reviewed-by: Jeremy Spewock <jspewock@iol.unh.edu>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v5 2/3] dts: initial queue start/stop suite implementation
  2024-07-03 18:08   ` [PATCH v5 2/3] dts: initial queue start/stop suite implementation Dean Marx
@ 2024-07-10 15:36     ` Jeremy Spewock
  0 siblings, 0 replies; 51+ messages in thread
From: Jeremy Spewock @ 2024-07-10 15:36 UTC (permalink / raw)
  To: Dean Marx
  Cc: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, bruce.richardson, luca.vizzarro, dev

Hey Dean, everything looks good here to me, but I had one thought
about how we do the verification below.

On Wed, Jul 3, 2024 at 2:08 PM Dean Marx <dmarx@iol.unh.edu> wrote:
<snip>
> +
> +    def test_rx_queue_start_stop(self) -> None:
> +        """Verify packets are not received by port 0 when Rx queue is disabled.
> +
> +        Test:
> +            Create an interactive testpmd session, stop Rx queue on port 0, verify
> +            packets are not received.
> +        """
> +        testpmd = TestPmdShell(node=self.sut_node)
> +        testpmd.set_forward_mode(SimpleForwardingModes.mac)
> +        testpmd.stop_port_queue(0, 0, True)
> +
> +        testpmd.start()
> +        self.send_packet_and_verify(should_receive=False)
> +        stats = testpmd.show_port_stats(port_id=0)
> +        self.verify(
> +            stats.rx_packets == 0,
> +            "Packets were received on Rx queue when it should've been disabled",
> +        )

Thinking more about this verification step, I think it makes a lot of
sense why we can verify here using port stats even though we usually
can't. One thing I was thinking about with this however is I think
there is a (probably small) chance that before you get the chance to
stop the port after opening testpmd, a packet is sent to it. When I
tested this it seemed like this verification step worked with some
NICs (like one I ran with on the bnxt_en driver), but specifically
because when you stop the Rx queue it clears all of the Rx stats on
the port. I'm not sure if this is something PMD specific or not, but
it might be worth putting a small comment in here that explains that
disabling the queue will reset the stats and that we then don't expect
the stat to grow from that point on at all.

If handling this number is something PMD specific, another alternative
route we could take would be taking the statistics that are returned
from the "stop" command. I think this would work because the
statistics from the stop command are only aggregated while packet
forwarding is running, and we know that we stopped the queue before
starting forwarding so that number should truly always be 0.



> +        testpmd.close()
> +
> +    def test_tx_queue_start_stop(self) -> None:
> +        """Verify packets are not forwarded by port 1 when Tx queue is disabled.
> +
> +        Test:
> +            Create an interactive testpmd session, stop Tx queue on port 1, verify
> +            packets are not forwarded.
> +        """
> +        testpmd = TestPmdShell(node=self.sut_node)
> +        testpmd.set_forward_mode(SimpleForwardingModes.mac)
> +        testpmd.stop_port_queue(1, 0, False)
> +        testpmd.start()
> +        self.send_packet_and_verify(should_receive=False)
> +        stats = testpmd.show_port_stats(port_id=1)
> +        self.verify(
> +            stats.tx_packets == 0,
> +            "Packets were forwarded on Tx queue when it should've been disabled",
> +        )
> +        testpmd.close()
> --
> 2.44.0
>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v5 3/3] dts: queue suite conf schema
  2024-07-03 18:08   ` [PATCH v5 3/3] dts: queue suite conf schema Dean Marx
@ 2024-07-10 15:37     ` Jeremy Spewock
  0 siblings, 0 replies; 51+ messages in thread
From: Jeremy Spewock @ 2024-07-10 15:37 UTC (permalink / raw)
  To: Dean Marx
  Cc: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, bruce.richardson, luca.vizzarro, dev

On Wed, Jul 3, 2024 at 2:08 PM Dean Marx <dmarx@iol.unh.edu> wrote:
>
> Configuration schema for the queue_start_stop suite.
>
> Signed-off-by: Dean Marx <dmarx@iol.unh.edu>
> ---
Reviewed-by: Jeremy Spewock <jspewock@iol.unh.edu>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v6 1/3] dts: add functions to testpmd shell
  2024-06-17 19:46 [PATCH v2 0/3] dts: queue start/stop suite Dean Marx
                   ` (6 preceding siblings ...)
  2024-07-03 18:08 ` [PATCH v5 " Dean Marx
@ 2024-07-10 16:01 ` Dean Marx
  2024-07-10 16:01   ` [PATCH v6 2/3] dts: initial queue start/stop suite implementation Dean Marx
                     ` (2 more replies)
  2024-07-17 20:23 ` [PATCH v7 " Dean Marx
  2024-07-24 18:32 ` [PATCH v8 0/3] dts: refactored queue start/stop suite Dean Marx
  9 siblings, 3 replies; 51+ messages in thread
From: Dean Marx @ 2024-07-10 16:01 UTC (permalink / raw)
  To: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, jspewock, bruce.richardson, luca.vizzarro
  Cc: dev, Dean Marx

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(-)

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()
-- 
2.44.0


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v6 2/3] dts: initial queue start/stop suite implementation
  2024-07-10 16:01 ` [PATCH v6 " Dean Marx
@ 2024-07-10 16:01   ` Dean Marx
  2024-07-11 13:58     ` Jeremy Spewock
  2024-07-10 16:01   ` [PATCH v6 3/3] dts: queue suite conf schema Dean Marx
  2024-07-11 13:59   ` [PATCH v6 1/3] dts: add functions to testpmd shell Jeremy Spewock
  2 siblings, 1 reply; 51+ messages in thread
From: Dean Marx @ 2024-07-10 16:01 UTC (permalink / raw)
  To: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, jspewock, bruce.richardson, luca.vizzarro
  Cc: dev, Dean Marx

This suite tests the ability of the Poll Mode Driver to enable
and disable Rx/Tx queues on a port.

Signed-off-by: Dean Marx <dmarx@iol.unh.edu>
---
 dts/tests/TestSuite_queue_start_stop.py | 94 +++++++++++++++++++++++++
 1 file changed, 94 insertions(+)
 create mode 100644 dts/tests/TestSuite_queue_start_stop.py

diff --git a/dts/tests/TestSuite_queue_start_stop.py b/dts/tests/TestSuite_queue_start_stop.py
new file mode 100644
index 0000000000..a5fa34ef5c
--- /dev/null
+++ b/dts/tests/TestSuite_queue_start_stop.py
@@ -0,0 +1,94 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2024 University of New Hampshire
+
+"""Rx/Tx queue start and stop functionality suite.
+
+This suite tests the ability of the poll mode driver to start and
+stop either the Rx or Tx queue (depending on the port) during runtime,
+and verify that packets are not received when one is disabled.
+
+Given a paired port topology, the Rx queue will be disabled on port 0,
+and the Tx queue will be disabled on port 1.
+
+"""
+
+from scapy.layers.inet import IP  # type: ignore[import-untyped]
+from scapy.layers.l2 import Ether  # type: ignore[import-untyped]
+from scapy.packet import Raw  # type: ignore[import-untyped]
+
+from framework.remote_session.testpmd_shell import SimpleForwardingModes, TestPmdShell
+from framework.test_suite import TestSuite
+
+
+class TestQueueStartStop(TestSuite):
+    """DPDK Queue start/stop test suite.
+
+    Ensures Rx/Tx queue on a port can be disabled and enabled.
+    Verifies packets are not received when either queue is disabled.
+    The suite contains two test cases, Rx queue start/stop and
+    Tx queue start/stop, which each disable the corresponding
+    queue and verify that packets are not received/forwarded.
+    """
+
+    def set_up_suite(self) -> None:
+        """Set up the test suite.
+
+        Setup:
+            Verify that at least two ports are open for session.
+        """
+        self.verify(len(self._port_links) > 1, "Not enough ports")
+
+    def send_packet_and_verify(self, should_receive: bool = True) -> None:
+        """Generate a packet, send to the DUT, and verify it is forwarded back.
+
+        Args:
+            should_receive: Indicate whether the packet should be received.
+        """
+        packet = Ether() / IP() / Raw(load="xxxxx")
+        received = self.send_packet_and_capture(packet)
+        contains_packet = any(
+            packet.haslayer(Raw) and b"xxxxx" in packet.load for packet in received
+        )
+        self.verify(
+            should_receive == contains_packet,
+            f"Packet was {'dropped' if should_receive else 'received'}",
+        )
+
+    def test_rx_queue_start_stop(self) -> None:
+        """Verify packets are not received by port 0 when Rx queue is disabled.
+
+        Test:
+            Create an interactive testpmd session, stop Rx queue on port 0, verify
+            packets are not received.
+        """
+        testpmd = TestPmdShell(node=self.sut_node)
+        testpmd.set_forward_mode(SimpleForwardingModes.mac)
+        testpmd.stop_port_queue(0, 0, True)
+
+        testpmd.start()
+        self.send_packet_and_verify(should_receive=False)
+        stats = testpmd.show_port_stats(port_id=0)
+        self.verify(
+            stats.rx_packets == 0,
+            "Packets were received on Rx queue when it should've been disabled",
+        )
+        testpmd.close()
+
+    def test_tx_queue_start_stop(self) -> None:
+        """Verify packets are not forwarded by port 1 when Tx queue is disabled.
+
+        Test:
+            Create an interactive testpmd session, stop Tx queue on port 1, verify
+            packets are not forwarded.
+        """
+        testpmd = TestPmdShell(node=self.sut_node)
+        testpmd.set_forward_mode(SimpleForwardingModes.mac)
+        testpmd.stop_port_queue(1, 0, False)
+        testpmd.start()
+        self.send_packet_and_verify(should_receive=False)
+        stats = testpmd.show_port_stats(port_id=1)
+        self.verify(
+            stats.tx_packets == 0,
+            "Packets were forwarded on Tx queue when it should've been disabled",
+        )
+        testpmd.close()
-- 
2.44.0


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v6 3/3] dts: queue suite conf schema
  2024-07-10 16:01 ` [PATCH v6 " Dean Marx
  2024-07-10 16:01   ` [PATCH v6 2/3] dts: initial queue start/stop suite implementation Dean Marx
@ 2024-07-10 16:01   ` Dean Marx
  2024-07-11 13:59   ` [PATCH v6 1/3] dts: add functions to testpmd shell Jeremy Spewock
  2 siblings, 0 replies; 51+ messages in thread
From: Dean Marx @ 2024-07-10 16:01 UTC (permalink / raw)
  To: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, jspewock, bruce.richardson, luca.vizzarro
  Cc: dev, Dean Marx

Configuration schema for the queue_start_stop suite.

Signed-off-by: Dean Marx <dmarx@iol.unh.edu>
---
 dts/framework/config/conf_yaml_schema.json | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/dts/framework/config/conf_yaml_schema.json b/dts/framework/config/conf_yaml_schema.json
index f02a310bb5..9882ddb3d8 100644
--- a/dts/framework/config/conf_yaml_schema.json
+++ b/dts/framework/config/conf_yaml_schema.json
@@ -187,7 +187,8 @@
       "enum": [
         "hello_world",
         "os_udp",
-        "pmd_buffer_scatter"
+        "pmd_buffer_scatter",
+        "queue_start_stop"
       ]
     },
     "test_target": {
-- 
2.44.0


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v6 2/3] dts: initial queue start/stop suite implementation
  2024-07-10 16:01   ` [PATCH v6 2/3] dts: initial queue start/stop suite implementation Dean Marx
@ 2024-07-11 13:58     ` Jeremy Spewock
  0 siblings, 0 replies; 51+ messages in thread
From: Jeremy Spewock @ 2024-07-11 13:58 UTC (permalink / raw)
  To: Dean Marx
  Cc: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, bruce.richardson, luca.vizzarro, dev

On Wed, Jul 10, 2024 at 12:01 PM Dean Marx <dmarx@iol.unh.edu> wrote:
>
> This suite tests the ability of the Poll Mode Driver to enable
> and disable Rx/Tx queues on a port.
>
> Signed-off-by: Dean Marx <dmarx@iol.unh.edu>
> ---

Reviewed-by: Jeremy Spewock<jspewock@iol.unh.edu>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v6 1/3] dts: add functions to testpmd shell
  2024-07-10 16:01 ` [PATCH v6 " Dean Marx
  2024-07-10 16:01   ` [PATCH v6 2/3] dts: initial queue start/stop suite implementation Dean Marx
  2024-07-10 16:01   ` [PATCH v6 3/3] dts: queue suite conf schema Dean Marx
@ 2024-07-11 13:59   ` Jeremy Spewock
  2 siblings, 0 replies; 51+ messages in thread
From: Jeremy Spewock @ 2024-07-11 13:59 UTC (permalink / raw)
  To: Dean Marx
  Cc: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, bruce.richardson, luca.vizzarro, dev

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
>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v7 1/3] dts: add functions to testpmd shell
  2024-06-17 19:46 [PATCH v2 0/3] dts: queue start/stop suite Dean Marx
                   ` (7 preceding siblings ...)
  2024-07-10 16:01 ` [PATCH v6 " Dean Marx
@ 2024-07-17 20:23 ` Dean Marx
  2024-07-17 20:23   ` [PATCH v7 2/3] dts: initial queue start/stop suite implementation Dean Marx
                     ` (2 more replies)
  2024-07-24 18:32 ` [PATCH v8 0/3] dts: refactored queue start/stop suite Dean Marx
  9 siblings, 3 replies; 51+ messages in thread
From: Dean Marx @ 2024-07-17 20:23 UTC (permalink / raw)
  To: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, jspewock, bruce.richardson, luca.vizzarro
  Cc: dev, Dean Marx

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 | 192 ++++++++++++++++++
 1 file changed, 192 insertions(+)

diff --git a/dts/framework/remote_session/testpmd_shell.py b/dts/framework/remote_session/testpmd_shell.py
index ec22f72221..57547b07b1 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,6 +848,156 @@ def show_port_stats(self, port_id: int) -> TestPmdPortStats:
 
         return TestPmdPortStats.parse(output)
 
+    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", "")
-- 
2.44.0


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v7 2/3] dts: initial queue start/stop suite implementation
  2024-07-17 20:23 ` [PATCH v7 " Dean Marx
@ 2024-07-17 20:23   ` Dean Marx
  2024-07-19 13:34     ` Jeremy Spewock
  2024-07-17 20:23   ` [PATCH v7 3/3] dts: queue suite conf schema Dean Marx
  2024-07-19 13:34   ` [PATCH v7 1/3] dts: add functions to testpmd shell Jeremy Spewock
  2 siblings, 1 reply; 51+ messages in thread
From: Dean Marx @ 2024-07-17 20:23 UTC (permalink / raw)
  To: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, jspewock, bruce.richardson, luca.vizzarro
  Cc: dev, Dean Marx

This suite tests the ability of the Poll Mode Driver to enable
and disable Rx/Tx queues on a port.

Signed-off-by: Dean Marx <dmarx@iol.unh.edu>
---
 dts/tests/TestSuite_queue_start_stop.py | 94 +++++++++++++++++++++++++
 1 file changed, 94 insertions(+)
 create mode 100644 dts/tests/TestSuite_queue_start_stop.py

diff --git a/dts/tests/TestSuite_queue_start_stop.py b/dts/tests/TestSuite_queue_start_stop.py
new file mode 100644
index 0000000000..a5fa34ef5c
--- /dev/null
+++ b/dts/tests/TestSuite_queue_start_stop.py
@@ -0,0 +1,94 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2024 University of New Hampshire
+
+"""Rx/Tx queue start and stop functionality suite.
+
+This suite tests the ability of the poll mode driver to start and
+stop either the Rx or Tx queue (depending on the port) during runtime,
+and verify that packets are not received when one is disabled.
+
+Given a paired port topology, the Rx queue will be disabled on port 0,
+and the Tx queue will be disabled on port 1.
+
+"""
+
+from scapy.layers.inet import IP  # type: ignore[import-untyped]
+from scapy.layers.l2 import Ether  # type: ignore[import-untyped]
+from scapy.packet import Raw  # type: ignore[import-untyped]
+
+from framework.remote_session.testpmd_shell import SimpleForwardingModes, TestPmdShell
+from framework.test_suite import TestSuite
+
+
+class TestQueueStartStop(TestSuite):
+    """DPDK Queue start/stop test suite.
+
+    Ensures Rx/Tx queue on a port can be disabled and enabled.
+    Verifies packets are not received when either queue is disabled.
+    The suite contains two test cases, Rx queue start/stop and
+    Tx queue start/stop, which each disable the corresponding
+    queue and verify that packets are not received/forwarded.
+    """
+
+    def set_up_suite(self) -> None:
+        """Set up the test suite.
+
+        Setup:
+            Verify that at least two ports are open for session.
+        """
+        self.verify(len(self._port_links) > 1, "Not enough ports")
+
+    def send_packet_and_verify(self, should_receive: bool = True) -> None:
+        """Generate a packet, send to the DUT, and verify it is forwarded back.
+
+        Args:
+            should_receive: Indicate whether the packet should be received.
+        """
+        packet = Ether() / IP() / Raw(load="xxxxx")
+        received = self.send_packet_and_capture(packet)
+        contains_packet = any(
+            packet.haslayer(Raw) and b"xxxxx" in packet.load for packet in received
+        )
+        self.verify(
+            should_receive == contains_packet,
+            f"Packet was {'dropped' if should_receive else 'received'}",
+        )
+
+    def test_rx_queue_start_stop(self) -> None:
+        """Verify packets are not received by port 0 when Rx queue is disabled.
+
+        Test:
+            Create an interactive testpmd session, stop Rx queue on port 0, verify
+            packets are not received.
+        """
+        testpmd = TestPmdShell(node=self.sut_node)
+        testpmd.set_forward_mode(SimpleForwardingModes.mac)
+        testpmd.stop_port_queue(0, 0, True)
+
+        testpmd.start()
+        self.send_packet_and_verify(should_receive=False)
+        stats = testpmd.show_port_stats(port_id=0)
+        self.verify(
+            stats.rx_packets == 0,
+            "Packets were received on Rx queue when it should've been disabled",
+        )
+        testpmd.close()
+
+    def test_tx_queue_start_stop(self) -> None:
+        """Verify packets are not forwarded by port 1 when Tx queue is disabled.
+
+        Test:
+            Create an interactive testpmd session, stop Tx queue on port 1, verify
+            packets are not forwarded.
+        """
+        testpmd = TestPmdShell(node=self.sut_node)
+        testpmd.set_forward_mode(SimpleForwardingModes.mac)
+        testpmd.stop_port_queue(1, 0, False)
+        testpmd.start()
+        self.send_packet_and_verify(should_receive=False)
+        stats = testpmd.show_port_stats(port_id=1)
+        self.verify(
+            stats.tx_packets == 0,
+            "Packets were forwarded on Tx queue when it should've been disabled",
+        )
+        testpmd.close()
-- 
2.44.0


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v7 3/3] dts: queue suite conf schema
  2024-07-17 20:23 ` [PATCH v7 " Dean Marx
  2024-07-17 20:23   ` [PATCH v7 2/3] dts: initial queue start/stop suite implementation Dean Marx
@ 2024-07-17 20:23   ` Dean Marx
  2024-07-19 13:34     ` Jeremy Spewock
  2024-07-19 13:34   ` [PATCH v7 1/3] dts: add functions to testpmd shell Jeremy Spewock
  2 siblings, 1 reply; 51+ messages in thread
From: Dean Marx @ 2024-07-17 20:23 UTC (permalink / raw)
  To: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, jspewock, bruce.richardson, luca.vizzarro
  Cc: dev, Dean Marx

Configuration schema for the queue_start_stop suite.

Signed-off-by: Dean Marx <dmarx@iol.unh.edu>
---
 dts/framework/config/conf_yaml_schema.json | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/dts/framework/config/conf_yaml_schema.json b/dts/framework/config/conf_yaml_schema.json
index f02a310bb5..9882ddb3d8 100644
--- a/dts/framework/config/conf_yaml_schema.json
+++ b/dts/framework/config/conf_yaml_schema.json
@@ -187,7 +187,8 @@
       "enum": [
         "hello_world",
         "os_udp",
-        "pmd_buffer_scatter"
+        "pmd_buffer_scatter",
+        "queue_start_stop"
       ]
     },
     "test_target": {
-- 
2.44.0


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v7 1/3] dts: add functions to testpmd shell
  2024-07-17 20:23 ` [PATCH v7 " Dean Marx
  2024-07-17 20:23   ` [PATCH v7 2/3] dts: initial queue start/stop suite implementation Dean Marx
  2024-07-17 20:23   ` [PATCH v7 3/3] dts: queue suite conf schema Dean Marx
@ 2024-07-19 13:34   ` Jeremy Spewock
  2 siblings, 0 replies; 51+ messages in thread
From: Jeremy Spewock @ 2024-07-19 13:34 UTC (permalink / raw)
  To: Dean Marx
  Cc: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, bruce.richardson, luca.vizzarro, dev

On Wed, Jul 17, 2024 at 4:23 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>

Reviewed-by: Jeremy Spewock <jspewock@iol.unh.edu>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v7 2/3] dts: initial queue start/stop suite implementation
  2024-07-17 20:23   ` [PATCH v7 2/3] dts: initial queue start/stop suite implementation Dean Marx
@ 2024-07-19 13:34     ` Jeremy Spewock
  2024-07-23 17:04       ` Adam Hassick
  0 siblings, 1 reply; 51+ messages in thread
From: Jeremy Spewock @ 2024-07-19 13:34 UTC (permalink / raw)
  To: Dean Marx
  Cc: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, bruce.richardson, luca.vizzarro, dev

On Wed, Jul 17, 2024 at 4:23 PM Dean Marx <dmarx@iol.unh.edu> wrote:
>
> This suite tests the ability of the Poll Mode Driver to enable
> and disable Rx/Tx queues on a port.
>
> Signed-off-by: Dean Marx <dmarx@iol.unh.edu>

Reviewed-by: Jeremy Spewock <jspewock@iol.unh.edu>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v7 3/3] dts: queue suite conf schema
  2024-07-17 20:23   ` [PATCH v7 3/3] dts: queue suite conf schema Dean Marx
@ 2024-07-19 13:34     ` Jeremy Spewock
  0 siblings, 0 replies; 51+ messages in thread
From: Jeremy Spewock @ 2024-07-19 13:34 UTC (permalink / raw)
  To: Dean Marx
  Cc: Honnappa.Nagarahalli, juraj.linkes, probb, paul.szczepanek,
	yoan.picchi, bruce.richardson, luca.vizzarro, dev

On Wed, Jul 17, 2024 at 4:23 PM Dean Marx <dmarx@iol.unh.edu> wrote:
>
> Configuration schema for the queue_start_stop suite.
>
> Signed-off-by: Dean Marx <dmarx@iol.unh.edu>

Reviewed-by: Jeremy Spewock <jspewock@iol.unh.edu>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v7 2/3] dts: initial queue start/stop suite implementation
  2024-07-19 13:34     ` Jeremy Spewock
@ 2024-07-23 17:04       ` Adam Hassick
  0 siblings, 0 replies; 51+ messages in thread
From: Adam Hassick @ 2024-07-23 17:04 UTC (permalink / raw)
  To: Jeremy Spewock
  Cc: Dean Marx, Honnappa.Nagarahalli, juraj.linkes, probb,
	paul.szczepanek, yoan.picchi, bruce.richardson, luca.vizzarro,
	dev

Recheck-request: rebase=main, iol-intel-Functional, iol-intel-Performance,

This is a test of the Community Lab's new retest changes. Please ignore.

On Fri, Jul 19, 2024 at 9:34 AM Jeremy Spewock <jspewock@iol.unh.edu> wrote:
>
> On Wed, Jul 17, 2024 at 4:23 PM Dean Marx <dmarx@iol.unh.edu> wrote:
> >
> > This suite tests the ability of the Poll Mode Driver to enable
> > and disable Rx/Tx queues on a port.
> >
> > Signed-off-by: Dean Marx <dmarx@iol.unh.edu>
>
> Reviewed-by: Jeremy Spewock <jspewock@iol.unh.edu>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v8 0/3] dts: refactored queue start/stop suite
  2024-06-17 19:46 [PATCH v2 0/3] dts: queue start/stop suite Dean Marx
                   ` (8 preceding siblings ...)
  2024-07-17 20:23 ` [PATCH v7 " Dean Marx
@ 2024-07-24 18:32 ` Dean Marx
  2024-07-24 18:32   ` [PATCH v8 1/3] dts: add functions to testpmd shell Dean Marx
                     ` (3 more replies)
  9 siblings, 4 replies; 51+ messages in thread
From: Dean Marx @ 2024-07-24 18:32 UTC (permalink / raw)
  To: probb, npratte, jspewock, luca.vizzarro, yoan.picchi,
	Honnappa.Nagarahalli, paul.szczepanek, juraj.linkes
  Cc: dev, Dean Marx

Refactored queue start/stop test suite to be compatible with context
manager. Updated queue setup, stop/start, and show queue info
methods/dataclasses in testpmd shell.

Dean Marx (3):
  dts: add functions to testpmd shell
  dts: initial queue start/stop suite implementation
  dts: queue suite conf schema

 dts/framework/config/conf_yaml_schema.json    |   3 +-
 dts/framework/remote_session/testpmd_shell.py | 232 +++++++++++++++++-
 dts/tests/TestSuite_queue_start_stop.py       |  91 +++++++
 3 files changed, 324 insertions(+), 2 deletions(-)
 create mode 100644 dts/tests/TestSuite_queue_start_stop.py

-- 
2.44.0


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v8 1/3] dts: add functions to testpmd shell
  2024-07-24 18:32 ` [PATCH v8 0/3] dts: refactored queue start/stop suite Dean Marx
@ 2024-07-24 18:32   ` Dean Marx
  2024-07-26 19:19     ` Jeremy Spewock
  2024-07-24 18:32   ` [PATCH v8 2/3] dts: initial queue start/stop suite implementation Dean Marx
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 51+ messages in thread
From: Dean Marx @ 2024-07-24 18:32 UTC (permalink / raw)
  To: probb, npratte, jspewock, luca.vizzarro, yoan.picchi,
	Honnappa.Nagarahalli, paul.szczepanek, juraj.linkes
  Cc: dev, Dean Marx

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 | 232 +++++++++++++++++-
 1 file changed, 231 insertions(+), 1 deletion(-)

diff --git a/dts/framework/remote_session/testpmd_shell.py b/dts/framework/remote_session/testpmd_shell.py
index eda6eb320f..bbc495bdba 100644
--- a/dts/framework/remote_session/testpmd_shell.py
+++ b/dts/framework/remote_session/testpmd_shell.py
@@ -19,7 +19,7 @@
 from dataclasses import dataclass, field
 from enum import Flag, auto
 from pathlib import PurePath
-from typing import ClassVar
+from typing import ClassVar, cast
 
 from typing_extensions import Self, Unpack
 
@@ -577,6 +577,56 @@ class TestPmdPortStats(TextParser):
     tx_bps: int = field(metadata=TextParser.find_int(r"Tx-bps:\s+(\d+)"))
 
 
+@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 | None = field(
+        default=None, metadata=TextParser.find(r"Burst mode: ([^\r\n]+)")
+    )
+
+
+@dataclass
+class TestPmdTxPortQueue(TestPmdPortQueue):
+    """Dataclass representation for testpmd `show txq info` command."""
+
+    #:
+    rs_threshold: int | None = field(
+        default=None, metadata=TextParser.find_int(r"RS threshold: (\d+)")
+    )
+
+
+@dataclass
+class TestPmdRxPortQueue(TestPmdPortQueue):
+    """Dataclass representation for testpmd `show rxq info` command."""
+
+    #:
+    mempool: str | None = field(default=None, metadata=TextParser.find(r"Mempool: ([^\r\n]+)"))
+    #:
+    can_drop_packets: bool | None = field(
+        default=None, metadata=TextParser.find(r"drop packets: on")
+    )
+    #:
+    is_scattering_packets: bool | None = field(
+        default=None, metadata=TextParser.find(r"scattered packets: on")
+    )
+
+
 class TestPmdShell(DPDKShell):
     """Testpmd interactive shell.
 
@@ -804,6 +854,186 @@ def show_port_stats(self, port_id: int) -> TestPmdPortStats:
 
         return TestPmdPortStats.parse(output)
 
+    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 show_port_rx_queue_info(self, port_id: int, queue_id: int) -> TestPmdRxPortQueue:
+        """Get port queue info and cast to :class:`TestPmdRxPortQueue`.
+
+        Wrapper around :meth:`show_port_queue_info` that casts the more generic type into the
+        correct subclass.
+
+        Args:
+            port_id: ID of the port where the queue resides.
+            queue_id: ID of the queue to query.
+
+        Returns:
+            Information about the Rx queue on the given port.
+        """
+        return cast(TestPmdRxPortQueue, self.show_port_queue_info(port_id, queue_id, True))
+
+    def show_port_tx_queue_info(self, port_id: int, queue_id: int) -> TestPmdTxPortQueue:
+        """Get port queue info and cast to :class:`TestPmdTxPortQueue`.
+
+        Wrapper around :meth:`show_port_queue_info` that casts the more generic type into the
+        correct subclass.
+
+        Args:
+            port_id: ID of the port where the queue resides.
+            queue_id: ID of the queue to query.
+
+        Returns:
+            Information about the Tx queue on the given port.
+        """
+        return cast(TestPmdTxPortQueue, self.show_port_queue_info(port_id, queue_id, False))
+
+    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.stop()
-- 
2.44.0


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v8 2/3] dts: initial queue start/stop suite implementation
  2024-07-24 18:32 ` [PATCH v8 0/3] dts: refactored queue start/stop suite Dean Marx
  2024-07-24 18:32   ` [PATCH v8 1/3] dts: add functions to testpmd shell Dean Marx
@ 2024-07-24 18:32   ` Dean Marx
  2024-07-26 19:19     ` Jeremy Spewock
  2024-07-24 18:32   ` [PATCH v8 3/3] dts: queue suite conf schema Dean Marx
  2024-08-07 19:36   ` [PATCH v9 0/2] dts: refactored queue start/stop suite Dean Marx
  3 siblings, 1 reply; 51+ messages in thread
From: Dean Marx @ 2024-07-24 18:32 UTC (permalink / raw)
  To: probb, npratte, jspewock, luca.vizzarro, yoan.picchi,
	Honnappa.Nagarahalli, paul.szczepanek, juraj.linkes
  Cc: dev, Dean Marx

This suite tests the ability of the Poll Mode Driver to enable
and disable Rx/Tx queues on a port.

Signed-off-by: Dean Marx <dmarx@iol.unh.edu>
---
 dts/tests/TestSuite_queue_start_stop.py | 91 +++++++++++++++++++++++++
 1 file changed, 91 insertions(+)
 create mode 100644 dts/tests/TestSuite_queue_start_stop.py

diff --git a/dts/tests/TestSuite_queue_start_stop.py b/dts/tests/TestSuite_queue_start_stop.py
new file mode 100644
index 0000000000..7533f0b395
--- /dev/null
+++ b/dts/tests/TestSuite_queue_start_stop.py
@@ -0,0 +1,91 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2024 University of New Hampshire
+
+"""Rx/Tx queue start and stop functionality suite.
+
+This suite tests the ability of the poll mode driver to start and
+stop either the Rx or Tx queue (depending on the port) during runtime,
+and verify that packets are not received when one is disabled.
+
+Given a paired port topology, the Rx queue will be disabled on port 0,
+and the Tx queue will be disabled on port 1.
+
+"""
+
+from scapy.layers.inet import IP  # type: ignore[import-untyped]
+from scapy.layers.l2 import Ether  # type: ignore[import-untyped]
+from scapy.packet import Raw  # type: ignore[import-untyped]
+
+from framework.remote_session.testpmd_shell import SimpleForwardingModes, TestPmdShell
+from framework.test_suite import TestSuite
+
+
+class TestQueueStartStop(TestSuite):
+    """DPDK Queue start/stop test suite.
+
+    Ensures Rx/Tx queue on a port can be disabled and enabled.
+    Verifies packets are not received when either queue is disabled.
+    The suite contains two test cases, Rx queue start/stop and
+    Tx queue start/stop, which each disable the corresponding
+    queue and verify that packets are not received/forwarded.
+    """
+
+    def set_up_suite(self) -> None:
+        """Set up the test suite.
+
+        Setup:
+            Verify that at least two ports are open for session.
+        """
+        self.verify(len(self._port_links) > 1, "Not enough ports")
+
+    def send_packet_and_verify(self, should_receive: bool = True) -> None:
+        """Generate a packet, send to the DUT, and verify it is forwarded back.
+
+        Args:
+            should_receive: Indicate whether the packet should be received.
+        """
+        packet = Ether() / IP() / Raw(load="xxxxx")
+        received = self.send_packet_and_capture(packet)
+        contains_packet = any(
+            packet.haslayer(Raw) and b"xxxxx" in packet.load for packet in received
+        )
+        self.verify(
+            should_receive == contains_packet,
+            f"Packet was {'dropped' if should_receive else 'received'}",
+        )
+
+    def test_rx_queue_start_stop(self) -> None:
+        """Verify packets are not received by port 0 when Rx queue is disabled.
+
+        Test:
+            Create an interactive testpmd session, stop Rx queue on port 0, verify
+            packets are not received.
+        """
+        with TestPmdShell(node=self.sut_node) as testpmd:
+            testpmd.set_forward_mode(SimpleForwardingModes.mac)
+            testpmd.stop_port_queue(0, 0, True)
+            testpmd.start()
+            self.send_packet_and_verify(should_receive=False)
+            stats = testpmd.show_port_stats(port_id=0)
+            self.verify(
+                stats.rx_packets == 0,
+                "Packets were received on Rx queue when it should've been disabled",
+            )
+
+    def test_tx_queue_start_stop(self) -> None:
+        """Verify packets are not forwarded by port 1 when Tx queue is disabled.
+
+        Test:
+            Create an interactive testpmd session, stop Tx queue on port 1, verify
+            packets are not forwarded.
+        """
+        with TestPmdShell(node=self.sut_node) as testpmd:
+            testpmd.set_forward_mode(SimpleForwardingModes.mac)
+            testpmd.stop_port_queue(1, 0, False)
+            testpmd.start()
+            self.send_packet_and_verify(should_receive=False)
+            stats = testpmd.show_port_stats(port_id=1)
+            self.verify(
+                stats.tx_packets == 0,
+                "Packets were forwarded on Tx queue when it should've been disabled",
+            )
-- 
2.44.0


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v8 3/3] dts: queue suite conf schema
  2024-07-24 18:32 ` [PATCH v8 0/3] dts: refactored queue start/stop suite Dean Marx
  2024-07-24 18:32   ` [PATCH v8 1/3] dts: add functions to testpmd shell Dean Marx
  2024-07-24 18:32   ` [PATCH v8 2/3] dts: initial queue start/stop suite implementation Dean Marx
@ 2024-07-24 18:32   ` Dean Marx
  2024-07-26 19:19     ` Jeremy Spewock
  2024-08-07 19:36   ` [PATCH v9 0/2] dts: refactored queue start/stop suite Dean Marx
  3 siblings, 1 reply; 51+ messages in thread
From: Dean Marx @ 2024-07-24 18:32 UTC (permalink / raw)
  To: probb, npratte, jspewock, luca.vizzarro, yoan.picchi,
	Honnappa.Nagarahalli, paul.szczepanek, juraj.linkes
  Cc: dev, Dean Marx

Configuration schema for the queue_start_stop suite.

Signed-off-by: Dean Marx <dmarx@iol.unh.edu>
---
 dts/framework/config/conf_yaml_schema.json | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/dts/framework/config/conf_yaml_schema.json b/dts/framework/config/conf_yaml_schema.json
index f02a310bb5..9882ddb3d8 100644
--- a/dts/framework/config/conf_yaml_schema.json
+++ b/dts/framework/config/conf_yaml_schema.json
@@ -187,7 +187,8 @@
       "enum": [
         "hello_world",
         "os_udp",
-        "pmd_buffer_scatter"
+        "pmd_buffer_scatter",
+        "queue_start_stop"
       ]
     },
     "test_target": {
-- 
2.44.0


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v8 1/3] dts: add functions to testpmd shell
  2024-07-24 18:32   ` [PATCH v8 1/3] dts: add functions to testpmd shell Dean Marx
@ 2024-07-26 19:19     ` Jeremy Spewock
  0 siblings, 0 replies; 51+ messages in thread
From: Jeremy Spewock @ 2024-07-26 19:19 UTC (permalink / raw)
  To: Dean Marx
  Cc: probb, npratte, luca.vizzarro, yoan.picchi, Honnappa.Nagarahalli,
	paul.szczepanek, juraj.linkes, dev

On Wed, Jul 24, 2024 at 2:32 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>

Reviewed-by: Jeremy Spewock <jspewock@iol.unh.edu>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v8 2/3] dts: initial queue start/stop suite implementation
  2024-07-24 18:32   ` [PATCH v8 2/3] dts: initial queue start/stop suite implementation Dean Marx
@ 2024-07-26 19:19     ` Jeremy Spewock
  0 siblings, 0 replies; 51+ messages in thread
From: Jeremy Spewock @ 2024-07-26 19:19 UTC (permalink / raw)
  To: Dean Marx
  Cc: probb, npratte, luca.vizzarro, yoan.picchi, Honnappa.Nagarahalli,
	paul.szczepanek, juraj.linkes, dev

On Wed, Jul 24, 2024 at 2:32 PM Dean Marx <dmarx@iol.unh.edu> wrote:
>
> This suite tests the ability of the Poll Mode Driver to enable
> and disable Rx/Tx queues on a port.
>
> Signed-off-by: Dean Marx <dmarx@iol.unh.edu>

Reviewed-by: Jeremy Spewock <jspewock@iol.unh.edu>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v8 3/3] dts: queue suite conf schema
  2024-07-24 18:32   ` [PATCH v8 3/3] dts: queue suite conf schema Dean Marx
@ 2024-07-26 19:19     ` Jeremy Spewock
  0 siblings, 0 replies; 51+ messages in thread
From: Jeremy Spewock @ 2024-07-26 19:19 UTC (permalink / raw)
  To: Dean Marx
  Cc: probb, npratte, luca.vizzarro, yoan.picchi, Honnappa.Nagarahalli,
	paul.szczepanek, juraj.linkes, dev

On Wed, Jul 24, 2024 at 2:32 PM Dean Marx <dmarx@iol.unh.edu> wrote:
>
> Configuration schema for the queue_start_stop suite.
>
> Signed-off-by: Dean Marx <dmarx@iol.unh.edu>

Reviewed-by: Jeremy Spewock <jspewock@iol.unh.edu>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v9 0/2] dts: refactored queue start/stop suite
  2024-07-24 18:32 ` [PATCH v8 0/3] dts: refactored queue start/stop suite Dean Marx
                     ` (2 preceding siblings ...)
  2024-07-24 18:32   ` [PATCH v8 3/3] dts: queue suite conf schema Dean Marx
@ 2024-08-07 19:36   ` Dean Marx
  2024-08-07 19:36     ` [PATCH v9 1/2] dts: add functions to testpmd shell Dean Marx
                       ` (2 more replies)
  3 siblings, 3 replies; 51+ messages in thread
From: Dean Marx @ 2024-08-07 19:36 UTC (permalink / raw)
  To: probb, npratte, jspewock, luca.vizzarro, yoan.picchi,
	Honnappa.Nagarahalli, paul.szczepanek, juraj.linkes
  Cc: dev, Dean Marx

*v9: combined conf schema and test suite patches

Dean Marx (2):
  dts: add functions to testpmd shell
  dts: initial queue start/stop suite implementation

 dts/framework/config/conf_yaml_schema.json    |   3 +-
 dts/framework/remote_session/testpmd_shell.py | 232 +++++++++++++++++-
 dts/tests/TestSuite_queue_start_stop.py       |  91 +++++++
 3 files changed, 324 insertions(+), 2 deletions(-)
 create mode 100644 dts/tests/TestSuite_queue_start_stop.py

-- 
2.44.0


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v9 1/2] dts: add functions to testpmd shell
  2024-08-07 19:36   ` [PATCH v9 0/2] dts: refactored queue start/stop suite Dean Marx
@ 2024-08-07 19:36     ` Dean Marx
  2024-08-09 15:51       ` Jeremy Spewock
  2024-08-07 19:36     ` [PATCH v9 2/2] dts: initial queue start/stop suite implementation Dean Marx
  2024-10-08 21:48     ` [PATCH v10 0/1] dts: port over queue start/stop suite Dean Marx
  2 siblings, 1 reply; 51+ messages in thread
From: Dean Marx @ 2024-08-07 19:36 UTC (permalink / raw)
  To: probb, npratte, jspewock, luca.vizzarro, yoan.picchi,
	Honnappa.Nagarahalli, paul.szczepanek, juraj.linkes
  Cc: dev, Dean Marx

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 | 232 +++++++++++++++++-
 1 file changed, 231 insertions(+), 1 deletion(-)

diff --git a/dts/framework/remote_session/testpmd_shell.py b/dts/framework/remote_session/testpmd_shell.py
index eda6eb320f..bbc495bdba 100644
--- a/dts/framework/remote_session/testpmd_shell.py
+++ b/dts/framework/remote_session/testpmd_shell.py
@@ -19,7 +19,7 @@
 from dataclasses import dataclass, field
 from enum import Flag, auto
 from pathlib import PurePath
-from typing import ClassVar
+from typing import ClassVar, cast
 
 from typing_extensions import Self, Unpack
 
@@ -577,6 +577,56 @@ class TestPmdPortStats(TextParser):
     tx_bps: int = field(metadata=TextParser.find_int(r"Tx-bps:\s+(\d+)"))
 
 
+@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 | None = field(
+        default=None, metadata=TextParser.find(r"Burst mode: ([^\r\n]+)")
+    )
+
+
+@dataclass
+class TestPmdTxPortQueue(TestPmdPortQueue):
+    """Dataclass representation for testpmd `show txq info` command."""
+
+    #:
+    rs_threshold: int | None = field(
+        default=None, metadata=TextParser.find_int(r"RS threshold: (\d+)")
+    )
+
+
+@dataclass
+class TestPmdRxPortQueue(TestPmdPortQueue):
+    """Dataclass representation for testpmd `show rxq info` command."""
+
+    #:
+    mempool: str | None = field(default=None, metadata=TextParser.find(r"Mempool: ([^\r\n]+)"))
+    #:
+    can_drop_packets: bool | None = field(
+        default=None, metadata=TextParser.find(r"drop packets: on")
+    )
+    #:
+    is_scattering_packets: bool | None = field(
+        default=None, metadata=TextParser.find(r"scattered packets: on")
+    )
+
+
 class TestPmdShell(DPDKShell):
     """Testpmd interactive shell.
 
@@ -804,6 +854,186 @@ def show_port_stats(self, port_id: int) -> TestPmdPortStats:
 
         return TestPmdPortStats.parse(output)
 
+    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 show_port_rx_queue_info(self, port_id: int, queue_id: int) -> TestPmdRxPortQueue:
+        """Get port queue info and cast to :class:`TestPmdRxPortQueue`.
+
+        Wrapper around :meth:`show_port_queue_info` that casts the more generic type into the
+        correct subclass.
+
+        Args:
+            port_id: ID of the port where the queue resides.
+            queue_id: ID of the queue to query.
+
+        Returns:
+            Information about the Rx queue on the given port.
+        """
+        return cast(TestPmdRxPortQueue, self.show_port_queue_info(port_id, queue_id, True))
+
+    def show_port_tx_queue_info(self, port_id: int, queue_id: int) -> TestPmdTxPortQueue:
+        """Get port queue info and cast to :class:`TestPmdTxPortQueue`.
+
+        Wrapper around :meth:`show_port_queue_info` that casts the more generic type into the
+        correct subclass.
+
+        Args:
+            port_id: ID of the port where the queue resides.
+            queue_id: ID of the queue to query.
+
+        Returns:
+            Information about the Tx queue on the given port.
+        """
+        return cast(TestPmdTxPortQueue, self.show_port_queue_info(port_id, queue_id, False))
+
+    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.stop()
-- 
2.44.0


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v9 2/2] dts: initial queue start/stop suite implementation
  2024-08-07 19:36   ` [PATCH v9 0/2] dts: refactored queue start/stop suite Dean Marx
  2024-08-07 19:36     ` [PATCH v9 1/2] dts: add functions to testpmd shell Dean Marx
@ 2024-08-07 19:36     ` Dean Marx
  2024-08-09 15:52       ` Jeremy Spewock
  2024-10-08 21:48     ` [PATCH v10 0/1] dts: port over queue start/stop suite Dean Marx
  2 siblings, 1 reply; 51+ messages in thread
From: Dean Marx @ 2024-08-07 19:36 UTC (permalink / raw)
  To: probb, npratte, jspewock, luca.vizzarro, yoan.picchi,
	Honnappa.Nagarahalli, paul.szczepanek, juraj.linkes
  Cc: dev, Dean Marx

This suite tests the ability of the Poll Mode Driver to enable
and disable Rx/Tx queues on a port.

Signed-off-by: Dean Marx <dmarx@iol.unh.edu>
---
 dts/framework/config/conf_yaml_schema.json |  3 +-
 dts/tests/TestSuite_queue_start_stop.py    | 91 ++++++++++++++++++++++
 2 files changed, 93 insertions(+), 1 deletion(-)
 create mode 100644 dts/tests/TestSuite_queue_start_stop.py

diff --git a/dts/framework/config/conf_yaml_schema.json b/dts/framework/config/conf_yaml_schema.json
index f02a310bb5..9882ddb3d8 100644
--- a/dts/framework/config/conf_yaml_schema.json
+++ b/dts/framework/config/conf_yaml_schema.json
@@ -187,7 +187,8 @@
       "enum": [
         "hello_world",
         "os_udp",
-        "pmd_buffer_scatter"
+        "pmd_buffer_scatter",
+        "queue_start_stop"
       ]
     },
     "test_target": {
diff --git a/dts/tests/TestSuite_queue_start_stop.py b/dts/tests/TestSuite_queue_start_stop.py
new file mode 100644
index 0000000000..7533f0b395
--- /dev/null
+++ b/dts/tests/TestSuite_queue_start_stop.py
@@ -0,0 +1,91 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2024 University of New Hampshire
+
+"""Rx/Tx queue start and stop functionality suite.
+
+This suite tests the ability of the poll mode driver to start and
+stop either the Rx or Tx queue (depending on the port) during runtime,
+and verify that packets are not received when one is disabled.
+
+Given a paired port topology, the Rx queue will be disabled on port 0,
+and the Tx queue will be disabled on port 1.
+
+"""
+
+from scapy.layers.inet import IP  # type: ignore[import-untyped]
+from scapy.layers.l2 import Ether  # type: ignore[import-untyped]
+from scapy.packet import Raw  # type: ignore[import-untyped]
+
+from framework.remote_session.testpmd_shell import SimpleForwardingModes, TestPmdShell
+from framework.test_suite import TestSuite
+
+
+class TestQueueStartStop(TestSuite):
+    """DPDK Queue start/stop test suite.
+
+    Ensures Rx/Tx queue on a port can be disabled and enabled.
+    Verifies packets are not received when either queue is disabled.
+    The suite contains two test cases, Rx queue start/stop and
+    Tx queue start/stop, which each disable the corresponding
+    queue and verify that packets are not received/forwarded.
+    """
+
+    def set_up_suite(self) -> None:
+        """Set up the test suite.
+
+        Setup:
+            Verify that at least two ports are open for session.
+        """
+        self.verify(len(self._port_links) > 1, "Not enough ports")
+
+    def send_packet_and_verify(self, should_receive: bool = True) -> None:
+        """Generate a packet, send to the DUT, and verify it is forwarded back.
+
+        Args:
+            should_receive: Indicate whether the packet should be received.
+        """
+        packet = Ether() / IP() / Raw(load="xxxxx")
+        received = self.send_packet_and_capture(packet)
+        contains_packet = any(
+            packet.haslayer(Raw) and b"xxxxx" in packet.load for packet in received
+        )
+        self.verify(
+            should_receive == contains_packet,
+            f"Packet was {'dropped' if should_receive else 'received'}",
+        )
+
+    def test_rx_queue_start_stop(self) -> None:
+        """Verify packets are not received by port 0 when Rx queue is disabled.
+
+        Test:
+            Create an interactive testpmd session, stop Rx queue on port 0, verify
+            packets are not received.
+        """
+        with TestPmdShell(node=self.sut_node) as testpmd:
+            testpmd.set_forward_mode(SimpleForwardingModes.mac)
+            testpmd.stop_port_queue(0, 0, True)
+            testpmd.start()
+            self.send_packet_and_verify(should_receive=False)
+            stats = testpmd.show_port_stats(port_id=0)
+            self.verify(
+                stats.rx_packets == 0,
+                "Packets were received on Rx queue when it should've been disabled",
+            )
+
+    def test_tx_queue_start_stop(self) -> None:
+        """Verify packets are not forwarded by port 1 when Tx queue is disabled.
+
+        Test:
+            Create an interactive testpmd session, stop Tx queue on port 1, verify
+            packets are not forwarded.
+        """
+        with TestPmdShell(node=self.sut_node) as testpmd:
+            testpmd.set_forward_mode(SimpleForwardingModes.mac)
+            testpmd.stop_port_queue(1, 0, False)
+            testpmd.start()
+            self.send_packet_and_verify(should_receive=False)
+            stats = testpmd.show_port_stats(port_id=1)
+            self.verify(
+                stats.tx_packets == 0,
+                "Packets were forwarded on Tx queue when it should've been disabled",
+            )
-- 
2.44.0


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v9 1/2] dts: add functions to testpmd shell
  2024-08-07 19:36     ` [PATCH v9 1/2] dts: add functions to testpmd shell Dean Marx
@ 2024-08-09 15:51       ` Jeremy Spewock
  0 siblings, 0 replies; 51+ messages in thread
From: Jeremy Spewock @ 2024-08-09 15:51 UTC (permalink / raw)
  To: Dean Marx
  Cc: probb, npratte, luca.vizzarro, yoan.picchi, Honnappa.Nagarahalli,
	paul.szczepanek, juraj.linkes, dev

On Wed, Aug 7, 2024 at 3:36 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>
> ---

Reviewed-by: Jeremy Spewock <jspewock@iol.unh.edu>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [PATCH v9 2/2] dts: initial queue start/stop suite implementation
  2024-08-07 19:36     ` [PATCH v9 2/2] dts: initial queue start/stop suite implementation Dean Marx
@ 2024-08-09 15:52       ` Jeremy Spewock
  0 siblings, 0 replies; 51+ messages in thread
From: Jeremy Spewock @ 2024-08-09 15:52 UTC (permalink / raw)
  To: Dean Marx
  Cc: probb, npratte, luca.vizzarro, yoan.picchi, Honnappa.Nagarahalli,
	paul.szczepanek, juraj.linkes, dev

On Wed, Aug 7, 2024 at 3:36 PM Dean Marx <dmarx@iol.unh.edu> wrote:
>
> This suite tests the ability of the Poll Mode Driver to enable
> and disable Rx/Tx queues on a port.
>
> Signed-off-by: Dean Marx <dmarx@iol.unh.edu>
> ---

Reviewed-by: Jeremy Spewock <jspewock@iol.unh.edu>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v10 0/1] dts: port over queue start/stop suite
  2024-08-07 19:36   ` [PATCH v9 0/2] dts: refactored queue start/stop suite Dean Marx
  2024-08-07 19:36     ` [PATCH v9 1/2] dts: add functions to testpmd shell Dean Marx
  2024-08-07 19:36     ` [PATCH v9 2/2] dts: initial queue start/stop suite implementation Dean Marx
@ 2024-10-08 21:48     ` Dean Marx
  2024-10-08 21:48       ` [PATCH v10] " Dean Marx
  2 siblings, 1 reply; 51+ messages in thread
From: Dean Marx @ 2024-10-08 21:48 UTC (permalink / raw)
  To: probb, npratte, luca.vizzarro, yoan.picchi, Honnappa.Nagarahalli,
	paul.szczepanek
  Cc: dev, Dean Marx

Queue start/stop suite ensures the Poll Mode Driver can functionally
enable and disable Rx/Tx queues on ports. The suite contains two test
cases:

1. All queues enabled - verifies that packets are received when all
queues on all ports are enabled.
2. Queue start/stop - verifies that packets are not received when the Rx
queue on port 0 is disabled, and then again when the Tx queue on port 1
is disabled.

An important aspect of DPDK is queueing packets for transmission to
bypass the kernel, which makes this test suite necessary to ensure
performance.
--------------
v8:
* Refactored to be compatible with context manager

v9: 
* Combined configuration schema and test suite patches

v10:
* Rebased off next-dts

Dean Marx (1):
  dts: port over queue start/stop suite

 dts/framework/config/conf_yaml_schema.json |  3 ++-
 dts/tests/TestSuite_queue_start_stop.py    | 16 +++++++---------
 2 files changed, 9 insertions(+), 10 deletions(-)

-- 
2.44.0


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [PATCH v10] dts: port over queue start/stop suite
  2024-10-08 21:48     ` [PATCH v10 0/1] dts: port over queue start/stop suite Dean Marx
@ 2024-10-08 21:48       ` Dean Marx
  0 siblings, 0 replies; 51+ messages in thread
From: Dean Marx @ 2024-10-08 21:48 UTC (permalink / raw)
  To: probb, npratte, luca.vizzarro, yoan.picchi, Honnappa.Nagarahalli,
	paul.szczepanek
  Cc: dev, Dean Marx, Jeremy Spewock

This suite tests the ability of the Poll Mode Driver to enable
and disable Rx/Tx queues on a port.

Depends-on: patch-144442 ("dts: add port queue modification
and forwarding stats to testpmd")

Signed-off-by: Dean Marx <dmarx@iol.unh.edu>
Reviewed-by: Jeremy Spewock <jspewock@iol.unh.edu>
---
 dts/framework/config/conf_yaml_schema.json |  3 ++-
 dts/tests/TestSuite_queue_start_stop.py    | 16 +++++++---------
 2 files changed, 9 insertions(+), 10 deletions(-)

diff --git a/dts/framework/config/conf_yaml_schema.json b/dts/framework/config/conf_yaml_schema.json
index df390e8ae2..12a4a26dc8 100644
--- a/dts/framework/config/conf_yaml_schema.json
+++ b/dts/framework/config/conf_yaml_schema.json
@@ -187,7 +187,8 @@
       "enum": [
         "hello_world",
         "os_udp",
-        "pmd_buffer_scatter"
+        "pmd_buffer_scatter",
+        "queue_start_stop"
       ]
     },
     "test_target": {
diff --git a/dts/tests/TestSuite_queue_start_stop.py b/dts/tests/TestSuite_queue_start_stop.py
index 7533f0b395..389030ae8c 100644
--- a/dts/tests/TestSuite_queue_start_stop.py
+++ b/dts/tests/TestSuite_queue_start_stop.py
@@ -17,9 +17,13 @@
 from scapy.packet import Raw  # type: ignore[import-untyped]
 
 from framework.remote_session.testpmd_shell import SimpleForwardingModes, TestPmdShell
-from framework.test_suite import TestSuite
+from framework.test_suite import TestSuite, func_test
+from framework.testbed_model.capability import NicCapability, TopologyType, requires
 
 
+@requires(topology_type=TopologyType.two_links)
+@requires(NicCapability.RUNTIME_RX_QUEUE_SETUP)
+@requires(NicCapability.RUNTIME_TX_QUEUE_SETUP)
 class TestQueueStartStop(TestSuite):
     """DPDK Queue start/stop test suite.
 
@@ -30,14 +34,6 @@ class TestQueueStartStop(TestSuite):
     queue and verify that packets are not received/forwarded.
     """
 
-    def set_up_suite(self) -> None:
-        """Set up the test suite.
-
-        Setup:
-            Verify that at least two ports are open for session.
-        """
-        self.verify(len(self._port_links) > 1, "Not enough ports")
-
     def send_packet_and_verify(self, should_receive: bool = True) -> None:
         """Generate a packet, send to the DUT, and verify it is forwarded back.
 
@@ -54,6 +50,7 @@ def send_packet_and_verify(self, should_receive: bool = True) -> None:
             f"Packet was {'dropped' if should_receive else 'received'}",
         )
 
+    @func_test
     def test_rx_queue_start_stop(self) -> None:
         """Verify packets are not received by port 0 when Rx queue is disabled.
 
@@ -72,6 +69,7 @@ def test_rx_queue_start_stop(self) -> None:
                 "Packets were received on Rx queue when it should've been disabled",
             )
 
+    @func_test
     def test_tx_queue_start_stop(self) -> None:
         """Verify packets are not forwarded by port 1 when Tx queue is disabled.
 
-- 
2.44.0


^ permalink raw reply	[flat|nested] 51+ messages in thread

end of thread, other threads:[~2024-10-08 21:47 UTC | newest]

Thread overview: 51+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-06-17 19:46 [PATCH v2 0/3] dts: queue start/stop suite Dean Marx
2024-06-17 19:46 ` [PATCH v2 1/3] dts: initial queue start/stop suite implementation Dean Marx
2024-06-21 21:27   ` Jeremy Spewock
2024-06-17 19:46 ` [PATCH v2 2/3] dts: added promisc/verbose func to testpmd shell Dean Marx
2024-06-21 21:28   ` Jeremy Spewock
2024-06-17 19:46 ` [PATCH v2 3/3] dts: queue suite conf schema Dean Marx
2024-06-21 21:28   ` Jeremy Spewock
2024-06-21 21:27 ` [PATCH v2 0/3] dts: queue start/stop suite Jeremy Spewock
2024-06-26 13:51 ` [PATCH v3 1/3] dts: initial queue start/stop suite implementation Dean Marx
2024-06-26 13:51   ` [PATCH v3 2/3] dts: add functions to testpmd shell Dean Marx
2024-06-26 19:51     ` Jeremy Spewock
2024-06-26 13:51   ` [PATCH v3 3/3] dts: queue suite conf schema Dean Marx
2024-06-26 19:51     ` Jeremy Spewock
2024-06-26 19:50   ` [PATCH v3 1/3] dts: initial queue start/stop suite implementation Jeremy Spewock
2024-06-28 16:19 ` [PATCH v4 1/3] dts: add functions to testpmd shell Dean Marx
2024-06-28 16:19   ` [PATCH v4 2/3] dts: initial queue start/stop suite implementation Dean Marx
2024-07-01 20:17     ` Jeremy Spewock
2024-06-28 16:19   ` [PATCH v4 3/3] dts: queue suite conf schema Dean Marx
2024-07-01 20:17   ` [PATCH v4 1/3] dts: add functions to testpmd shell Jeremy Spewock
2024-07-03 18:08 ` [PATCH v5 " Dean Marx
2024-07-03 18:08   ` [PATCH v5 2/3] dts: initial queue start/stop suite implementation Dean Marx
2024-07-10 15:36     ` Jeremy Spewock
2024-07-03 18:08   ` [PATCH v5 3/3] dts: queue suite conf schema Dean Marx
2024-07-10 15:37     ` Jeremy Spewock
2024-07-10 15:36   ` [PATCH v5 1/3] dts: add functions to testpmd shell Jeremy Spewock
2024-07-10 16:01 ` [PATCH v6 " Dean Marx
2024-07-10 16:01   ` [PATCH v6 2/3] dts: initial queue start/stop suite implementation Dean Marx
2024-07-11 13:58     ` Jeremy Spewock
2024-07-10 16:01   ` [PATCH v6 3/3] dts: queue suite conf schema Dean Marx
2024-07-11 13:59   ` [PATCH v6 1/3] dts: add functions to testpmd shell Jeremy Spewock
2024-07-17 20:23 ` [PATCH v7 " Dean Marx
2024-07-17 20:23   ` [PATCH v7 2/3] dts: initial queue start/stop suite implementation Dean Marx
2024-07-19 13:34     ` Jeremy Spewock
2024-07-23 17:04       ` Adam Hassick
2024-07-17 20:23   ` [PATCH v7 3/3] dts: queue suite conf schema Dean Marx
2024-07-19 13:34     ` Jeremy Spewock
2024-07-19 13:34   ` [PATCH v7 1/3] dts: add functions to testpmd shell Jeremy Spewock
2024-07-24 18:32 ` [PATCH v8 0/3] dts: refactored queue start/stop suite Dean Marx
2024-07-24 18:32   ` [PATCH v8 1/3] dts: add functions to testpmd shell Dean Marx
2024-07-26 19:19     ` Jeremy Spewock
2024-07-24 18:32   ` [PATCH v8 2/3] dts: initial queue start/stop suite implementation Dean Marx
2024-07-26 19:19     ` Jeremy Spewock
2024-07-24 18:32   ` [PATCH v8 3/3] dts: queue suite conf schema Dean Marx
2024-07-26 19:19     ` Jeremy Spewock
2024-08-07 19:36   ` [PATCH v9 0/2] dts: refactored queue start/stop suite Dean Marx
2024-08-07 19:36     ` [PATCH v9 1/2] dts: add functions to testpmd shell Dean Marx
2024-08-09 15:51       ` Jeremy Spewock
2024-08-07 19:36     ` [PATCH v9 2/2] dts: initial queue start/stop suite implementation Dean Marx
2024-08-09 15:52       ` Jeremy Spewock
2024-10-08 21:48     ` [PATCH v10 0/1] dts: port over queue start/stop suite Dean Marx
2024-10-08 21:48       ` [PATCH v10] " Dean Marx

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).