* [PATCH v2 1/6] dts: add RSS functions to testpmd
2025-02-25 15:33 ` [PATCH v2 0/6] Added RSS functions and tests Thomas Wilks
@ 2025-02-25 15:33 ` Thomas Wilks
2025-02-25 15:33 ` [PATCH v2 2/6] dts: add utils for PMD RSS testsuites Thomas Wilks
` (4 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Thomas Wilks @ 2025-02-25 15:33 UTC (permalink / raw)
To: dev
Cc: Paul Szczepanek, Luca Vizzarro, Patrick Robb, Alex Chapman, Thomas Wilks
From: Alex Chapman <alex.chapman@arm.com>
This patch adds the required functionality for the RSS key_update,
RETA, and hash test suites. This includes:
The setting of custom RETA values for routing packets to specific
queues.
The setting of the RSS mode on all ports, to specify how to hash
the packets.
The updating of the RSS hash key used during the hashing process.
Alongside this, there is the addition of a __str__ method to the
RSSOffloadTypesFlags class, so that when flag names are cast to
a string they will use '-' as separators, instead of '_'.
This allows them to be directly used within testpmd RSS commands
without any further changes.
Signed-off-by: Alex Chapman <alex.chapman@arm.com>
Signed-off-by: Thomas Wilks <thomas.wilks@arm.com>
Reviewed-by: Paul Szczepanek <paul.szczepanek@arm.com>
---
dts/framework/remote_session/testpmd_shell.py | 137 ++++++++++++++++--
1 file changed, 123 insertions(+), 14 deletions(-)
diff --git a/dts/framework/remote_session/testpmd_shell.py b/dts/framework/remote_session/testpmd_shell.py
index 1f291fcb68..0e1f29f2f3 100644
--- a/dts/framework/remote_session/testpmd_shell.py
+++ b/dts/framework/remote_session/testpmd_shell.py
@@ -350,6 +350,12 @@ def make_parser(cls) -> ParserFn:
RSSOffloadTypesFlag.from_list_string,
)
+ def __str__(self):
+ """Replaces underscores with hyphens to produce valid testpmd value."""
+ if self.name is None:
+ return ""
+ return self.name.replace("_", "-")
+
class DeviceCapabilitiesFlag(Flag):
"""Flag representing the device capabilities."""
@@ -655,7 +661,8 @@ class TestPmdPort(TextParser):
)
#: Maximum number of VMDq pools
max_vmdq_pools_num: int | None = field(
- default=None, metadata=TextParser.find_int(r"Maximum number of VMDq pools: (\d+)")
+ default=None,
+ metadata=TextParser.find_int(r"Maximum number of VMDq pools: (\d+)"),
)
#:
@@ -1482,7 +1489,9 @@ def _wrapper(self: "TestPmdShell", *args: P.args, **kwargs: P.kwargs):
return _wrapper
-def add_remove_mtu(mtu: int = 1500) -> Callable[[TestPmdShellMethod], TestPmdShellMethod]:
+def add_remove_mtu(
+ mtu: int = 1500,
+) -> Callable[[TestPmdShellMethod], TestPmdShellMethod]:
"""Configure MTU to `mtu` on all ports, run the decorated function, then revert.
Args:
@@ -1723,6 +1732,82 @@ def set_ports_queues(self, number_of: int) -> None:
self.send_command(f"port config all rxq {number_of}")
self.send_command(f"port config all txq {number_of}")
+ def port_config_rss_reta(
+ self, port_id: int, hash_index: int, queue_id: int, verify: bool = True
+ ) -> None:
+ """Configure a port's RSS redirection table.
+
+ Args:
+ port_id: The port where the redirection table will be configured.
+ hash_index: The index into the redirection table associated with the destination queue.
+ queue_id: The destination queue of the packet.
+ verify: If :data:`True`, verifies if a port's redirection table
+ was correctly configured.
+
+ Raises:
+ InteractiveCommandExecutionError: If `verify` is :data:`True`
+ Testpmd failed to config RSS reta.
+ """
+ out = self.send_command(f"port config {port_id} rss reta ({hash_index},{queue_id})")
+ if verify:
+ if f"The reta size of port {port_id} is" not in out:
+ self._logger.debug(f"Failed to config RSS reta: \n{out}")
+ raise InteractiveCommandExecutionError("Testpmd failed to config RSS reta.")
+
+ def port_config_all_rss_offload_type(
+ self, flag: RSSOffloadTypesFlag, verify: bool = True
+ ) -> None:
+ """Set the RSS mode on all ports.
+
+ Args:
+ flag: The RSS iptype all ports will be configured to.
+ verify: If :data:`True`, it verifies if all ports RSS offload type
+ was correctly configured.
+
+ Raises:
+ InteractiveCommandExecutionError: If `verify` is :data:`True`
+ Testpmd failed to config the RSS mode on all ports.
+ """
+ out = self.send_command(f"port config all rss {flag.name}")
+ if verify:
+ if "error" in out:
+ self._logger.debug(f"Failed to config the RSS mode on all ports: \n{out}")
+ raise InteractiveCommandExecutionError(
+ f"Testpmd failed to change RSS mode to {flag.name}"
+ )
+
+ def port_config_rss_hash_key(
+ self,
+ port_id: int,
+ offload_type: RSSOffloadTypesFlag,
+ hex_str: str,
+ verify: bool = True,
+ ) -> str:
+ """Sets the RSS hash key for the specified port.
+
+ Args:
+ port_id: The port that will have the hash key applied to.
+ offload_type: The offload type the hash key will be applied to.
+ hex_str: The hash key to set.
+ verify: If :data:`True`, verify that RSS has the key.
+
+ Raises:
+ InteractiveCommandExecutionError: If `verify` is :data:`True`
+ Testpmd failed to set the RSS hash key.
+ """
+ output = self.send_command(
+ f"port config {port_id} rss-hash-key {offload_type} {hex_str}",
+ skip_first_line=True,
+ )
+
+ if verify:
+ if output.strip():
+ self._logger.debug(f"Failed to set rss hash key: \n{output}")
+ raise InteractiveCommandExecutionError(
+ f"Testpmd failed to set {hex_str} on {port_id} with a flag of {offload_type}."
+ )
+ return output
+
def show_port_info_all(self) -> list[TestPmdPort]:
"""Returns the information of all the ports.
@@ -1939,22 +2024,28 @@ def csum_set_hw(
{port_id}:\n{csum_output}"""
)
- def flow_create(self, flow_rule: FlowRule, port_id: int) -> int:
+ def flow_create(self, flow_rule: FlowRule, port_id: int, verify: bool = True) -> int:
"""Creates a flow rule in the testpmd session.
- This command is implicitly verified as needed to return the created flow rule id.
-
Args:
flow_rule: :class:`FlowRule` object used for creating testpmd flow rule.
port_id: Integer representing the port to use.
+ verify: If :data:`True`, the output of the command is scanned
+ to ensure the flow rule was created successfully.
Raises:
InteractiveCommandExecutionError: If flow rule is invalid.
Returns:
- Id of created flow rule.
+ Id of created flow rule as an integer.
"""
flow_output = self.send_command(f"flow create {port_id} {flow_rule}")
+ if verify:
+ if "created" not in flow_output:
+ self._logger.debug(f"Failed to create flow rule:\n{flow_output}")
+ raise InteractiveCommandExecutionError(
+ f"Failed to create flow rule:\n{flow_output}"
+ )
match = re.search(r"#(\d+)", flow_output)
if match is not None:
match_str = match.group(1)
@@ -1968,10 +2059,10 @@ def flow_delete(self, flow_id: int, port_id: int, verify: bool = True) -> None:
"""Deletes the specified flow rule from the testpmd session.
Args:
- flow_id: ID of the flow to remove.
+ flow_id: :class:`FlowRule` id used for deleting testpmd flow rule.
port_id: Integer representing the port to use.
verify: If :data:`True`, the output of the command is scanned
- to ensure the flow rule was deleted successfully.
+ to ensure the flow rule was deleted successfully.
Raises:
InteractiveCommandExecutionError: If flow rule is invalid.
@@ -2639,7 +2730,10 @@ class NicCapability(NoAliasEnum):
None,
)
#: Device supports Large Receive Offload.
- RX_OFFLOAD_TCP_LRO: TestPmdShellNicCapability = (TestPmdShell.get_capabilities_rx_offload, None)
+ RX_OFFLOAD_TCP_LRO: TestPmdShellNicCapability = (
+ TestPmdShell.get_capabilities_rx_offload,
+ None,
+ )
#: Device supports QinQ (queue in queue) offload.
RX_OFFLOAD_QINQ_STRIP: TestPmdShellNicCapability = (
TestPmdShell.get_capabilities_rx_offload,
@@ -2666,7 +2760,10 @@ class NicCapability(NoAliasEnum):
None,
)
#: Device supports receiving segmented mbufs.
- RX_OFFLOAD_SCATTER: TestPmdShellNicCapability = (TestPmdShell.get_capabilities_rx_offload, None)
+ RX_OFFLOAD_SCATTER: TestPmdShellNicCapability = (
+ TestPmdShell.get_capabilities_rx_offload,
+ None,
+ )
#: Device supports Timestamp.
RX_OFFLOAD_TIMESTAMP: TestPmdShellNicCapability = (
TestPmdShell.get_capabilities_rx_offload,
@@ -2708,7 +2805,10 @@ class NicCapability(NoAliasEnum):
None,
)
#: Device supports all VLAN capabilities.
- RX_OFFLOAD_VLAN: TestPmdShellNicCapability = (TestPmdShell.get_capabilities_rx_offload, None)
+ RX_OFFLOAD_VLAN: TestPmdShellNicCapability = (
+ TestPmdShell.get_capabilities_rx_offload,
+ None,
+ )
#: Device supports Rx queue setup after device started.
RUNTIME_RX_QUEUE_SETUP: TestPmdShellNicCapability = (
TestPmdShell.get_capabilities_show_port_info,
@@ -2720,9 +2820,15 @@ class NicCapability(NoAliasEnum):
None,
)
#: Device supports shared Rx queue among ports within Rx domain and switch domain.
- RXQ_SHARE: TestPmdShellNicCapability = (TestPmdShell.get_capabilities_show_port_info, None)
+ RXQ_SHARE: TestPmdShellNicCapability = (
+ TestPmdShell.get_capabilities_show_port_info,
+ None,
+ )
#: Device supports keeping flow rules across restart.
- FLOW_RULE_KEEP: TestPmdShellNicCapability = (TestPmdShell.get_capabilities_show_port_info, None)
+ FLOW_RULE_KEEP: TestPmdShellNicCapability = (
+ TestPmdShell.get_capabilities_show_port_info,
+ None,
+ )
#: Device supports keeping shared flow objects across restart.
FLOW_SHARED_OBJECT_KEEP: TestPmdShellNicCapability = (
TestPmdShell.get_capabilities_show_port_info,
@@ -2734,7 +2840,10 @@ class NicCapability(NoAliasEnum):
None,
)
#: Device supports flow ctrl.
- FLOW_CTRL: TestPmdShellNicCapability = (TestPmdShell.get_capabilities_flow_ctrl, None)
+ FLOW_CTRL: TestPmdShellNicCapability = (
+ TestPmdShell.get_capabilities_flow_ctrl,
+ None,
+ )
def __call__(
self,
--
2.43.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 2/6] dts: add utils for PMD RSS testsuites
2025-02-25 15:33 ` [PATCH v2 0/6] Added RSS functions and tests Thomas Wilks
2025-02-25 15:33 ` [PATCH v2 1/6] dts: add RSS functions to testpmd Thomas Wilks
@ 2025-02-25 15:33 ` Thomas Wilks
2025-02-25 15:33 ` [PATCH v2 3/6] dts: add PMD RSS hash testsuite Thomas Wilks
` (3 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Thomas Wilks @ 2025-02-25 15:33 UTC (permalink / raw)
To: dev
Cc: Paul Szczepanek, Luca Vizzarro, Patrick Robb, Alex Chapman, Thomas Wilks
From: Alex Chapman <alex.chapman@arm.com>
To reduce the amount of maintenance and code duplication,
common functionality between the rss_key_update, pmd_rss_reta
and pmd_rss_hash test suites has been collated into a single
file called rss_utils.
It contains 3 main functions:
1. verify that a packets RSS hash correctly associates with
the packets RSS queue.
2. Send test packets specific to RSS, such as symmetric
packets that have the L4 port src and dst swapped.
3. The setting up of the RSS environment which is common
between all 3 tets suites.
Signed-off-by: Alex Chapman <alex.chapman@arm.com>
Signed-off-by: Thomas Wilks <thomas.wilks@arm.com>
Reviewed-by: Paul Szczepanek <paul.szczepanek@arm.com>
---
| 195 +++++++++++++++++++++++++++++++++++++
1 file changed, 195 insertions(+)
create mode 100644 dts/tests/pmd_rss_utils.py
--git a/dts/tests/pmd_rss_utils.py b/dts/tests/pmd_rss_utils.py
new file mode 100644
index 0000000000..2d9b333859
--- /dev/null
+++ b/dts/tests/pmd_rss_utils.py
@@ -0,0 +1,195 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2025 Arm Limited
+
+"""PMD RSS Test Suite Utils.
+
+Utility functions for the pmd_rss_... test suite series
+"""
+
+import random
+
+from scapy.layers.inet import IP, UDP
+from scapy.layers.l2 import Ether
+
+from framework.exception import InteractiveCommandExecutionError
+from framework.params.testpmd import SimpleForwardingModes
+from framework.remote_session.testpmd_shell import (
+ FlowRule,
+ RSSOffloadTypesFlag,
+ TestPmdShell,
+ TestPmdVerbosePacket,
+)
+from framework.test_suite import TestSuite
+
+
+def VerifyHashQueue(
+ test_suite: TestSuite,
+ reta: list[int],
+ received_packets: list[TestPmdVerbosePacket],
+ verify_packet_pairs: bool,
+) -> None:
+ """Verifies the packet hash corresponds to the packet queue.
+
+ Given the received packets in the verbose output, iterate through each packet.
+ Lookup the packet hash in the RETA and get its intended queue.
+ Verify the intended queue is the same as the actual queue the packet was received in.
+ If the hash algorithm is symmetric, verify that pairs of packets have the same hash,
+ as the pairs of packets sent have "mirrored" L4 ports.
+ e.g. received_packets[0, 1, 2, 3, ...] hash(0) = hash(1), hash(2) = hash(3), ...
+
+ Args:
+ test_suite: The reference to the currently running test suite.
+ reta: Used to get predicted queue based on hash.
+ received_packets: Packets received in the verbose output of testpmd.
+ verify_packet_pairs: Verify pairs of packets have the same hash.
+
+ Raises:
+ InteractiveCommandExecutionError: If packet_hash is None.
+ """
+ # List of packet hashes, used for symmetric algorithms
+ hash_list = []
+ for packet in received_packets:
+ if packet.port_id != 0 or packet.src_mac != "02:00:00:00:00:00":
+ continue
+
+ # Get packet hash
+ packet_hash = packet.rss_hash
+ if packet_hash is None:
+ raise InteractiveCommandExecutionError(
+ "Packet sent by the Traffic Generator has no RSS hash attribute."
+ )
+
+ packet_queue = packet.rss_queue
+
+ # Calculate the predicted packet queue
+ predicted_reta_index = packet_hash % len(reta)
+ predicted_queue = reta[predicted_reta_index]
+
+ # Verify packets are in the correct queue
+ test_suite.verify(
+ predicted_queue == packet_queue,
+ "Packet sent by the Traffic Generator has no RSS queue attribute.",
+ )
+
+ if verify_packet_pairs:
+ hash_list.append(packet_hash)
+
+ if verify_packet_pairs:
+ # Go through pairs of hashes in list and verify they are the same
+ for odd_hash, even_hash in zip(hash_list[0::2], hash_list[1::2]):
+ test_suite.verify(
+ odd_hash == even_hash,
+ "Packet pair do not have same hash. Hash algorithm is not symmetric.",
+ )
+
+
+def SendTestPackets(
+ TestSuite: TestSuite,
+ testpmd: TestPmdShell,
+ send_additional_mirrored_packet: bool,
+) -> list[TestPmdVerbosePacket]:
+ """Sends test packets.
+
+ Send 10 packets from the TG to SUT, parsing the verbose output and returning it.
+ If the algorithm chosen is symmetric, send an additional packet for each initial
+ packet sent, which has the L4 src and dst swapped.
+
+ Args:
+ TestSuite: The reference to the currently running test suite.
+ testpmd: Used to send packets and send commands to testpmd.
+ send_additional_mirrored_packet: Send an additional mirrored packet for each packet sent.
+
+ Returns:
+ TestPmdVerbosePacket: List of packets.
+ """
+ # Create test packets
+ packets = []
+ for i in range(10):
+ packets.append(
+ Ether(src="02:00:00:00:00:00", dst="11:00:00:00:00:00")
+ / IP()
+ / UDP(sport=i, dport=i + 1),
+ )
+ if send_additional_mirrored_packet: # If symmetric, send the inverse packets
+ packets.append(
+ Ether(src="02:00:00:00:00:00", dst="11:00:00:00:00:00")
+ / IP()
+ / UDP(sport=i + 1, dport=i),
+ )
+
+ # Set verbose packet information and start packet capture
+ testpmd.set_verbose(3)
+ testpmd.start()
+ testpmd.start_all_ports()
+ TestSuite.send_packets_and_capture(packets)
+
+ # Stop packet capture and revert verbose packet information
+ testpmd_shell_out = testpmd.stop()
+ testpmd.set_verbose(0)
+ # Parse the packets and return them
+ return testpmd.extract_verbose_output(testpmd_shell_out)
+
+
+def SetupRssEnvironment(
+ TestSuite: TestSuite,
+ testpmd: TestPmdShell,
+ num_queues: int,
+ flow_rule: FlowRule | None,
+) -> tuple[list[int], int]:
+ """Sets up the testpmd environment for RSS test suites.
+
+ This involves:
+ 1. Setting the testpmd forward mode to rx_only.
+ 2. Setting RSS on the NIC to UDP.
+ 3. Creating a flow if provided.
+ 4. Configuring RETA.
+
+ The reta and key_size of the NIC are then returned
+
+ Args:
+ TestSuite: TestSuite environment.
+ testpmd: Where the environment will be set.
+ num_queues: Number of queues in the RETA table.
+ flow_rule: The flow rule for altering packet fate.
+
+ Raises:
+ InteractiveCommandExecutionError: If size of hash key for driver is None.
+ InteractiveCommandExecutionError: If size of RETA table for driver is None.
+
+ Returns:
+ reta: Configured Redirection Table.
+ key_size: key size supported by NIC.
+ """
+ ports = []
+ for port_id, _ in enumerate(TestSuite.topology.sut_ports):
+ ports.append(port_id)
+
+ port_info = testpmd.show_port_info(ports[0])
+
+ # Get hash key size
+ key_size = port_info.hash_key_size
+ if key_size is None:
+ raise InteractiveCommandExecutionError("Size of hash key for driver is None.")
+
+ # Get RETA table size
+ reta_size = port_info.redirection_table_size
+ if reta_size is None:
+ raise InteractiveCommandExecutionError("Size of RETA table for driver is None.")
+
+ # Set forward mode to receive only, to remove forwarded packets from verbose output
+ testpmd.set_forward_mode(SimpleForwardingModes.rxonly)
+
+ # Reset RSS settings and only RSS udp packets
+ testpmd.port_config_all_rss_offload_type(RSSOffloadTypesFlag.udp)
+
+ # Create flow rule
+ if flow_rule is not None:
+ testpmd.flow_create(flow_rule, ports[0])
+
+ # Configure the RETA with random queues
+ reta: list[int] = []
+ for i in range(reta_size):
+ reta.insert(i, random.randint(0, num_queues - 1))
+ testpmd.port_config_rss_reta(ports[0], i, reta[i])
+
+ return reta, key_size
--
2.43.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 3/6] dts: add PMD RSS hash testsuite
2025-02-25 15:33 ` [PATCH v2 0/6] Added RSS functions and tests Thomas Wilks
2025-02-25 15:33 ` [PATCH v2 1/6] dts: add RSS functions to testpmd Thomas Wilks
2025-02-25 15:33 ` [PATCH v2 2/6] dts: add utils for PMD RSS testsuites Thomas Wilks
@ 2025-02-25 15:33 ` Thomas Wilks
2025-02-25 15:33 ` [PATCH v2 4/6] dts: add PMD RSS RETA testsuite Thomas Wilks
` (2 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Thomas Wilks @ 2025-02-25 15:33 UTC (permalink / raw)
To: dev
Cc: Paul Szczepanek, Luca Vizzarro, Patrick Robb, Alex Chapman, Thomas Wilks
From: Alex Chapman <alex.chapman@arm.com>
Port over the pmd_rss_hash test suite from old DTS. This
suite verifies that the 4 supported types of hashing
algorithm used in Receive Side Scaling (RSS) function
correctly. Them being DEFAULT, TOEPLITZ
SYMMETRIC_TOEPLITZ and SIMPLE_XOR. This test suite also
verifies the supported hashing algorithms reported by
the NIC are correct.
Signed-off-by: Alex Chapman <alex.chapman@arm.com>
Signed-off-by: Thomas Wilks <thomas.wilks@arm.com>
Reviewed-by: Paul Szczepanek <paul.szczepanek@arm.com>
---
| 118 ++++++++++++++++++++++++++++
1 file changed, 118 insertions(+)
create mode 100644 dts/tests/TestSuite_pmd_rss_hash.py
--git a/dts/tests/TestSuite_pmd_rss_hash.py b/dts/tests/TestSuite_pmd_rss_hash.py
new file mode 100644
index 0000000000..d21e33456e
--- /dev/null
+++ b/dts/tests/TestSuite_pmd_rss_hash.py
@@ -0,0 +1,118 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2025 Arm Limited
+
+"""RSS Hash testing suite.
+
+Hashing algorithms are used in conjunction with a RSS hash keys to hash packets.
+This test suite verifies that updating the Hashing algorithms will
+continue to correctly hash packets.
+
+Symmetric_toeplitz_sort hasn't been included due to it not being supported by
+the rss func actions in the flow rule.
+"""
+
+from framework.remote_session.testpmd_shell import FlowRule, TestPmdShell
+from framework.test_suite import TestSuite, func_test
+from framework.testbed_model.capability import NicCapability, requires
+from framework.testbed_model.topology import TopologyType
+from framework.utils import StrEnum
+
+from .pmd_rss_utils import ( # type: ignore[import-untyped]
+ SendTestPackets,
+ SetupRssEnvironment,
+ VerifyHashQueue,
+)
+
+NUM_QUEUES = 16
+
+
+class HashAlgorithm(StrEnum):
+ """Enum of hashing algorithms."""
+
+ DEFAULT = "default"
+ SIMPLE_XOR = "simple_xor"
+ TOEPLITZ = "toeplitz"
+ SYMMETRIC_TOEPLITZ = "symmetric_toeplitz"
+
+
+@requires(topology_type=TopologyType.one_link)
+class TestPmdRssHash(TestSuite):
+ """PMD RSS Hash test suite.
+
+ Verifies the redirection table when updating the size.
+ The suite contains four tests, one for each hash algorithms.
+ """
+
+ def VerifyHashFunction(self, hash_algorithm: HashAlgorithm) -> None:
+ """Verifies the hash function is supported by the NIC.
+
+ Args:
+ hash_algorithm: The hash algorithm to be tested.
+ """
+ is_symmetric = hash_algorithm == HashAlgorithm.SYMMETRIC_TOEPLITZ
+ # Build flow rule
+ flow_rule = FlowRule(
+ group_id=0,
+ direction="ingress",
+ pattern=["eth / ipv4 / udp"],
+ actions=[f"rss types ipv4-udp end queues end func {str(hash_algorithm).lower()}"],
+ )
+
+ # Run the key update test suite with an asymmetric hash algorithm
+ with TestPmdShell(
+ rx_queues=NUM_QUEUES,
+ tx_queues=NUM_QUEUES,
+ ) as testpmd:
+ # Setup testpmd environment for RSS, create RETA table, return RETA table and key_size
+ reta, _ = SetupRssEnvironment(self, testpmd, NUM_QUEUES, flow_rule)
+ # Send udp packets and ensure hash corresponds with queue
+ parsed_output = SendTestPackets(self, testpmd, is_symmetric)
+ VerifyHashQueue(self, reta, parsed_output, is_symmetric)
+
+ @func_test
+ def TestDefaultHashAlgorithm(self) -> None:
+ """Default hashing algorithm test.
+
+ Steps:
+ Setup RSS environment using the default RSS hashing algorithm
+ and send test packets.
+ Verify:
+ Packet hash corresponds to the packet queue.
+ """
+ self.VerifyHashFunction(HashAlgorithm.DEFAULT)
+
+ @func_test
+ def TestToeplitzHashAlgorithm(self) -> None:
+ """Toeplitz hashing algorithm test.
+
+ Steps:
+ Setup RSS environment using the toeplitz RSS hashing algorithm and send test packets.
+ Verify:
+ Packet hash corresponds to the packet queue.
+ """
+ self.VerifyHashFunction(HashAlgorithm.TOEPLITZ)
+
+ @func_test
+ def TestSymmetricToeplitzHashAlgorithm(self) -> None:
+ """Symmetric toeplitz hashing algorithm test.
+
+ Steps:
+ Setup RSS environment using the symmetric_toeplitz RSS hashing algorithm
+ and send test packets.
+ Verify:
+ Packet hash corresponds to the packet queue.
+ """
+ self.VerifyHashFunction(HashAlgorithm.SYMMETRIC_TOEPLITZ)
+
+ @requires(NicCapability.XOR_SUPPORT)
+ @func_test
+ def TestSimpleXorHashAlgorithm(self) -> None:
+ """Simple xor hashing algorithm test.
+
+ Steps:
+ Setup RSS environment using the simple xor RSS hashing algorithm
+ and send test packets.
+ Verify:
+ Packet hash corresponds to the packet queue.
+ """
+ self.VerifyHashFunction(HashAlgorithm.SIMPLE_XOR)
--
2.43.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 4/6] dts: add PMD RSS RETA testsuite
2025-02-25 15:33 ` [PATCH v2 0/6] Added RSS functions and tests Thomas Wilks
` (2 preceding siblings ...)
2025-02-25 15:33 ` [PATCH v2 3/6] dts: add PMD RSS hash testsuite Thomas Wilks
@ 2025-02-25 15:33 ` Thomas Wilks
2025-02-25 15:33 ` [PATCH v2 5/6] dts: add PMD RSS key update testsuite Thomas Wilks
2025-02-25 15:33 ` [PATCH v2 6/6] dts: add NIC capabilities for hash algorithms Thomas Wilks
5 siblings, 0 replies; 9+ messages in thread
From: Thomas Wilks @ 2025-02-25 15:33 UTC (permalink / raw)
To: dev
Cc: Paul Szczepanek, Luca Vizzarro, Patrick Robb, Alex Chapman, Thomas Wilks
From: Alex Chapman <alex.chapman@arm.com>
Port over the pmd_rss_reta test suite from old DTS. This
suite verifies that Redirection Tables (RETAs) of different
sizes function correctly in Receive Side Scaling (RSS).
This test suite also verifies that the reported reta size
of the NIC is correct.
Signed-off-by: Alex Chapman <alex.chapman@arm.com>
Signed-off-by: Thomas Wilks <thomas.wilks@arm.com>
Reviewed-by: Paul Szczepanek <paul.szczepanek@arm.com>
---
| 101 ++++++++++++++++++++++++++++
1 file changed, 101 insertions(+)
create mode 100644 dts/tests/TestSuite_pmd_rss_reta.py
--git a/dts/tests/TestSuite_pmd_rss_reta.py b/dts/tests/TestSuite_pmd_rss_reta.py
new file mode 100644
index 0000000000..31df817e75
--- /dev/null
+++ b/dts/tests/TestSuite_pmd_rss_reta.py
@@ -0,0 +1,101 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2025 Arm Limited
+
+"""RSS RETA (redirection table) Test Suite.
+
+The RETA is used in RSS to redirect packets to different queues based on the
+least significant bits of the packets hash.
+This suite tests updating the size of the RETA and verifying the reported RETA size.
+"""
+
+from framework.remote_session.testpmd_shell import TestPmdShell
+from framework.test_suite import TestSuite, func_test
+from framework.testbed_model.capability import requires
+from framework.testbed_model.topology import TopologyType
+
+from .pmd_rss_utils import ( # type: ignore[import-untyped]
+ SendTestPackets,
+ SetupRssEnvironment,
+ VerifyHashQueue,
+)
+
+ACTUAL_RETA_SIZE = 512
+
+
+@requires(topology_type=TopologyType.one_link)
+class TestPmdRssReta(TestSuite):
+ """PMD RSS Reta test suite.
+
+ Verifies the redirection table when updating the size.
+ The suite contains four tests, three for different RETA sizes
+ and one for verifying the reported RETA size.
+ """
+
+ def CheckRetaNQueues(self, num_queues: int) -> None:
+ """Create RETA of size n, send packets, verify packets end up in correct queue.
+
+ Args:
+ num_queues: Number of rx/tx queues.
+ """
+ with TestPmdShell(
+ rx_queues=num_queues,
+ tx_queues=num_queues,
+ ) as testpmd:
+ # Setup testpmd for RSS, create RETA table, return RETA table and key_size
+ reta, _ = SetupRssEnvironment(self, testpmd, num_queues, None)
+
+ # Send UDP packets and ensure hash corresponds with queue
+ parsed_output = SendTestPackets(self, testpmd, False)
+ VerifyHashQueue(self, reta, parsed_output, False)
+
+ @func_test
+ def TestReta2Queues(self) -> None:
+ """RETA rx/tx queues 2 test.
+
+ Steps:
+ Setup RSS environment and send Test packets.
+ Verify:
+ Packet hash corresponds to hash queue.
+ """
+ self.CheckRetaNQueues(2)
+
+ @func_test
+ def TestReta9Queues(self) -> None:
+ """RETA rx/tx queues 9 test.
+
+ Steps:
+ Setup RSS environment and send Test packets.
+ Verify:
+ Packet hash corresponds to hash queue.
+ """
+ self.CheckRetaNQueues(9)
+
+ @func_test
+ def TestReta16Queues(self) -> None:
+ """RETA rx/tx queues 16 test.
+
+ Steps:
+ Setup RSS environment and send Test packets.
+ Verify:
+ Packet hash corresponds to hash queue.
+ """
+ self.CheckRetaNQueues(16)
+
+ @func_test
+ def TestReportedRetaSize(self) -> None:
+ """Reported RETA size test.
+
+ Steps:
+ Fetch reported reta size.
+ Verify:
+ Reported RETA size is equal to the actual RETA size.
+ """
+ with TestPmdShell() as testpmd:
+ self.topology.sut_port_egress.config
+ # Get RETA table size
+ port_info = testpmd.show_port_info(0)
+ reported_reta_size = port_info.redirection_table_size
+ self.verify(
+ reported_reta_size == ACTUAL_RETA_SIZE,
+ "Reported RETA size is not the same as the config file.",
+ )
--
2.43.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 5/6] dts: add PMD RSS key update testsuite
2025-02-25 15:33 ` [PATCH v2 0/6] Added RSS functions and tests Thomas Wilks
` (3 preceding siblings ...)
2025-02-25 15:33 ` [PATCH v2 4/6] dts: add PMD RSS RETA testsuite Thomas Wilks
@ 2025-02-25 15:33 ` Thomas Wilks
2025-02-25 15:33 ` [PATCH v2 6/6] dts: add NIC capabilities for hash algorithms Thomas Wilks
5 siblings, 0 replies; 9+ messages in thread
From: Thomas Wilks @ 2025-02-25 15:33 UTC (permalink / raw)
To: dev
Cc: Paul Szczepanek, Luca Vizzarro, Patrick Robb, Alex Chapman, Thomas Wilks
From: Alex Chapman <alex.chapman@arm.com>
Port over the rss_key_update test suite from old DTS. This
suite verifies that setting a new hash key when Receive Side
Scaling (RSS) will result in a change in the packets destination
queue. This test suite also verifies that the reported key size
of the NIC is correct.
Signed-off-by: Alex Chapman <alex.chapman@arm.com>
Signed-off-by: Thomas Wilks <thomas.wilks@arm.com>
Reviewed-by: Paul Szczepanek <paul.szczepanek@arm.com>
---
| 168 ++++++++++++++++++++++
1 file changed, 168 insertions(+)
create mode 100644 dts/tests/TestSuite_pmd_rss_key_update.py
--git a/dts/tests/TestSuite_pmd_rss_key_update.py b/dts/tests/TestSuite_pmd_rss_key_update.py
new file mode 100644
index 0000000000..8a88d44e77
--- /dev/null
+++ b/dts/tests/TestSuite_pmd_rss_key_update.py
@@ -0,0 +1,168 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2025 Arm Limited
+
+"""RSS Key Update testing suite.
+
+RSS hash keys are used in conjunction with a hashing algorithm to hash packets.
+This test suite verifies that updating the RSS hash key will change the hash
+generated if the hashing algorithm stays the same.
+"""
+
+import random
+
+from framework.exception import InteractiveCommandExecutionError
+from framework.remote_session.testpmd_shell import (
+ FlowRule,
+ RSSOffloadTypesFlag,
+ TestPmdShell,
+)
+from framework.test_suite import TestSuite, func_test
+from framework.testbed_model.capability import requires
+from framework.testbed_model.topology import TopologyType
+
+from .pmd_rss_utils import ( # type: ignore[import-untyped]
+ SendTestPackets,
+ SetupRssEnvironment,
+ VerifyHashQueue,
+)
+
+NUM_QUEUES = 16
+
+ACTUAL_KEY_SIZE = 52
+
+
+@requires(topology_type=TopologyType.one_link)
+class TestPmdRssKeyUpdate(TestSuite):
+ """The DPDK RSS key update test suite.
+
+ Configure the redirection table to have random entries.
+ Create a flow rule so ipv4-udp packets utalise the desired RSS hash algorithm.
+ Send packets, and verify they are in the desired queue based on the redirection table.
+ Update the RSS hash key.
+ Send packets, and verify they are in the desired queue based on the redirection table.
+ Verify the packet hashes before and after the key update are different.
+ """
+
+ @func_test
+ def TestKeyUpdate(
+ self,
+ ) -> None:
+ """Update RSS hash key test.
+
+ Steps:
+ Setup the RSS environment, send test packet verify the hash queue based on the
+ RETA table, Reset the flow rules and update the hash key.
+ Create the flow and send/verify the hash/queue of the packets again.
+
+ Verify:
+ Verify the packet hashes before and after the hash key was updated are not the same.
+ to show the key update was successful.
+ """
+ # Create flow rule
+ flow_rule = FlowRule(
+ group_id=0,
+ direction="ingress",
+ pattern=["eth / ipv4 / udp"],
+ actions=["rss types ipv4-udp end queues end func default"],
+ )
+
+ with TestPmdShell(
+ memory_channels=4,
+ rx_queues=NUM_QUEUES,
+ tx_queues=NUM_QUEUES,
+ ) as testpmd:
+ # Setup testpmd environment for RSS, create RETA table, return RETA table and key_size
+ reta, key_size = SetupRssEnvironment(self, testpmd, NUM_QUEUES, flow_rule)
+
+ # Send UDP packets and ensure hash corresponds with queue
+ pre_update_output = SendTestPackets(self, testpmd, False)
+
+ VerifyHashQueue(self, reta, pre_update_output, False)
+
+ # Reset RSS settings and only RSS UDP packets
+ testpmd.port_config_all_rss_offload_type(RSSOffloadTypesFlag.udp)
+
+ # Create new hash key and update it
+ new_hash_key = "".join([random.choice("0123456789ABCDEF") for n in range(key_size * 2)])
+ testpmd.port_config_rss_hash_key(0, RSSOffloadTypesFlag.ipv4_udp, new_hash_key)
+
+ # Create flow rule
+
+ for port_id, _ in enumerate(self.topology.sut_ports):
+ testpmd.flow_create(flow_rule, port_id)
+
+ # Send UDP packets and ensure hash corresponds with queue
+ post_update_output = SendTestPackets(self, testpmd, False)
+ VerifyHashQueue(self, reta, pre_update_output, False)
+
+ self.verify(
+ pre_update_output != post_update_output,
+ "The hash key had no effect on the packets hash.",
+ )
+
+ @func_test
+ def TestSetHashKeyShortLong(self) -> None:
+ """Set hash key short long test.
+
+ Steps:
+ Fetch the hash key size, create two random hash keys one key that is too short and one
+ that is too long.
+
+ Verify:
+ Verify that it is not possible to set the shorter key.
+ Verify that it is not possible to set the longer key.
+
+ Raises:
+ InteractiveCommandExecutionError: If port info dose not contain hash key size.
+ """
+ with TestPmdShell(
+ memory_channels=4,
+ rx_queues=NUM_QUEUES,
+ tx_queues=NUM_QUEUES,
+ ) as testpmd:
+ # Get RETA and key size
+ port_info = testpmd.show_port_info(0)
+
+ # Get hash key size
+ key_size = port_info.hash_key_size
+ if key_size is None:
+ raise InteractiveCommandExecutionError("Port info does not contain hash key size.")
+
+ # Create 2 hash keys based on the NIC capabilities
+ short_key = "".join(
+ [random.choice("0123456789ABCDEF") for n in range(key_size * 2 - 2)]
+ )
+ long_key = "".join([random.choice("0123456789ABCDEF") for n in range(key_size * 2 + 2)])
+
+ # Verify a short key cannot be set
+ short_key_out = testpmd.port_config_rss_hash_key(
+ 0, RSSOffloadTypesFlag.ipv4_udp, short_key, False
+ )
+ self.verify(
+ "invalid" in short_key_out,
+ "Able to set hash key shorter than specified.",
+ )
+
+ # Verify a long key cannot be set
+ long_key_out = testpmd.port_config_rss_hash_key(
+ 0, RSSOffloadTypesFlag.ipv4_udp, long_key, False
+ )
+ self.verify("invalid" in long_key_out, "Able to set hash key longer than specified.")
+
+ @func_test
+ def TestReportedKeySize(self) -> None:
+ """Verify reported hash key size is the same as the NIC capabilities.
+
+ Steps:
+ Fetch the hash key size and compare to the actual key size.
+ Verify:
+ Reported key size is the same as the actual key size.
+ """
+ with TestPmdShell() as testpmd:
+ port_info = testpmd.show_port_info(0)
+ reported_key_size = port_info.hash_key_size
+
+ self.verify(
+ reported_key_size == ACTUAL_KEY_SIZE,
+ "Reported key size is not the same as the config file.",
+ )
--
2.43.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 6/6] dts: add NIC capabilities for hash algorithms
2025-02-25 15:33 ` [PATCH v2 0/6] Added RSS functions and tests Thomas Wilks
` (4 preceding siblings ...)
2025-02-25 15:33 ` [PATCH v2 5/6] dts: add PMD RSS key update testsuite Thomas Wilks
@ 2025-02-25 15:33 ` Thomas Wilks
5 siblings, 0 replies; 9+ messages in thread
From: Thomas Wilks @ 2025-02-25 15:33 UTC (permalink / raw)
To: dev; +Cc: Paul Szczepanek, Luca Vizzarro, Patrick Robb, Thomas Wilks
Added checks for if a nic supports the simple_xor,
symmetric_toeplitz, symmetric_toeplitz_sort,
toeplitz, and default hashing algorithms.
Signed-off-by: Thomas Wilks <thomas.wilks@arm.com>
Reviewed-by: Paul Szczepanek <paul.szczepanek@arm.com>
---
dts/framework/remote_session/testpmd_shell.py | 146 ++++++++++++++++++
| 5 +-
2 files changed, 150 insertions(+), 1 deletion(-)
diff --git a/dts/framework/remote_session/testpmd_shell.py b/dts/framework/remote_session/testpmd_shell.py
index 0e1f29f2f3..4a5b31574c 100644
--- a/dts/framework/remote_session/testpmd_shell.py
+++ b/dts/framework/remote_session/testpmd_shell.py
@@ -2678,6 +2678,127 @@ def get_capabilities_flow_ctrl(
else:
unsupported_capabilities.add(NicCapability.FLOW_CTRL)
+ def get_capabilities_xor_rss_hash_algorithms(
+ self,
+ supported_capabilities: MutableSet["NicCapability"],
+ unsupported_capabilities: MutableSet["NicCapability"],
+ ) -> None:
+ """Get simple_xor rss hash algorithm capability and check for testpmd failure.
+
+ Args:
+ supported_capabilities: Supported capabilities will be added to this set.
+ unsupported_capabilities: Unsupported capabilities will be added to this set.
+ """
+ self.get_capabilities_rss_hash_algorithms(
+ "simple_xor",
+ NicCapability.RSS_HASH_XOR,
+ supported_capabilities,
+ unsupported_capabilities,
+ )
+
+ def get_capabilities_symmetric_toeplitz_rss_hash_algorithms(
+ self,
+ supported_capabilities: MutableSet["NicCapability"],
+ unsupported_capabilities: MutableSet["NicCapability"],
+ ) -> None:
+ """Get symmetric_toeplitz rss hash algorithm capability and check for testpmd failure.
+
+ Args:
+ supported_capabilities: Supported capabilities will be added to this set.
+ unsupported_capabilities: Unsupported capabilities will be added to this set.
+ """
+ self.get_capabilities_rss_hash_algorithms(
+ "symmetric Toeplitz",
+ NicCapability.RSS_HASH_SYMMETRIC_TOEPLITZ,
+ supported_capabilities,
+ unsupported_capabilities,
+ )
+
+ def get_capabilities_toeplitz_rss_hash_algorithms(
+ self,
+ supported_capabilities: MutableSet["NicCapability"],
+ unsupported_capabilities: MutableSet["NicCapability"],
+ ) -> None:
+ """Get toeplitz rss hash algorithm capability and check for testpmd failure.
+
+ Args:
+ supported_capabilities: Supported capabilities will be added to this set.
+ unsupported_capabilities: Unsupported capabilities will be added to this set.
+ """
+ self.get_capabilities_rss_hash_algorithms(
+ "toeplitz",
+ NicCapability.RSS_HASH_TOEPLITZ,
+ supported_capabilities,
+ unsupported_capabilities,
+ )
+
+ def get_capabilities_default_rss_hash_algorithms(
+ self,
+ supported_capabilities: MutableSet["NicCapability"],
+ unsupported_capabilities: MutableSet["NicCapability"],
+ ) -> None:
+ """Get default rss hash algorithm capability and check for testpmd failure.
+
+ Args:
+ supported_capabilities: Supported capabilities will be added to this set.
+ unsupported_capabilities: Unsupported capabilities will be added to this set.
+ """
+ self.get_capabilities_rss_hash_algorithms(
+ "default",
+ NicCapability.RSS_HASH_DEFAULT,
+ supported_capabilities,
+ unsupported_capabilities,
+ )
+
+ def get_capabilities_symmetric_toeplitz_sort_rss_hash_algorithms(
+ self,
+ supported_capabilities: MutableSet["NicCapability"],
+ unsupported_capabilities: MutableSet["NicCapability"],
+ ) -> None:
+ """Get symmetric_toeplitz_sort rss hash algorithm capability and check for testpmd failure.
+
+ Args:
+ supported_capabilities: Supported capabilities will be added to this set.
+ unsupported_capabilities: Unsupported capabilities will be added to this set.
+ """
+ self.get_capabilities_rss_hash_algorithms(
+ "symmetric_toeplitz_sort",
+ NicCapability.RSS_HASH_SYMMETRIC_TOEPLITZ_SORT,
+ supported_capabilities,
+ unsupported_capabilities,
+ )
+
+ def get_capabilities_rss_hash_algorithms(
+ self,
+ algorithm: str,
+ NicCapability,
+ supported_capabilities: MutableSet["NicCapability"],
+ unsupported_capabilities: MutableSet["NicCapability"],
+ ):
+ """Get algorithm and check for capability.
+
+ Args:
+ algorithm: The rss algorithm that is being tested.
+ NicCapability: The nic capability constant to be added to one of the MutableSets.
+ supported_capabilities: Supported capabilities will be added to this set.
+ unsupported_capabilities: Unsupported capabilities will be added to this set.
+
+ """
+ self._logger.debug(f"Getting hash capabilities for {algorithm} algorithm.")
+ self.send_command("port stop all")
+ self.send_command("port config all rxq 16")
+ self.send_command("port config all txq 16")
+ self.send_command("port start all")
+ command = f"show port {self.ports[0].id} rss-hash algorithm"
+ output = self.send_command(command)
+ if algorithm in output:
+ supported_capabilities.add(NicCapability)
+ else:
+ unsupported_capabilities.add(NicCapability)
+ self.send_command("port stop all")
+ self.send_command("port config all rxq 0")
+ self.send_command("port config all txq 0")
+
class NicCapability(NoAliasEnum):
"""A mapping between capability names and the associated :class:`TestPmdShell` methods.
@@ -2844,6 +2965,31 @@ class NicCapability(NoAliasEnum):
TestPmdShell.get_capabilities_flow_ctrl,
None,
)
+ #: Device supports simple_xor algorithm.
+ RSS_HASH_XOR: TestPmdShellNicCapability = (
+ TestPmdShell.get_capabilities_xor_rss_hash_algorithms,
+ None,
+ )
+ #: Device supports symmetric_toeplitz algorithm.
+ RSS_HASH_SYMMETRIC_TOEPLITZ: TestPmdShellNicCapability = (
+ TestPmdShell.get_capabilities_symmetric_toeplitz_rss_hash_algorithms,
+ None,
+ )
+ #: Device supports toeplitz algorithm.
+ RSS_HASH_TOEPLITZ: TestPmdShellNicCapability = (
+ TestPmdShell.get_capabilities_toeplitz_rss_hash_algorithms,
+ None,
+ )
+ #: Device supports default algorithm.
+ RSS_HASH_DEFAULT: TestPmdShellNicCapability = (
+ TestPmdShell.get_capabilities_default_rss_hash_algorithms,
+ None,
+ )
+ #: Device supports symmetric_toeplitz_sort algorithm.
+ RSS_HASH_SYMMETRIC_TOEPLITZ_SORT: TestPmdShellNicCapability = (
+ TestPmdShell.get_capabilities_symmetric_toeplitz_sort_rss_hash_algorithms,
+ None,
+ )
def __call__(
self,
--git a/dts/tests/TestSuite_pmd_rss_hash.py b/dts/tests/TestSuite_pmd_rss_hash.py
index d21e33456e..93aad80d50 100644
--- a/dts/tests/TestSuite_pmd_rss_hash.py
+++ b/dts/tests/TestSuite_pmd_rss_hash.py
@@ -69,6 +69,7 @@ def VerifyHashFunction(self, hash_algorithm: HashAlgorithm) -> None:
parsed_output = SendTestPackets(self, testpmd, is_symmetric)
VerifyHashQueue(self, reta, parsed_output, is_symmetric)
+ @requires(NicCapability.RSS_HASH_DEFAULT)
@func_test
def TestDefaultHashAlgorithm(self) -> None:
"""Default hashing algorithm test.
@@ -81,6 +82,7 @@ def TestDefaultHashAlgorithm(self) -> None:
"""
self.VerifyHashFunction(HashAlgorithm.DEFAULT)
+ @requires(NicCapability.RSS_HASH_TOEPLITZ)
@func_test
def TestToeplitzHashAlgorithm(self) -> None:
"""Toeplitz hashing algorithm test.
@@ -92,6 +94,7 @@ def TestToeplitzHashAlgorithm(self) -> None:
"""
self.VerifyHashFunction(HashAlgorithm.TOEPLITZ)
+ @requires(NicCapability.RSS_HASH_SYMMETRIC_TOEPLITZ)
@func_test
def TestSymmetricToeplitzHashAlgorithm(self) -> None:
"""Symmetric toeplitz hashing algorithm test.
@@ -104,7 +107,7 @@ def TestSymmetricToeplitzHashAlgorithm(self) -> None:
"""
self.VerifyHashFunction(HashAlgorithm.SYMMETRIC_TOEPLITZ)
- @requires(NicCapability.XOR_SUPPORT)
+ @requires(NicCapability.RSS_HASH_XOR)
@func_test
def TestSimpleXorHashAlgorithm(self) -> None:
"""Simple xor hashing algorithm test.
--
2.43.0
^ permalink raw reply [flat|nested] 9+ messages in thread