DPDK patches and discussions
 help / color / mirror / Atom feed
From: Luca Vizzarro <luca.vizzarro@arm.com>
To: dev@dpdk.org
Cc: Luca Vizzarro <luca.vizzarro@arm.com>,
	Paul Szczepanek <paul.szczepanek@arm.com>,
	Patrick Robb <probb@iol.unh.edu>
Subject: [PATCH 6/6] dts: use artifacts in packet capture and softnic
Date: Fri, 25 Jul 2025 16:11:41 +0100	[thread overview]
Message-ID: <20250725151503.87374-7-luca.vizzarro@arm.com> (raw)
In-Reply-To: <20250725151503.87374-1-luca.vizzarro@arm.com>

Use the newly added artifact/file manager in the packet capture and
softnic test suites.

Signed-off-by: Luca Vizzarro <luca.vizzarro@arm.com>
Reviewed-by: Paul Szczepanek <paul.szczepanek@arm.com>
---
 dts/tests/TestSuite_packet_capture.py | 73 ++++++++++----------
 dts/tests/TestSuite_softnic.py        | 95 +++++++++++----------------
 2 files changed, 74 insertions(+), 94 deletions(-)

diff --git a/dts/tests/TestSuite_packet_capture.py b/dts/tests/TestSuite_packet_capture.py
index bad243a571..f8cd1b00cf 100644
--- a/dts/tests/TestSuite_packet_capture.py
+++ b/dts/tests/TestSuite_packet_capture.py
@@ -7,7 +7,7 @@
 """
 
 from dataclasses import dataclass, field
-from pathlib import Path, PurePath
+from pathlib import PurePath
 
 from scapy.contrib.lldp import (
     LLDPDUChassisID,
@@ -29,11 +29,10 @@
 from framework.remote_session.blocking_app import BlockingApp
 from framework.remote_session.dpdk_shell import compute_eal_params
 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.artifact import Artifact
 from framework.testbed_model.capability import requires
 from framework.testbed_model.cpu import LogicalCoreList
-from framework.testbed_model.os_session import FilePermissions
 from framework.testbed_model.topology import TopologyType
 from framework.testbed_model.traffic_generator.capturing_traffic_generator import (
     PacketFilteringConfig,
@@ -65,13 +64,13 @@ class TestPacketCapture(TestSuite):
 
     Attributes:
         packets: List of packets to send for testing dumpcap.
-        rx_pcap_path: The remote path where to create the Rx packets pcap with dumpcap.
-        tx_pcap_path: The remote path where to create the Tx packets pcap with dumpcap.
+        rx_pcap: The artifact associated with the Rx packets pcap created by dumpcap.
+        tx_pcap: The artifact associated with the Tx packets pcap created by dumpcap.
     """
 
     packets: list[Packet]
-    rx_pcap_path: PurePath
-    tx_pcap_path: PurePath
+    rx_pcap: Artifact
+    tx_pcap: Artifact
 
     def _run_dumpcap(self, params: DumpcapParams) -> BlockingApp:
         eal_params = compute_eal_params()
@@ -108,29 +107,32 @@ def set_up_suite(self) -> None:
             / LLDPDUSystemCapabilities()
             / LLDPDUEndOfLLDPDU(),
         ]
-        self.tx_pcap_path = self._ctx.sut_node.tmp_dir.joinpath("tx.pcapng")
-        self.rx_pcap_path = self._ctx.sut_node.tmp_dir.joinpath("rx.pcapng")
 
-    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 set_up_test_case(self):
+        """Test case setup.
+
+        Prepare the artifacts for the Rx and Tx pcap files.
+        """
+        self.tx_pcap = Artifact("sut", "tx.pcapng")
+        self.rx_pcap = Artifact("sut", "rx.pcapng")
 
     def _send_and_dump(
         self, packet_filter: str | None = None, rx_only: bool = False
     ) -> list[Packet]:
+        self.rx_pcap.touch()
         dumpcap_rx = self._run_dumpcap(
             DumpcapParams(
                 interface=self.topology.sut_port_ingress.pci,
-                output_pcap_path=self.rx_pcap_path,
+                output_pcap_path=self.rx_pcap.path,
                 packet_filter=packet_filter,
             )
         )
         if not rx_only:
+            self.tx_pcap.touch()
             dumpcap_tx = self._run_dumpcap(
                 DumpcapParams(
                     interface=self.topology.sut_port_egress.pci,
-                    output_pcap_path=self.tx_pcap_path,
+                    output_pcap_path=self.tx_pcap.path,
                     packet_filter=packet_filter,
                 )
             )
@@ -140,14 +142,8 @@ def _send_and_dump(
         )
 
         dumpcap_rx.close()
-        self._ctx.sut_node.main_session.change_permissions(
-            self.rx_pcap_path, FilePermissions(0o644)
-        )
         if not rx_only:
             dumpcap_tx.close()
