DPDK patches and discussions
 help / color / mirror / Atom feed
* [PATCH 0/2] dts: add packet capture test suite
@ 2025-03-31 15:57 Thomas Wilks
  2025-03-31 15:57 ` [PATCH 1/2] " Thomas Wilks
  2025-03-31 15:58 ` [PATCH 2/2] dts: import lldp package in scapy Thomas Wilks
  0 siblings, 2 replies; 3+ messages in thread
From: Thomas Wilks @ 2025-03-31 15:57 UTC (permalink / raw)
  To: dev; +Cc: Paul Szczepanek, Luca Vizzarro, Patrick Robb, Thomas Wilks

Hi,

Sending this new test suite that tests the packet capture framework.

Best regards,
Thomas

Depends-on: series-34865 ("dts: shell improvements")

Thomas Wilks (2):
  dts: add packet capture test suite
  dts: import lldp package in scapy

 .../dts/tests.TestSuite_packet_capture.rst    |   8 +
 .../testbed_model/traffic_generator/scapy.py  |   1 +
 dts/tests/TestSuite_packet_capture.py         | 357 ++++++++++++++++++
 3 files changed, 366 insertions(+)
 create mode 100644 doc/api/dts/tests.TestSuite_packet_capture.rst
 create mode 100644 dts/tests/TestSuite_packet_capture.py

-- 
2.43.0


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

* [PATCH 1/2] dts: add packet capture test suite
  2025-03-31 15:57 [PATCH 0/2] dts: add packet capture test suite Thomas Wilks
@ 2025-03-31 15:57 ` Thomas Wilks
  2025-03-31 15:58 ` [PATCH 2/2] dts: import lldp package in scapy Thomas Wilks
  1 sibling, 0 replies; 3+ messages in thread
From: Thomas Wilks @ 2025-03-31 15:57 UTC (permalink / raw)
  To: dev; +Cc: Paul Szczepanek, Luca Vizzarro, Patrick Robb, Thomas Wilks

Add a test suite that tests the packet capture framework
through the use of dpdk-pdump.

Signed-off-by: Thomas Wilks <thomas.wilks@arm.com>
Reviewed-by: Luca Vizzarro <luca.vizzarro@arm.com>
---
 .../dts/tests.TestSuite_packet_capture.rst    |   8 +
 dts/tests/TestSuite_packet_capture.py         | 358 ++++++++++++++++++
 2 files changed, 366 insertions(+)
 create mode 100644 doc/api/dts/tests.TestSuite_packet_capture.rst
 create mode 100644 dts/tests/TestSuite_packet_capture.py

