From: Patrick Robb <probb@iol.unh.edu>
To: Dean Marx <dmarx@iol.unh.edu>
Cc: luca.vizzarro@arm.com, yoan.picchi@foss.arm.com,
Honnappa.Nagarahalli@arm.com, paul.szczepanek@arm.com,
dev@dpdk.org,
"NBU-Contact-Thomas Monjalon (EXTERNAL)" <thomas@monjalon.net>
Subject: Re: [PATCH v3 1/2] dts: add rte flow test suite
Date: Fri, 27 Jun 2025 10:20:39 -0400 [thread overview]
Message-ID: <CAJvnSUD91p_7DYge3PCy5J3CNPEX3fjy6DD7xLH7inWWHRkCEQ@mail.gmail.com> (raw)
In-Reply-To: <20250626195617.219395-1-dmarx@iol.unh.edu>
[-- Attachment #1: Type: text/plain, Size: 36235 bytes --]
On Thu, Jun 26, 2025 at 3:56 PM Dean Marx <dmarx@iol.unh.edu> wrote:
> Add an RTE Flow API testing suite, which covers some basic
> synchronous Flow API rules that should be supported across PMDs.
> This suite will be added to over time, as the Flow API is too large
> to cover all in one suite, and sending one monolithic series
> would be impossible.
>
> Signed-off-by: Dean Marx <dmarx@iol.unh.edu>
> Reviewed-by: Patrick Robb <probb@iol.unh.edu>
> ---
> doc/api/dts/tests.TestSuite_rte_flow.rst | 8 +
> dts/tests/TestSuite_rte_flow.py | 790 +++++++++++++++++++++++
> 2 files changed, 798 insertions(+)
> create mode 100644 doc/api/dts/tests.TestSuite_rte_flow.rst
> create mode 100644 dts/tests/TestSuite_rte_flow.py
>
> diff --git a/doc/api/dts/tests.TestSuite_rte_flow.rst
> b/doc/api/dts/tests.TestSuite_rte_flow.rst
> new file mode 100644
> index 0000000000..cad96b2530
> --- /dev/null
> +++ b/doc/api/dts/tests.TestSuite_rte_flow.rst
> @@ -0,0 +1,8 @@
> +.. SPDX-License-Identifier: BSD-3-Clause
> +
> +checksum_offload Test Suite
>
I'm just seeing this rst misnaming of the testsuite with the docs build
now. I'm going to update and force push to next-dts.
> +===========================
> +
> +.. automodule:: tests.TestSuite_rte_flow
> + :members:
> + :show-inheritance:
> \ No newline at end of file
> diff --git a/dts/tests/TestSuite_rte_flow.py
> b/dts/tests/TestSuite_rte_flow.py
> new file mode 100644
> index 0000000000..e70f7ea8d1
> --- /dev/null
> +++ b/dts/tests/TestSuite_rte_flow.py
> @@ -0,0 +1,790 @@
> +# SPDX-License-Identifier: BSD-3-Clause
> +# Copyright(c) 2025 University of New Hampshire
> +
> +"""RTE Flow testing suite.
> +
> +This suite verifies a range of flow rules built using patterns
> +and actions from the RTE Flow API. It would be impossible to cover
> +every valid flow rule, but this suite aims to test the most
> +important and common functionalities across PMDs.
> +
> +"""
> +
> +from collections.abc import Callable
> +from itertools import zip_longest
> +from typing import Any, Iterator, cast
> +
> +from scapy.layers.inet import IP, TCP, UDP
> +from scapy.layers.inet6 import IPv6
> +from scapy.layers.l2 import Dot1Q, Ether
> +from scapy.packet import Packet, Raw
> +
> +from framework.exception import InteractiveCommandExecutionError
> +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
> +
> +
> +@requires(NicCapability.FLOW_CTRL)
> +class TestRteFlow(TestSuite):
> + """RTE Flow test suite.
> +
> + This suite consists of 12 test cases:
> + 1. Queue Action Ethernet: Verifies queue actions with ethernet
> patterns
> + 2. Queue Action IP: Verifies queue actions with IPv4 and IPv6 patterns
> + 3. Queue Action L4: Verifies queue actions with TCP and UDP patterns
> + 4. Queue Action VLAN: Verifies queue actions with VLAN patterns
> + 5. Drop Action Eth: Verifies drop action with ethernet patterns
> + 6. Drop Action IP: Verifies drop actions with IPV4 and IPv6 patterns
> + 7. Drop Action L4: Verifies drop actions with TCP and UDP patterns
> + 8. Drop Action VLAN: Verifies drop actions with VLAN patterns
> + 9. Modify Field Action: Verifies packet modification patterns
> + 10. Egress Rules: Verifies previously covered rules are still valid
> as egress
> + 11. Jump Action: Verifies packet behavior given grouped flows
> + 12. Priority Attribute: Verifies packet behavior given flows with
> different priorities
> +
> + """
> +
> + def runner(
> + self,
> + verification_method: Callable[..., Any],
> + flows: list[FlowRule],
> + packets: list[Packet],
> + port_id: int,
> + expected_packets: list[Packet] | None = None,
> + *args: Any,
> + **kwargs: Any,
> + ) -> None:
> + """Runner method that validates each flow using the corresponding
> verification method.
> +
> + Args:
> + verification_method: Callable that performs verification
> logic.
> + flows: List of flow rules to create and test.
> + packets: List of packets corresponding to each flow.
> + port_id: Number representing the port to create flows on.
> + expected_packets: List of packets to check sent packets
> against in modification cases.
> + *args: Additional positional arguments to pass to the
> verification method.
> + **kwargs: Additional keyword arguments to pass to the
> verification method.
> + """
> +
> + def zip_lists(
> + rules: list[FlowRule],
> + packets1: list[Packet],
> + packets2: list[Packet] | None,
> + ) -> Iterator[tuple[FlowRule, Packet, Packet | None]]:
> + """Method that creates an iterable zip containing lists used
> in runner.
> +
> + Args:
> + rules: List of flow rules.
> + packets1: List of packets.
> + packets2: Optional list of packets, excluded from zip if
> not passed to runner.
> + """
> + return cast(
> + Iterator[tuple[FlowRule, Packet, Packet | None]],
> + zip_longest(rules, packets1, packets2 or [],
> fillvalue=None),
> + )
> +
> + with TestPmdShell(rx_queues=4, tx_queues=4) as testpmd:
> + for flow, packet, expected_packet in zip_lists(flows,
> packets, expected_packets):
> + is_valid = testpmd.flow_validate(flow_rule=flow,
> port_id=port_id)
> + self.verify_else_skip(is_valid, "flow rule failed
> validation.")
> +
> + try:
> + flow_id = testpmd.flow_create(flow_rule=flow,
> port_id=port_id)
> + except InteractiveCommandExecutionError:
> + self.log("Flow rule validation passed, but flow
> creation failed.")
> + self.verify(False, "Failed flow creation")
> +
> + if verification_method == self.send_packet_and_verify:
> + verification_method(packet=packet, *args, **kwargs)
> +
> + elif verification_method ==
> self.send_packet_and_verify_queue:
> + verification_method(
> + packet=packet, test_queue=kwargs["test_queue"],
> testpmd=testpmd
> + )
> +
> + elif verification_method ==
> self.send_packet_and_verify_modification:
> + verification_method(packet=packet,
> expected_packet=expected_packet)
> +
> + testpmd.flow_delete(flow_id, port_id=port_id)
> +
> + def send_packet_and_verify(self, packet: Packet, should_receive: bool
> = True) -> None:
> + """Generate a packet, send to the DUT, and verify it is forwarded
> back.
> +
> + Args:
> + packet: Scapy packet to send and verify.
> + should_receive: Indicate whether the packet should be
> received.
> + """
> + 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 send_packet_and_verify_queue(
> + self, packet: Packet, test_queue: int, testpmd: TestPmdShell
> + ) -> None:
> + """Send packet and verify queue stats show packet was received.
> +
> + Args:
> + packet: Scapy packet to send to the SUT.
> + test_queue: Represents the queue the test packet is being
> sent to.
> + testpmd: TestPmdShell instance being used to send test packet.
> + """
> + testpmd.set_verbose(level=8)
> + testpmd.start()
> + self.send_packet_and_capture(packet=packet)
> + verbose_output = testpmd.extract_verbose_output(testpmd.stop())
> + received = False
> + for testpmd_packet in verbose_output:
> + if testpmd_packet.queue_id == test_queue:
> + received = True
> + self.verify(received, f"Expected packet was not received on queue
> {test_queue}")
> +
> + def send_packet_and_verify_modification(self, packet: Packet,
> expected_packet: Packet) -> None:
> + """Send packet and verify the expected modifications are present
> upon reception.
> +
> + Args:
> + packet: Scapy packet to send to the SUT.
> + expected_packet: Scapy packet that should match the received
> packet.
> + """
> + received = self.send_packet_and_capture(packet)
> +
> + # verify reception
> + self.verify(received != [], "Packet was never received.")
> +
> + self.log(f"SENT PACKET: {packet.summary()}")
> + self.log(f"EXPECTED PACKET: {expected_packet.summary()}")
> + for packet in received:
> + self.log(f"RECEIVED PACKET: {packet.summary()}")
> +
> + expected_ip_dst = expected_packet[IP].dst if IP in
> expected_packet else None
> + received_ip_dst = received[IP].dst if IP in received else None
> +
> + expected_mac_dst = expected_packet[Ether].dst if Ether in
> expected_packet else None
> + received_mac_dst = received[Ether].dst if Ether in received else
> None
> +
> + # verify modification
> + if expected_ip_dst is not None:
> + self.verify(
> + received_ip_dst == expected_ip_dst,
> + f"IPv4 dst mismatch: expected {expected_ip_dst}, got
> {received_ip_dst}",
> + )
> +
> + if expected_mac_dst is not None:
> + self.verify(
> + received_mac_dst == expected_mac_dst,
> + f"MAC dst mismatch: expected {expected_mac_dst}, got
> {received_mac_dst}",
> + )
> +
> + def send_packet_and_verify_jump(
> + self,
> + packets: list[Packet],
> + flow_rules: list[FlowRule],
> + test_queues: list[int],
> + testpmd: TestPmdShell,
> + ) -> None:
> + """Create a testpmd session with every rule in the given list,
> verify jump behavior.
> +
> + Args:
> + packets: List of packets to send.
> + flow_rules: List of flow rules to create in the same session.
> + test_queues: List of Rx queue IDs each packet should be
> received on.
> + testpmd: TestPmdShell instance to create flows on.
> + """
> + testpmd.set_verbose(level=8)
> + for flow in flow_rules:
> + is_valid = testpmd.flow_validate(flow_rule=flow, port_id=0)
> + self.verify_else_skip(is_valid, "flow rule failed
> validation.")
> +
> + try:
> + testpmd.flow_create(flow_rule=flow, port_id=0)
> + except InteractiveCommandExecutionError:
> + self.log("Flow validation passed, but flow creation
> failed.")
> + self.verify(False, "Failed flow creation")
> +
> + for packet, test_queue in zip(packets, test_queues):
> + testpmd.start()
> + self.send_packet_and_capture(packet=packet)
> + verbose_output =
> testpmd.extract_verbose_output(testpmd.stop())
> + received = False
> + for testpmd_packet in verbose_output:
> + if testpmd_packet.queue_id == test_queue:
> + received = True
> + self.verify(received, f"Expected packet was not received on
> queue {test_queue}")
> +
> + @func_test
> + def test_queue_action_ETH(self) -> None:
> + """Validate flow rules with queue actions and ethernet patterns.
> +
> + Steps:
> + Create a list of packets to test, with a corresponding flow
> list.
> + Launch testpmd.
> + Create first flow rule in flow list.
> + Send first packet in packet list, capture verbose output.
> + Delete flow rule, repeat for all flows/packets.
> +
> + Verify:
> + Check that each packet is received on the appropriate queue.
> + """
> + packet_list = [
> + Ether(src="02:00:00:00:00:00"),
> + Ether(dst="02:00:00:00:00:00"),
> + Ether(type=0x0800) / IP(),
> + ]
> + flow_list = [
> + FlowRule(
> + direction="ingress",
> + pattern=["eth src is 02:00:00:00:00:00"],
> + actions=["queue index 2"],
> + ),
> + FlowRule(
> + direction="ingress",
> + pattern=["eth dst is 02:00:00:00:00:00"],
> + actions=["queue index 2"],
> + ),
> + FlowRule(
> + direction="ingress", pattern=["eth type is 0x0800"],
> actions=["queue index 2"]
> + ),
> + ]
> + self.runner(
> + verification_method=self.send_packet_and_verify_queue,
> + flows=flow_list,
> + packets=packet_list,
> + port_id=0,
> + test_queue=2,
> + )
> +
> + @func_test
> + def test_queue_action_IP(self) -> None:
> + """Validate flow rules with queue actions and IPv4/IPv6 patterns.
> +
> + Steps:
> + Create a list of packets to test, with a corresponding flow
> list.
> + Launch testpmd.
> + Create first flow rule in flow list.
> + Send first packet in packet list, capture verbose output.
> + Delete flow rule, repeat for all flows/packets.
> +
> + Verify:
> + Check that each packet is received on the appropriate queue.
> + """
> + packet_list = [
> + Ether() / IP(src="192.168.1.1"),
> + Ether() / IP(dst="192.168.1.1"),
> + Ether() / IP(ttl=64),
> + Ether() / IPv6(src="2001:db8::1"),
> + Ether() / IPv6(dst="2001:db8::2"),
> + Ether() / IPv6() / UDP(),
> + ]
> + flow_list = [
> + FlowRule(
> + direction="ingress",
> + pattern=["eth / ipv4 src is 192.168.1.1"],
> + actions=["queue index 2"],
> + ),
> + FlowRule(
> + direction="ingress",
> + pattern=["eth / ipv4 dst is 192.168.1.1"],
> + actions=["queue index 2"],
> + ),
> + FlowRule(
> + direction="ingress", pattern=["eth / ipv4 ttl is 64"],
> actions=["queue index 2"]
> + ),
> + FlowRule(
> + direction="ingress",
> + pattern=["eth / ipv6 src is 2001:db8::1"],
> + actions=["queue index 2"],
> + ),
> + FlowRule(
> + direction="ingress",
> + pattern=["eth / ipv6 dst is 2001:db8::2"],
> + actions=["queue index 2"],
> + ),
> + FlowRule(
> + direction="ingress", pattern=["eth / ipv6 proto is 17"],
> actions=["queue index 2"]
> + ),
> + ]
> + self.runner(
> + verification_method=self.send_packet_and_verify_queue,
> + flows=flow_list,
> + packets=packet_list,
> + port_id=0,
> + test_queue=2,
> + )
> +
> + @func_test
> + def test_queue_action_L4(self) -> None:
> + """Validate flow rules with queue actions and TCP/UDP patterns.
> +
> + Steps:
> + Create a list of packets to test, with a corresponding flow
> list.
> + Launch testpmd.
> + Create first flow rule in flow list.
> + Send first packet in packet list, capture verbose output.
> + Delete flow rule, repeat for all flows/packets.
> +
> + Verify:
> + Check that each packet is received on the appropriate queue.
> + """
> + packet_list = [
> + Ether() / IP() / TCP(sport=1234),
> + Ether() / IP() / TCP(dport=80),
> + Ether() / IP() / TCP(flags=0x02),
> + Ether() / IP() / UDP(sport=5000),
> + Ether() / IP() / UDP(dport=53),
> + ]
> + flow_list = [
> + FlowRule(
> + direction="ingress",
> + pattern=["eth / ipv4 / tcp src is 1234"],
> + actions=["queue index 2"],
> + ),
> + FlowRule(
> + direction="ingress",
> + pattern=["eth / ipv4 / tcp dst is 80"],
> + actions=["queue index 2"],
> + ),
> + FlowRule(
> + direction="ingress",
> + pattern=["eth / ipv4 / tcp flags is 0x02"],
> + actions=["queue index 2"],
> + ),
> + FlowRule(
> + direction="ingress",
> + pattern=["eth / ipv4 / udp src is 5000"],
> + actions=["queue index 2"],
> + ),
> + FlowRule(
> + direction="ingress",
> + pattern=["eth / ipv4 / udp dst is 53"],
> + actions=["queue index 2"],
> + ),
> + ]
> + self.runner(
> + verification_method=self.send_packet_and_verify_queue,
> + flows=flow_list,
> + packets=packet_list,
> + port_id=0,
> + test_queue=2,
> + )
> +
> + @func_test
> + def test_queue_action_VLAN(self) -> None:
> + """Validate flow rules with queue actions and VLAN patterns.
> +
> + Steps:
> + Create a list of packets to test, with a corresponding flow
> list.
> + Launch testpmd.
> + Create first flow rule in flow list.
> + Send first packet in packet list, capture verbose output.
> + Delete flow rule, repeat for all flows/packets.
> +
> + Verify:
> + Check that each packet is received on the appropriate queue.
> + """
> + packet_list = [Ether() / Dot1Q(vlan=100), Ether() /
> Dot1Q(type=0x0800)]
> + flow_list = [
> + FlowRule(direction="ingress", pattern=["eth / vlan"],
> actions=["queue index 2"]),
> + FlowRule(direction="ingress", pattern=["eth / vlan"],
> actions=["queue index 2"]),
> + ]
> + self.runner(
> + verification_method=self.send_packet_and_verify_queue,
> + flows=flow_list,
> + packets=packet_list,
> + port_id=0,
> + test_queue=2,
> + )
> +
> + @func_test
> + def test_drop_action_ETH(self) -> None:
> + """Validate flow rules with drop actions and ethernet patterns.
> +
> + Steps:
> + Create a list of packets to test, with a corresponding flow
> list.
> + Launch testpmd.
> + Create first flow rule in flow list.
> + Send first packet in packet list, capture verbose output.
> + Delete flow rule, repeat for all flows/packets.
> +
> + Verify:
> + Check that each packet is dropped.
> +
> + One packet will be sent as a confidence check, to ensure packets
> are being
> + received under normal circumstances.
> + """
> + packet_list = [
> + Ether(src="02:00:00:00:00:00") / Raw(load="xxxxx"),
> + Ether(dst="02:00:00:00:00:00") / Raw(load="xxxxx"),
> + Ether(type=0x0800) / Raw(load="xxxxx"),
> + ]
> + flow_list = [
> + FlowRule(
> + direction="ingress", pattern=["eth src is
> 02:00:00:00:00:00"], actions=["drop"]
> + ),
> + FlowRule(
> + direction="ingress", pattern=["eth dst is
> 02:00:00:00:00:00"], actions=["drop"]
> + ),
> + FlowRule(direction="ingress", pattern=["eth type is 0x0800"],
> actions=["drop"]),
> + ]
> + # verify reception with test packet
> + packet = Ether() / IP() / Raw(load="xxxxx")
> + with TestPmdShell() as testpmd:
> + testpmd.start()
> + received = self.send_packet_and_capture(packet)
> + self.verify(received != [], "Test packet was never received.")
> + self.runner(
> + verification_method=self.send_packet_and_verify,
> + flows=flow_list,
> + packets=packet_list,
> + port_id=0,
> + should_receive=False,
> + )
> +
> + @func_test
> + def test_drop_action_IP(self) -> None:
> + """Validate flow rules with drop actions and ethernet patterns.
> +
> + Steps:
> + Create a list of packets to test, with a corresponding flow
> list.
> + Launch testpmd.
> + Create first flow rule in flow list.
> + Send first packet in packet list, capture verbose output.
> + Delete flow rule, repeat for all flows/packets.
> +
> + Verify:
> + Check that each packet is dropped.
> +
> + One packet will be sent as a confidence check, to ensure packets
> are being
> + received under normal circumstances.
> + """
> + packet_list = [
> + Ether() / IP(src="192.168.1.1") / Raw(load="xxxxx"),
> + Ether() / IP(dst="192.168.1.1") / Raw(load="xxxxx"),
> + Ether() / IP(ttl=64) / Raw(load="xxxxx"),
> + Ether() / IPv6(src="2001:db8::1") / Raw(load="xxxxx"),
> + Ether() / IPv6(dst="2001:db8::1") / Raw(load="xxxxx"),
> + Ether() / IPv6() / UDP() / Raw(load="xxxxx"),
> + ]
> + flow_list = [
> + FlowRule(
> + direction="ingress", pattern=["eth / ipv4 src is
> 192.168.1.1"], actions=["drop"]
> + ),
> + FlowRule(
> + direction="ingress", pattern=["eth / ipv4 dst is
> 192.168.1.1"], actions=["drop"]
> + ),
> + FlowRule(direction="ingress", pattern=["eth / ipv4 ttl is
> 64"], actions=["drop"]),
> + FlowRule(
> + direction="ingress", pattern=["eth / ipv6 src is
> 2001:db8::1"], actions=["drop"]
> + ),
> + FlowRule(
> + direction="ingress", pattern=["eth / ipv6 dst is
> 2001:db8::2"], actions=["drop"]
> + ),
> + FlowRule(direction="ingress", pattern=["eth / ipv6 proto is
> 17"], actions=["drop"]),
> + ]
> + # verify reception with test packet
> + packet = Ether() / IP() / Raw(load="xxxxx")
> + with TestPmdShell() as testpmd:
> + testpmd.start()
> + received = self.send_packet_and_capture(packet)
> + self.verify(received != [], "Test packet was never received.")
> + self.runner(
> + verification_method=self.send_packet_and_verify,
> + flows=flow_list,
> + packets=packet_list,
> + port_id=0,
> + should_receive=False,
> + )
> +
> + @func_test
> + def test_drop_action_L4(self) -> None:
> + """Validate flow rules with drop actions and ethernet patterns.
> +
> + Steps:
> + Create a list of packets to test, with a corresponding flow
> list.
> + Launch testpmd.
> + Create first flow rule in flow list.
> + Send first packet in packet list, capture verbose output.
> + Delete flow rule, repeat for all flows/packets.
> +
> + Verify:
> + Check that each packet is dropped.
> +
> + One packet will be sent as a confidence check, to ensure packets
> are being
> + received under normal circumstances.
> + """
> + packet_list = [
> + Ether() / IP() / TCP(sport=1234) / Raw(load="xxxxx"),
> + Ether() / IP() / TCP(dport=80) / Raw(load="xxxxx"),
> + Ether() / IP() / TCP(flags=0x02) / Raw(load="xxxxx"),
> + Ether() / IP() / UDP(sport=5000) / Raw(load="xxxxx"),
> + Ether() / IP() / UDP(dport=53) / Raw(load="xxxxx"),
> + ]
> + flow_list = [
> + FlowRule(
> + direction="ingress", pattern=["eth / ipv4 / tcp src is
> 1234"], actions=["drop"]
> + ),
> + FlowRule(direction="ingress", pattern=["eth / ipv4 / tcp dst
> is 80"], actions=["drop"]),
> + FlowRule(
> + direction="ingress", pattern=["eth / ipv4 / tcp flags is
> 0x02"], actions=["drop"]
> + ),
> + FlowRule(
> + direction="ingress", pattern=["eth / ipv4 / udp src is
> 5000"], actions=["drop"]
> + ),
> + FlowRule(direction="ingress", pattern=["eth / ipv4 / udp dst
> is 53"], actions=["drop"]),
> + ]
> + # verify reception with test packet
> + packet = Ether() / IP() / Raw(load="xxxxx")
> + with TestPmdShell() as testpmd:
> + testpmd.start()
> + received = self.send_packet_and_capture(packet)
> + self.verify(received != [], "Test packet was never received.")
> + self.runner(
> + verification_method=self.send_packet_and_verify,
> + flows=flow_list,
> + packets=packet_list,
> + port_id=0,
> + should_receive=False,
> + )
> +
> + @func_test
> + def test_drop_action_VLAN(self) -> None:
> + """Validate flow rules with drop actions and ethernet patterns.
> +
> + Steps:
> + Create a list of packets to test, with a corresponding flow
> list.
> + Launch testpmd.
> + Create first flow rule in flow list.
> + Send first packet in packet list, capture verbose output.
> + Delete flow rule, repeat for all flows/packets.
> +
> + Verify:
> + Check that each packet is dropped.
> +
> + One packet will be sent as a confidence check, to ensure packets
> are being
> + received under normal circumstances.
> + """
> + packet_list = [
> + Ether() / Dot1Q(vlan=100) / Raw(load="xxxxx"),
> + Ether() / Dot1Q(type=0x0800) / Raw(load="xxxxx"),
> + ]
> + flow_list = [
> + FlowRule(direction="ingress", pattern=["eth / vlan"],
> actions=["drop"]),
> + FlowRule(direction="ingress", pattern=["eth / vlan"],
> actions=["drop"]),
> + ]
> + # verify reception with test packet
> + packet = Ether() / IP() / Raw(load="xxxxx")
> + with TestPmdShell() as testpmd:
> + testpmd.start()
> + received = self.send_packet_and_capture(packet)
> + self.verify(received != [], "Test packet was never received.")
> + self.runner(
> + verification_method=self.send_packet_and_verify,
> + flows=flow_list,
> + packets=packet_list,
> + port_id=0,
> + should_receive=False,
> + )
> +
> + @func_test
> + def test_modify_actions(self) -> None:
> + """Validate flow rules with actions that modify that packet
> during transmission.
> +
> + Steps:
> + Create a list of packets to test, with a corresponding flow
> list.
> + Launch testpmd.
> + Create first flow rule in flow list.
> + Send first packet in packet list, capture verbose output.
> + Delete flow rule, repeat for all flows/packets.
> +
> + Verify:
> + Verify packet is received with the new attributes.
> + """
> + packet_list = [Ether() / IP(src="192.68.1.1"),
> Ether(src="02:00:00:00:00:00")]
> + flow_list = [
> + # rule to copy IPv4 src to IPv4 dst
> + FlowRule(
> + direction="ingress",
> + group_id=1,
> + pattern=["eth"],
> + actions=[
> + "modify_field op set dst_type ipv4_dst src_type
> ipv4_src width 32"
> + " / queue index 0"
> + ],
> + ),
> + # rule to copy src MAC to dst MAC
> + FlowRule(
> + direction="ingress",
> + group_id=1,
> + pattern=["eth"],
> + actions=[
> + "modify_field op set dst_type mac_dst src_type
> mac_src width 48 / queue index 0"
> + ],
> + ),
> + ]
> + expected_packet_list = [Ether() / IP(dst="192.68.1.1"),
> Ether(dst="02:00:00:00:00:00")]
> + self.runner(
> + verification_method=self.send_packet_and_verify_modification,
> + flows=flow_list,
> + packets=packet_list,
> + port_id=0,
> + expected_packets=expected_packet_list,
> + )
> +
> + @func_test
> + def test_egress_rules(self) -> None:
> + """Validate flow rules with egress directions.
> +
> + Steps:
> + Create a list of packets to test, with a corresponding flow
> list.
> + Launch testpmd.
> + Create first flow rule in flow list.
> + Send first packet in packet list, capture verbose output.
> + Delete flow rule, repeat for all flows/packets.
> +
> + Verify:
> + Check that each packet is dropped.
> +
> + One packet will be sent as a confidence check, to ensure packets
> are being
> + received under normal circumstances.
> + """
> + packet_list = [
> + Ether(src="02:00:00:00:00:00"),
> + Ether() / IP(src="192.168.1.1"),
> + IP() / TCP(sport=1234),
> + IP() / UDP(sport=5000),
> + ]
> + flow_list = [
> + FlowRule(
> + direction="egress", pattern=["eth src is
> 02:00:00:00:00:00"], actions=["drop"]
> + ),
> + FlowRule(direction="egress", pattern=["ipv4 src is
> 192.168.1.1"], actions=["drop"]),
> + FlowRule(direction="egress", pattern=["tcp src is 1234"],
> actions=["drop"]),
> + FlowRule(direction="egress", pattern=["udp src is 5000"],
> actions=["drop"]),
> + ]
> + # verify reception with test packet
> + packet = Ether() / IP() / Raw(load="xxxxx")
> + with TestPmdShell() as testpmd:
> + testpmd.start()
> + received = self.send_packet_and_capture(packet)
> + self.verify(received != [], "Test packet was never received.")
> + self.runner(
> + verification_method=self.send_packet_and_verify,
> + flows=flow_list,
> + packets=packet_list,
> + port_id=1,
> + should_receive=False,
> + )
> +
> + @func_test
> + def test_jump_action(self) -> None:
> + """Validate flow rules with different group levels and jump
> actions.
> +
> + Steps:
> + Create a list of packets to test, with a corresponding flow
> list.
> + Launch testpmd with the necessary configuration.
> + Create each flow rule in testpmd.
> + Send each packet in the list, check Rx queue ID.
> +
> + Verify:
> + Check that each packet is received on the appropriate Rx
> queue.
> + """
> + packet_list = [Ether() / IP(), Ether() / IP() / TCP(), Ether() /
> IP() / UDP()]
> + flow_list = [
> + FlowRule(
> + direction="ingress",
> + group_id=0,
> + pattern=["eth / ipv4 / tcp"],
> + actions=["jump group 1"],
> + ),
> + FlowRule(
> + direction="ingress",
> + group_id=0,
> + pattern=["eth / ipv4 / udp"],
> + actions=["jump group 2"],
> + ),
> + FlowRule(
> + direction="ingress",
> + group_id=1,
> + pattern=["eth / ipv4 / tcp"],
> + actions=["queue index 2"],
> + ),
> + FlowRule(
> + direction="ingress",
> + group_id=2,
> + pattern=["eth / ipv4 / udp"],
> + actions=["queue index 3"],
> + ),
> + FlowRule(
> + direction="ingress",
> + group_id=0,
> + pattern=["eth / ipv4"],
> + actions=["queue index 1"],
> + ),
> + ]
> + expected_queue_list = [1, 2, 3]
> + with TestPmdShell(rx_queues=4, tx_queues=4) as testpmd:
> + self.send_packet_and_verify_jump(
> + packets=packet_list,
> + flow_rules=flow_list,
> + test_queues=expected_queue_list,
> + testpmd=testpmd,
> + )
> +
> + @func_test
> + def test_priority_attribute(self) -> None:
> + """Validate flow rules with queue actions and ethernet patterns.
> +
> + Steps:
> + Create a list of packets to test, with a corresponding flow
> list.
> + Launch testpmd.
> + Create first flow rule in flow list.
> + Send first packet in packet list, capture verbose output.
> + Delete flow rule, repeat for all flows/packets.
> +
> + Verify:
> + Check that each packet is received on the appropriate queue.
> + """
> + test_packet = Ether() / IP() / Raw()
> + flow_list = [
> + FlowRule(
> + direction="ingress",
> + priority_level=3,
> + pattern=["eth / ipv4"],
> + actions=["queue index 1"],
> + ),
> + FlowRule(
> + direction="ingress",
> + priority_level=2,
> + pattern=["eth / ipv4"],
> + actions=["queue index 2"],
> + ),
> + FlowRule(
> + direction="ingress",
> + priority_level=1,
> + pattern=["eth / ipv4"],
> + actions=["queue index 3"],
> + ),
> + ]
> + expected_queue_list = [1, 2, 3]
> + with TestPmdShell(rx_queues=4, tx_queues=4) as testpmd:
> + testpmd.set_verbose(level=8)
> + for flow, expected_queue in zip(flow_list,
> expected_queue_list):
> + is_valid = testpmd.flow_validate(flow_rule=flow,
> port_id=0)
> + self.verify_else_skip(is_valid, "flow rule failed
> validation.")
> + try:
> + testpmd.flow_create(flow_rule=flow, port_id=0)
> + except InteractiveCommandExecutionError:
> + self.log("Flow rule validation passed, but flow
> creation failed.")
> + self.verify(False, "Failed flow creation")
> + testpmd.start()
> + self.send_packet_and_capture(test_packet)
> + verbose_output =
> testpmd.extract_verbose_output(testpmd.stop())
> + received = False
> + for testpmd_packet in verbose_output:
> + if testpmd_packet.queue_id == expected_queue:
> + received = True
> + self.verify(received, f"Packet was not received on queue
> {expected_queue}")
> --
> 2.49.0
>
>
[-- Attachment #2: Type: text/html, Size: 44821 bytes --]
next prev parent reply other threads:[~2025-06-27 14:26 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-05-15 16:38 [RFC PATCH 0/1] " Dean Marx
2025-05-15 16:38 ` [RFC PATCH] dts: add " Dean Marx
2025-05-19 18:19 ` [PATCH v1 1/2] " Dean Marx
2025-05-19 18:19 ` [PATCH v1 2/2] dts: add jump and priority tests to flow suite Dean Marx
2025-05-21 19:26 ` [PATCH v2 1/3] dts: add rte flow test suite Dean Marx
2025-05-21 19:26 ` [PATCH v2 2/3] dts: add jump and priority tests to flow suite Dean Marx
2025-06-25 17:25 ` Patrick Robb
2025-05-21 19:26 ` [PATCH v2 3/3] dts: add flow validation Dean Marx
2025-06-25 17:38 ` Patrick Robb
2025-06-26 19:56 ` [PATCH v3 1/2] dts: add rte flow test suite Dean Marx
2025-06-26 19:56 ` [PATCH v3 2/2] dts: add flow validation Dean Marx
2025-06-27 4:29 ` Patrick Robb
2025-06-27 4:29 ` [PATCH v3 1/2] dts: add rte flow test suite Patrick Robb
2025-06-27 14:20 ` Patrick Robb [this message]
2025-06-27 14:46 ` Patrick Robb
2025-06-25 17:15 ` [PATCH v2 1/3] " Patrick Robb
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=CAJvnSUD91p_7DYge3PCy5J3CNPEX3fjy6DD7xLH7inWWHRkCEQ@mail.gmail.com \
--to=probb@iol.unh.edu \
--cc=Honnappa.Nagarahalli@arm.com \
--cc=dev@dpdk.org \
--cc=dmarx@iol.unh.edu \
--cc=luca.vizzarro@arm.com \
--cc=paul.szczepanek@arm.com \
--cc=thomas@monjalon.net \
--cc=yoan.picchi@foss.arm.com \
/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).