-            self._ctx.sut_node.main_session.change_permissions(
-                self.tx_pcap_path, FilePermissions(0o644)
-            )
 
         return received_packets
 
@@ -169,17 +165,19 @@ def test_dumpcap(self) -> None:
             received_packets = self._send_and_dump()
 
             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 packets from dumpcap weren't the same as the expected packets.",
-            )
+            with self.rx_pcap.open() as fd:
+                rx_pcap_packets = list(rdpcap(fd))
+                self.verify(
+                    self.match_all_packets(expected_packets, rx_pcap_packets, verify=False),
+                    "Rx packets from dumpcap weren't the same as the expected packets.",
+                )
 
-            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 packets from dumpcap weren't the same as the packets received by Scapy.",
-            )
+            with self.tx_pcap.open() as fd:
+                tx_pcap_packets = list(rdpcap(fd))
+                self.verify(
+                    self.match_all_packets(tx_pcap_packets, received_packets, verify=False),
+                    "Tx packets from dumpcap weren't the same as the packets received by Scapy.",
+                )
 
     @func_test
     def test_dumpcap_filter(self) -> None:
@@ -202,9 +200,10 @@ def test_dumpcap_filter(self) -> None:
                 if not p.haslayer(TCP)
             ]
 
-            rx_pcap_packets = [raw(p) for p in self._load_pcap_packets(self.rx_pcap_path)]
-            for filtered_packet in filtered_packets:
-                self.verify(
-                    filtered_packet not in rx_pcap_packets,
-                    "Found a packet in the pcap that was meant to be filtered out.",
-                )
+            with self.rx_pcap.open() as fd:
+                rx_pcap_packets = [raw(p) for p in rdpcap(fd)]
+                for filtered_packet in filtered_packets:
+                    self.verify(
+                        filtered_packet not in rx_pcap_packets,
+                        "Found a packet in the pcap that was meant to be filtered out.",
+                    )
diff --git a/dts/tests/TestSuite_softnic.py b/dts/tests/TestSuite_softnic.py
index 27754c08e7..edeca55f32 100644
--- a/dts/tests/TestSuite_softnic.py
+++ b/dts/tests/TestSuite_softnic.py
@@ -6,11 +6,10 @@
 Create a softnic virtual device and verify it successfully forwards packets.
 """
 
-from pathlib import Path, PurePath
-
 from framework.params.testpmd import EthPeer
 from framework.remote_session.testpmd_shell import NicCapability, TestPmdShell
 from framework.test_suite import TestSuite, func_test
+from framework.testbed_model.artifact import Artifact
 from framework.testbed_model.capability import requires
 from framework.testbed_model.topology import TopologyType
 from framework.testbed_model.virtual_device import VirtualDevice
@@ -35,62 +34,44 @@ def set_up_suite(self) -> None:
         """
         self.sut_node = self._ctx.sut_node  # FIXME: accessing the context should be forbidden
         self.packets = generate_random_packets(self.NUMBER_OF_PACKETS_TO_SEND, self.PAYLOAD_SIZE)