diff --git a/doc/api/dts/tests.TestSuite_packet_capture.rst b/doc/api/dts/tests.TestSuite_packet_capture.rst
new file mode 100644
index 0000000000..3d760d3ae4
--- /dev/null
+++ b/doc/api/dts/tests.TestSuite_packet_capture.rst
@@ -0,0 +1,8 @@
+.. SPDX-License-Identifier: BSD-3-Clause
+
+packet_capture Test Suite
+=========================
+
+.. automodule:: tests.TestSuite_packet_capture
+   :members:
+   :show-inheritance:
diff --git a/dts/tests/TestSuite_packet_capture.py b/dts/tests/TestSuite_packet_capture.py
new file mode 100644
index 0000000000..bdc3d008a3
--- /dev/null
+++ b/dts/tests/TestSuite_packet_capture.py
@@ -0,0 +1,358 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2025 Arm Limited
+
+"""Packet capture TestSuite.
+
+Tests pdump by sending packets, changing the arguments of pdump
+and verifying the received packets.
+"""
+
+from dataclasses import asdict, dataclass
+from pathlib import Path, PurePath
+from random import randint
+from typing import Union
+
+from scapy.contrib.lldp import (
+    LLDPDUChassisID,
+    LLDPDUEndOfLLDPDU,
+    LLDPDUPortID,
+    LLDPDUSystemCapabilities,
+    LLDPDUSystemDescription,
+    LLDPDUSystemName,
+    LLDPDUTimeToLive,
+)
+from scapy.layers.inet import IP, TCP, UDP
+from scapy.layers.inet6 import IPv6
+from scapy.layers.l2 import Dot1Q, Ether
+from scapy.layers.sctp import SCTP
+from scapy.packet import Packet, Raw
+from scapy.utils import rdpcap
+from typing_extensions import Literal
+
+from framework.params.eal import EalParams
+from framework.params.testpmd import PortTopology
+from framework.remote_session.dpdk_app import BlockingDPDKApp
+from framework.remote_session.testpmd_shell import TestPmdShell
+from framework.settings import SETTINGS
+from framework.test_suite import TestSuite, func_test
+from framework.testbed_model.traffic_generator.capturing_traffic_generator import (
+    PacketFilteringConfig,
+)
+
+
+@dataclass(order=True, kw_only=True)
+class PdumpParameters:
+    """Parameters for --pdump.
+
+    Attributes:
+        device_id: The PCIE address of the device to capture packets.
+        port: The port id of the device to capture packets.
+        queue: The ID of the RX and TX queue.
+        tx_dev: The path or iface that the TX packets captured on TX will be outputted at.
+        rx_dev: The path or iface that the RX packets captured on RX will be outputted at.
+        ring_size: The size of the ring.
+        mbuf_size: The size of the mbuf data.
+        total_num_mbufs: Total number of the mbufs in the memory pool.
+    """
+
+    device_id: str | None = None
+    port: int | None = None
+    queue: Union[int, Literal["*"]] = "*"
+    tx_dev: PurePath | str | None = None
+    rx_dev: PurePath | str | None = None
+    ring_size: int | None = None
+    mbuf_size: int | None = None
+    total_num_mbufs: int | None = None
+
+    def __str__(self) -> str:
+        """Parameters as string for --pdump.
+
+        Returns:
+            String of the pdump commands
+        """
+
+        def pair_to_str(field, value):
+            if field != "device_id":
+                field = field.replace("_", "-")
+            return f"{field}={value}"
+
+        arg = ",".join(
+            [
+                pair_to_str(field, value)
+                for field, value in asdict(self).items()
+                if value is not None
+            ]
+        )
+
+        return arg
+
+
+class TestPacketCapture(TestSuite):
+    """Packet Capture TestSuite.
+
+    Attributes:
+        packets: List of packets to send for testing pdump.
+        rx_pcap_path: The remote path where to create the RX packets pcap with pdump.
+        tx_pcap_path: The remote path where to create the TX packets pcap with pdump.
+        pdump_params: The list of pdump parameters.
+    """
+
+    packets: list[Packet]
+    rx_pcap_path: PurePath
+    tx_pcap_path: PurePath
+    pdump_params: list[PdumpParameters]
+
+    def set_up_suite(self) -> None:
+        """Test suite setup.
+
+        Prepare the packets, file paths and queue range to be used in the test suite.
+        """
+        self.packets = [
+            Ether() / IP() / Raw(b"\0" * 60),
+            Ether() / IP() / TCP() / Raw(b"\0" * 60),
+            Ether() / IP() / UDP() / Raw(b"\0" * 60),
+            Ether() / IP() / SCTP() / Raw(b"\0" * 40),
+            Ether() / IPv6() / TCP() / Raw(b"\0" * 60),
+            Ether() / IPv6() / UDP() / Raw(b"\0" * 60),
+            Ether() / IP() / IPv6() / SCTP() / Raw(b"\0" * 40),
+            Ether() / Dot1Q() / IP() / UDP() / Raw(b"\0" * 40),
+            Ether(dst="FF:FF:FF:FF:FF:FF", type=0x88F7) / Raw(b"\0" * 60),
+            Ether(type=0x88CC)
+            / LLDPDUChassisID(subtype=4, id=self.topology.tg_port_egress.mac_address)
+            / LLDPDUPortID(subtype=5, id="Test Id")
+            / LLDPDUTimeToLive(ttl=180)
+            / LLDPDUSystemName(system_name="DTS Test sys")
+            / LLDPDUSystemDescription(description="DTS Test Packet")
+            / LLDPDUSystemCapabilities()
+            / LLDPDUEndOfLLDPDU(),
+        ]
+        self.tx_pcap_path = self._ctx.sut_node.tmp_dir.joinpath("tx.pcap")
+        self.rx_pcap_path = self._ctx.sut_node.tmp_dir.joinpath("rx.pcap")
+
+    def set_up_test_case(self) -> None:
+        """Set up test case.
+
+        Prepare default pdump parameters.
+        """
+        self.pdump_params = [
+            PdumpParameters(
+                device_id=self.topology.sut_port_ingress.pci,
+                rx_dev=self.rx_pcap_path,
+            ),
+            PdumpParameters(
+                device_id=self.topology.sut_port_egress.pci,
+                tx_dev=self.tx_pcap_path,
+            ),
+        ]
+
+    def _load_pcap_packets(self, remote_pcap_path: PurePath) -> list[Packet]:
+        local_pcap_path = Path(SETTINGS.output_dir).joinpath(remote_pcap_path.name)
+        self._ctx.sut_node.main_session.copy_from(remote_pcap_path, local_pcap_path)
+        return list(rdpcap(str(local_pcap_path)))
+
+    def _verify_packets(self, received_packets: list[Packet]) -> None:
+        expected_packets = self.get_expected_packets(self.packets, sent_from_tg=True)
+        rx_pcap_packets = self._load_pcap_packets(self.rx_pcap_path)
+        self.verify(
+            self.match_all_packets(expected_packets, rx_pcap_packets, verify=False),
+            "RX packet from pdump wasn't the same as the packet from Scapy.",
+        )
+
+        tx_pcap_packets = self._load_pcap_packets(self.tx_pcap_path)
+        self.verify(
+            self.match_all_packets(tx_pcap_packets, received_packets, verify=False),
+            "TX packet from pdump wasn't the same as the expected packet.",
+        )
+
+    def _start_pdump(
+        self,
+        pdump_params: list[PdumpParameters],
+        eal_params: EalParams | None = None,
+    ) -> BlockingDPDKApp:
+        if eal_params is None:
+            eal_params = EalParams()
+
+        eal_params.append_str(" ".join([f'--pdump "{param}"' for param in pdump_params]))
+
+        pdump = BlockingDPDKApp(PurePath("app/dpdk-pdump"), app_params=eal_params)
+        pdump.wait_until_ready(
+            "queue 65535" if pdump_params[0].queue == "*" else f"queue {pdump_params[0].queue}"
+        )
+        return pdump
+
+    def _start_pdump_and_verify_packets(self) -> None:
+        pdump = self._start_pdump(self.pdump_params)
+        received_packets = self.send_packets_and_capture(
+            self.packets, PacketFilteringConfig(no_lldp=False)
+        )
+        pdump.close()
+        self._verify_packets(received_packets)
+
+    @func_test
+    def test_pdump_device_id(self) -> None:
+        """Test pdump device id.
+
+        Steps:
+            Start up TestPMD Shell.
+            Boot up Pdump with the default values.
+            Send packets.
+
+        Verify:
+            Verify the expected packets are the same as the RX packets.
+            Verify the TX packets are the same as the packets received from Scapy.
+        """
+        with TestPmdShell() as testpmd:
+            testpmd.start()
+            self._start_pdump_and_verify_packets()
+
+    @func_test
+    def test_pdump_port(self) -> None:
+        """Test pdump port.
+
+        Steps:
+            Start up TestPMD Shell.
+            Boot up Pdump specifying port numbers instead of device ids.
+            Send packets.
+
+        Verify:
+            Verify the expected packets are the same as the RX packets.
+            Verify the TX packets are the same as the packets received from Scapy.
+        """
+        with TestPmdShell() as testpmd:
+            testpmd.start()
+
+            self.pdump_params[0].port = 0
+            self.pdump_params[0].device_id = None
+            self.pdump_params[1].port = 1
+            self.pdump_params[1].device_id = None
+
+            self._start_pdump_and_verify_packets()
+
+    @func_test
+    def test_pdump_queue(self) -> None:
+        """Test pdump queue.
+
+        Steps:
+            Start up TestPMD Shell.
+            Boot up Pdump specifying queue 0 instead of the default queue value.
+            Send packets.
+
+        Verify:
+            Verify the expected packets are the same as the RX packets.
+            Verify the TX packets are the same as the packets received from Scapy.
+        """
+        with TestPmdShell() as testpmd:
+            testpmd.start()
+
+            self.pdump_params[0].queue = 0
+            self.pdump_params[1].queue = 0
+
+            self._start_pdump_and_verify_packets()
+
+    @func_test
+    def test_pdump_dev_iface(self) -> None:
+        """Test pdump dev iface.
+
+        Dump RX packets to the link that scapy is capturing packets on.
+
+        Steps:
+            Switch the SUT egress port driver to the kernel driver and bring up the device.
+            Start up TestPMD Shell with loop port topology.
+            Boot up Pdump with the SUT port egress logical name instead of the pcap file.
+            Send packet and capture.
+
+        Verify:
+            Verify the expected packets are the same as the packets received by Scapy.
+        """
+        try:
+            self._ctx.dpdk.bind_ports_to_driver(self.topology.sut_ports[1:], for_dpdk=False)
+            self._ctx.sut_node.main_session.bring_up_link(self.topology.sut_ports[1:])
+
+            with TestPmdShell(
+                allowed_ports=self.topology.sut_ports[:1], port_topology=PortTopology.loop
+            ) as testpmd:
+                testpmd.start()
+
+                pdump = self._start_pdump(
+                    eal_params=EalParams(allowed_ports=self.topology.sut_ports[:1]),
+                    pdump_params=[
+                        PdumpParameters(
+                            device_id=self.topology.sut_port_ingress.pci,
+                            rx_dev=self.topology.sut_port_egress.logical_name,
+                        ),
+                    ],
+                )
+                received_packets = self.send_packets_and_capture(
+                    self.packets, PacketFilteringConfig(no_lldp=False)
+                )
+                pdump.close()
+
+                self.match_all_packets(
+                    self.get_expected_packets(self.packets, sent_from_tg=True), received_packets
+                )
+        finally:
+            self._ctx.dpdk.bind_ports_to_driver(self.topology.sut_ports[1:], for_dpdk=True)
+
+    @func_test
+    def test_pdump_ring_size(self) -> None:
+        """Test pdump mbuf size.
+
+        Steps:
+            Start up TestPMD Shell.
+            Boot up Pdump with a custom ring size of 1024.
+            Send packets.
+
+        Verify:
+            Verify the expected packets are the same as the RX packets.
+            Verify the TX packets are the same as the packets received from Scapy.
+        """
+        with TestPmdShell() as testpmd:
+            testpmd.start()
+
+            self.pdump_params[0].ring_size = 1024
+            self.pdump_params[1].ring_size = 1024
+
+            self._start_pdump_and_verify_packets()
+
+    @func_test
+    def test_pdump_mbuf_size(self) -> None:
+        """Test pdump total num mbufs.
+
+        Steps:
+            Start up TestPMD Shell.
+            Boot up Pdump with a custom mbuf size of 2048.
+            Send packets.
+
+        Verify:
+            Verify the expected packets are the same as the RX packets.
+            Verify the TX packets are the same as the packets received from Scapy.
+        """
+        with TestPmdShell() as testpmd:
+            testpmd.start()
+
+            self.pdump_params[0].mbuf_size = 2048
+            self.pdump_params[1].mbuf_size = 2048
+
+            self._start_pdump_and_verify_packets()
+
+    @func_test
+    def test_pdump_total_num_mbufs(self) -> None:
+        """Test pdump total num mbufs.
+
+        Steps:
+            Start up TestPMD Shell.
+            Boot up Pdump with a custom total num mbufs value chosen at random from 1025 to 65535.
+            Send packets.
+
+        Verify:
+            Verify the expected packets are the same as the RX packets.
+            Verify the TX packets are the same as the packets received from Scapy.
+        """
+        with TestPmdShell() as testpmd:
+            testpmd.start()
+
+            total_num_mbufs = randint(1025, 65535)
+            self.pdump_params[0].total_num_mbufs = total_num_mbufs
+            self.pdump_params[1].total_num_mbufs = total_num_mbufs
+
+            self._start_pdump_and_verify_packets()
-- 
2.43.0


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

