I will test this tonight. What do we have right now in terms of DTS dev systems and NICs for non-iol people like me. Is it still:
iol-dts-tester And iol-dts-dut With mlnx cx5 and intel xl710? Just checking in. On Tue, Aug 11, 2026 at 1:04 PM Andrew Bailey <[email protected]> wrote: > Refactor current flow test suite to utilize a generator > method, which dynamically creates flow rules from a > dictionary of pattern and action fields during runtime. > This allows for much more extensive testing of the flow > API without exponential code growth. > > Signed-off-by: Andrew Bailey <[email protected]> > Signed-off-by: Dean Marx <[email protected]> > Reviewed-by: Patrick Robb <[email protected]> > --- > > v7: > * Resolve merge conflicts. > dts/tests/TestSuite_flow_offload.py | 206 ++++++++++++++++++++++++---- > 1 file changed, 182 insertions(+), 24 deletions(-) > > diff --git a/dts/tests/TestSuite_flow_offload.py > b/dts/tests/TestSuite_flow_offload.py > index be11d09875..d1a6c2fa74 100644 > --- a/dts/tests/TestSuite_flow_offload.py > +++ b/dts/tests/TestSuite_flow_offload.py > @@ -1,7 +1,7 @@ > # SPDX-License-Identifier: BSD-3-Clause > # Copyright(c) 2025 University of New Hampshire > > -"""RTE Flow testing suite. > +"""Flow offload 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 > @@ -10,7 +10,7 @@ > > """ > > -from dataclasses import dataclass > +from dataclasses import dataclass, field > from itertools import product > from typing import Any, Callable, Optional > > @@ -18,6 +18,7 @@ > from scapy.layers.inet6 import IPv6 > from scapy.layers.l2 import ARP, Dot1Q, Ether > from scapy.layers.sctp import SCTP > +from scapy.layers.vxlan import VXLAN > from scapy.packet import Packet, Raw > > from api.capabilities import NicCapability, requires_nic_capability > @@ -50,10 +51,16 @@ class Protocol: > scapy_class: type[Packet] > pattern_name: str > fields: list[PatternField] > + default_values: dict[str, Any] = field(default_factory=dict) > > def build_scapy_layer(self, field_values: dict[str, Any]) -> Packet: > - """Construct a Scapy layer with the given field values.""" > - return self.scapy_class(**field_values) > + """Construct a Scapy layer with the given field values. > + > + Default values are applied first, then overridden by any > + explicit field values so test parameters always win. > + """ > + merged = {**self.default_values, **field_values} > + return self.scapy_class(**merged) > > > @dataclass > @@ -125,6 +132,7 @@ class JumpTest: > > > PROTOCOLS: dict[str, Protocol] = { > + # -------------------- Base Protocols -------------------- > "eth": Protocol( > name="eth", > scapy_class=Ether, > @@ -215,6 +223,89 @@ class JumpTest: > PatternField("op", "opcode", [1, 2]), > ], > ), > + # -------------------- VXLAN Outer Protocols -------------------- > + "eth_outer": Protocol( > + name="eth_outer", > + scapy_class=Ether, > + pattern_name="eth", > + fields=[ > + PatternField("src", "src", ["02:00:00:00:00:00"]), > + PatternField("dst", "dst", ["02:00:00:00:00:02"]), > + ], > + ), > + "ipv4_outer": Protocol( > + name="ipv4_outer", > + scapy_class=IP, > + pattern_name="ipv4", > + fields=[ > + PatternField("src", "src", ["10.0.0.1"]), > + PatternField("dst", "dst", ["10.0.0.2"]), > + PatternField("ttl", "ttl", [64, 128]), > + PatternField("tos", "tos", [0, 4]), > + ], > + ), > + "udp_outer": Protocol( > + name="udp_outer", > + scapy_class=UDP, > + pattern_name="udp", > + fields=[], > + default_values={"dport": 4789}, > + ), > + # -------------------- VXLAN Tunnel Header -------------------- > + "vxlan": Protocol( > + name="vxlan", > + scapy_class=VXLAN, > + pattern_name="vxlan", > + fields=[ > + PatternField("vni", "vni", [42, 100]), > + ], > + ), > + # -------------------- VXLAN Inner Protocols -------------------- > + "eth_inner": Protocol( > + name="eth_inner", > + scapy_class=Ether, > + pattern_name="eth", > + fields=[ > + PatternField("src", "src", ["02:00:00:00:00:00"]), > + PatternField("dst", "dst", ["02:00:00:00:00:02"]), > + ], > + ), > + "ipv4_inner": Protocol( > + name="ipv4_inner", > + scapy_class=IP, > + pattern_name="ipv4", > + fields=[ > + PatternField("src", "src", ["192.168.1.1"]), > + PatternField("dst", "dst", ["192.168.1.2"]), > + ], > + ), > + "ipv6_inner": Protocol( > + name="ipv6_inner", > + scapy_class=IPv6, > + pattern_name="ipv6", > + fields=[ > + PatternField("src", "src", ["2001:db8::1"]), > + PatternField("dst", "dst", ["2001:db8::2"]), > + ], > + ), > + "tcp_inner": Protocol( > + name="tcp_inner", > + scapy_class=TCP, > + pattern_name="tcp", > + fields=[ > + PatternField("sport", "src", [1234]), > + PatternField("dport", "dst", [80]), > + ], > + ), > + "udp_inner": Protocol( > + name="udp_inner", > + scapy_class=UDP, > + pattern_name="udp", > + fields=[ > + PatternField("sport", "src", [5000]), > + PatternField("dport", "dst", [53]), > + ], > + ), > } > > > @@ -234,6 +325,7 @@ class JumpTest: > } > > PROTOCOL_STACKS = [ > + # -------------------- Non-tunnel stacks -------------------- > [("eth", True)], > [("eth", False), ("ipv4", True)], > [("eth", False), ("ipv4", True), ("tcp", True)], > @@ -253,6 +345,66 @@ class JumpTest: > [("eth", False), ("vlan", False), ("ipv6", True), ("tcp", True)], > [("eth", False), ("vlan", False), ("ipv6", True), ("udp", True)], > [("eth", False), ("arp", True)], > + # -------------------- VXLAN tunnel stacks -------------------- > + [ > + ("eth_outer", False), > + ("ipv4_outer", True), > + ("udp_outer", False), > + ("vxlan", True), > + ("eth_inner", False), > + ("ipv4_inner", False), > + ], > + [ > + ("eth_outer", False), > + ("ipv4_outer", True), > + ("udp_outer", False), > + ("vxlan", True), > + ("eth_inner", False), > + ("ipv4_inner", False), > + ("tcp_inner", False), > + ], > + [ > + ("eth_outer", False), > + ("ipv4_outer", True), > + ("udp_outer", False), > + ("vxlan", True), > + ("eth_inner", False), > + ("ipv4_inner", False), > + ("udp_inner", False), > + ], > + [ > + ("eth_outer", False), > + ("ipv4_outer", True), > + ("udp_outer", False), > + ("vxlan", True), > + ("eth_inner", False), > + ("ipv6_inner", False), > + ], > + [ > + ("eth_outer", False), > + ("ipv4_outer", True), > + ("udp_outer", False), > + ("vxlan", True), > + ("eth_inner", False), > + ("ipv6_inner", False), > + ("tcp_inner", False), > + ], > + [ > + ("eth_outer", False), > + ("ipv4_outer", True), > + ("udp_outer", False), > + ("vxlan", True), > + ("eth_inner", False), > + ("ipv6_inner", False), > + ("udp_inner", False), > + ], > + [ > + ("eth_outer", False), > + ("ipv4_outer", True), > + ("udp_outer", False), > + ("vxlan", True), > + ("eth_inner", False), > + ], > ] > > > @@ -304,6 +456,10 @@ def generate( > ) -> list[FlowTest]: > """Generate test cases for patterns matching fields across > multiple protocols. > > + Pattern parts are assembled in stack order to preserve positional > + correctness, which is required for tunnel encapsulations where > + inner and outer layers share the same pattern_name. > + > Args: > protocol_stack: List of (protocol_name, test_fields) tuples. > If test_fields is True, iterate through field > combinations. > @@ -316,15 +472,12 @@ def generate( > List of FlowTest objects ready for execution. > """ > action_spec = self.actions[action_name] > - > - wildcard_protocols = [name for name, test_fields in > protocol_stack if not test_fields] > - field_test_protocols = [name for name, test_fields in > protocol_stack if test_fields] > all_protocol_names = [name for name, _ in protocol_stack] > - > - wildcard_pattern_parts = [self.protocols[name].pattern_name for > name in wildcard_protocols] > + field_test_protocols = [name for name, test_fields in > protocol_stack if test_fields] > > if not field_test_protocols: > - pattern = " / ".join(wildcard_pattern_parts) > + pattern_parts = [self.protocols[name].pattern_name for name, > _ in protocol_stack] > + pattern = " / ".join(pattern_parts) > flow_rule = FlowRule( > direction="ingress", > pattern=[pattern], > @@ -339,7 +492,7 @@ def generate( > packet=packet, > verification_type=action_spec.verification_type, > > verification_params=action_spec.build_verification_params(action_value), > - description=" / ".join(wildcard_pattern_parts) + f" > -> {action_spec.name}", > + description=pattern + f" -> {action_spec.name}", > ) > ] > > @@ -354,24 +507,32 @@ def generate( > max_vals = max(len(f_spec.test_parameters) for _, f_spec in > field_combo) > > for i in range(max_vals): > - field_pattern_parts = [] > + field_value_map: dict[str, tuple[Protocol, PatternField, > Any]] = {} > all_field_values: dict[str, dict[str, Any]] = {} > - desc_parts = [] > > for protocol_spec, field_spec in field_combo: > val = field_spec.test_parameters[i % > len(field_spec.test_parameters)] > - > - field_pattern_parts.append( > - f"{protocol_spec.pattern_name} > {field_spec.pattern_field} is {val}" > - ) > + field_value_map[protocol_spec.name] = > (protocol_spec, field_spec, val) > > if protocol_spec.name not in all_field_values: > all_field_values[protocol_spec.name] = {} > > all_field_values[protocol_spec.name][field_spec.scapy_field] > = val > > - desc_parts.append(f"{protocol_spec.name > }[{field_spec.scapy_field}={val}]") > + pattern_parts = [] > + desc_parts = [] > + > + for proto_name, test_fields in protocol_stack: > + proto_spec = self.protocols[proto_name] > + if test_fields and proto_name in field_value_map: > + _, f_spec, val = field_value_map[proto_name] > + pattern_parts.append( > + f"{proto_spec.pattern_name} > {f_spec.pattern_field} is {val}" > + ) > + desc_parts.append(f"{proto_spec.name > }[{f_spec.scapy_field}={val}]") > + else: > + pattern_parts.append(proto_spec.pattern_name) > > - full_pattern = " / ".join(wildcard_pattern_parts + > field_pattern_parts) > + full_pattern = " / ".join(pattern_parts) > > flow_rule = FlowRule( > direction="ingress", > @@ -384,10 +545,7 @@ def generate( > all_protocol_names, all_field_values, add_payload=True > ) > > - wildcard_desc = " / ".join(wildcard_pattern_parts) > - field_desc = " / ".join(desc_parts) > - full_desc = f"{wildcard_desc} / {field_desc}" if > wildcard_desc else field_desc > - > + full_desc = " / ".join(desc_parts) > test_cases.append( > FlowTest( > flow_rule=flow_rule, > @@ -403,7 +561,7 @@ def generate( > > @requires_nic_capability(NicCapability.FLOW_CTRL) > class TestFlowOffload(TestSuite): > - """Flow offload test suite. > + """Flow Offload test suite. > > This suite consists of 4 test cases: > 1. Queue Action: Verifies queue actions with multi-protocol patterns > -- > 2.55.0 > >