-        self.cli_file = self.prepare_softnic_files()
-
-    def prepare_softnic_files(self) -> PurePath:
-        """Creates the config files that are required for the creation of the softnic.
-
-        The config files are created at runtime to accommodate paths and device addresses.
-        """
-        # paths of files needed by softnic
-        cli_file = Path("rx_tx.cli")
-        spec_file = Path("rx_tx.spec")
-        rx_tx_1_file = Path("rx_tx_1.io")
-        rx_tx_2_file = Path("rx_tx_2.io")
-        path_sut = self._ctx.sut_node.tmp_dir
-        cli_file_sut = self.sut_node.main_session.join_remote_path(path_sut, cli_file)
-        spec_file_sut = self.sut_node.main_session.join_remote_path(path_sut, spec_file)
-        rx_tx_1_file_sut = self.sut_node.main_session.join_remote_path(path_sut, rx_tx_1_file)
-        rx_tx_2_file_sut = self.sut_node.main_session.join_remote_path(path_sut, rx_tx_2_file)
-        firmware_c_file_sut = self.sut_node.main_session.join_remote_path(path_sut, "firmware.c")
-        firmware_so_file_sut = self.sut_node.main_session.join_remote_path(path_sut, "firmware.so")
-
-        # write correct remote paths to local files
-        with open(cli_file, "w+") as fh:
-            fh.write(f"pipeline codegen {spec_file_sut} {firmware_c_file_sut}\n")
-            fh.write(f"pipeline libbuild {firmware_c_file_sut} {firmware_so_file_sut}\n")
-            fh.write(f"pipeline RX build lib {firmware_so_file_sut} io {rx_tx_1_file_sut} numa 0\n")
-            fh.write(f"pipeline TX build lib {firmware_so_file_sut} io {rx_tx_2_file_sut} numa 0\n")
-            fh.write("thread 2 pipeline RX enable\n")
-            fh.write("thread 2 pipeline TX enable\n")
-        with open(spec_file, "w+") as fh:
-            fh.write("struct metadata_t {{\n")
-            fh.write("	bit<32> port\n")
-            fh.write("}}\n")
-            fh.write("metadata instanceof metadata_t\n")
-            fh.write("apply {{\n")
-            fh.write("	rx m.port\n")
-            fh.write("	tx m.port\n")
-            fh.write("}}\n")
-        with open(rx_tx_1_file, "w+") as fh:
-            fh.write(f"port in 0 ethdev {self.sut_node.config.ports[0].pci} rxq 0 bsz 32\n")
-            fh.write("port out 0 ring RXQ0 bsz 32\n")
-        with open(rx_tx_2_file, "w+") as fh:
-            fh.write("port in 0 ring TXQ0 bsz 32\n")
-            fh.write(f"port out 1 ethdev {self.sut_node.config.ports[1].pci} txq 0 bsz 32\n")
-
-        # copy files over to SUT
-        self.sut_node.main_session.copy_to(cli_file, cli_file_sut)
-        self.sut_node.main_session.copy_to(spec_file, spec_file_sut)
-        self.sut_node.main_session.copy_to(rx_tx_1_file, rx_tx_1_file_sut)
-        self.sut_node.main_session.copy_to(rx_tx_2_file, rx_tx_2_file_sut)
-        # and cleanup local files
-        cli_file.unlink()
-        spec_file.unlink()
-        rx_tx_1_file.unlink()
-        rx_tx_2_file.unlink()
 
-        return cli_file_sut
+        self.cli_file = Artifact("sut", "rx_tx.cli")
+        self.spec_file = Artifact("sut", "rx_tx.spec")
+        self.rx_tx_1_file = Artifact("sut", "rx_tx_1.io")
+        self.rx_tx_2_file = Artifact("sut", "rx_tx_2.io")
+        self.firmware_c_file = Artifact("sut", "firmware.c")
+        self.firmware_so_file = Artifact("sut", "firmware.so")
+
+        with self.cli_file.open("w+") as fh:
+            fh.write(
+                f"pipeline codegen {self.spec_file} {self.firmware_c_file}\n"
+                f"pipeline libbuild {self.firmware_c_file} {self.firmware_so_file}\n"
+                f"pipeline RX build lib {self.firmware_so_file} io {self.rx_tx_1_file} numa 0\n"
+                f"pipeline TX build lib {self.firmware_so_file} io {self.rx_tx_2_file} numa 0\n"
+                "thread 2 pipeline RX enable\n"
+                "thread 2 pipeline TX enable\n"
+            )
+        with self.spec_file.open("w+") as fh:
+            fh.write(
+                "struct metadata_t {\n"
+                "	bit<32> port\n"
+                "}\n"
+                "metadata instanceof metadata_t\n"
+                "apply {\n"
+                "	rx m.port\n"
+                "	tx m.port\n"
+                "}\n"
+            )
+        with self.rx_tx_1_file.open("w+") as fh:
+            fh.write(
+                f"port in 0 ethdev {self.sut_node.config.ports[0].pci} rxq 0 bsz 32\n"
+                "port out 0 ring RXQ0 bsz 32\n"
+            )
+        with self.rx_tx_2_file.open("w+") as fh:
+            fh.write(
+                "port in 0 ring TXQ0 bsz 32\n"
+                f"port out 1 ethdev {self.sut_node.config.ports[1].pci} txq 0 bsz 32\n"
+            )
 
     @func_test
     def softnic(self) -> None:
-- 
2.43.0


      parent reply	other threads:[~2025-07-25 15:16 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-07-25 15:11 [PATCH 0/6] dts: add file management Luca Vizzarro
2025-07-25 15:11 ` [PATCH 1/6] dts: merge RemoteSession class Luca Vizzarro
2025-07-25 15:11 ` [PATCH 2/6] dts: add node retriever by identifier Luca Vizzarro
2025-07-25 15:11 ` [PATCH 3/6] dts: add current test suite and cases to context Luca Vizzarro
2025-07-25 15:11 ` [PATCH 4/6] dts: add artifact module Luca Vizzarro
2025-07-25 15:11 ` [PATCH 5/6] dts: make log files into artifacts Luca Vizzarro
2025-07-25 15:11 ` Luca Vizzarro [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250725151503.87374-7-luca.vizzarro@arm.com \
    --to=luca.vizzarro@arm.com \
    --cc=dev@dpdk.org \
    --cc=paul.szczepanek@arm.com \
    --cc=probb@iol.unh.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).