* [PATCH 2/2] dts: import lldp package in scapy
  2025-03-31 15:57 [PATCH 0/2] dts: add packet capture test suite Thomas Wilks
  2025-03-31 15:57 ` [PATCH 1/2] " Thomas Wilks
@ 2025-03-31 15:58 ` Thomas Wilks
  1 sibling, 0 replies; 3+ messages in thread
From: Thomas Wilks @ 2025-03-31 15:58 UTC (permalink / raw)
  To: dev; +Cc: Paul Szczepanek, Luca Vizzarro, Patrick Robb, Thomas Wilks

Add import for lldp scapy package to enable lldp packet
creation and handling.

Signed-off-by: Thomas Wilks <thomas.wilks@arm.com>
Reviewed-by: Luca Vizzarro <luca.vizzarro@arm.com>
---
 dts/framework/testbed_model/traffic_generator/scapy.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/dts/framework/testbed_model/traffic_generator/scapy.py b/dts/framework/testbed_model/traffic_generator/scapy.py
index 78a6ded74c..c7e8fc42e9 100644
--- a/dts/framework/testbed_model/traffic_generator/scapy.py
+++ b/dts/framework/testbed_model/traffic_generator/scapy.py
@@ -95,6 +95,7 @@ def setup(self, ports: Iterable[Port]):
         self._tg_node.main_session.bring_up_link(ports)
         self._shell.start_application()
         self._shell.send_command("from scapy.all import *")
+        self._shell.send_command("from scapy.contrib.lldp import *")
 
     def close(self):
         """Close traffic generator."""
-- 
2.43.0


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

end of thread, other threads:[~2025-03-31 15:58 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-03-31 15:57 [PATCH 0/2] dts: add packet capture test suite Thomas Wilks
2025-03-31 15:57 ` [PATCH 1/2] " Thomas Wilks
2025-03-31 15:58 ` [PATCH 2/2] dts: import lldp package in scapy Thomas Wilks

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