test suite reviews and discussions
 help / color / mirror / Atom feed
From: "Tu, Lijuan" <lijuan.tu@intel.com>
To: Owen Hilyard <ohilyard@iol.unh.edu>,
	"dts@dpdk.org" <dts@dpdk.org>,
	"Ma, LihongX" <lihongx.ma@intel.com>
Cc: "lylavoie@iol.unh.edu" <lylavoie@iol.unh.edu>,
	"Chen, Zhaoyan" <zhaoyan.chen@intel.com>,
	"Peng, Yuan" <yuan.peng@intel.com>,
	"shall@iol.unh.edu" <shall@iol.unh.edu>
Subject: Re: [dts] [PATCH] rte flow: added test suite and framework
Date: Thu, 22 Oct 2020 08:53:24 +0000
Message-ID: <f010c65a87f64ff2821a7df093ed7d46@intel.com> (raw)
In-Reply-To: <20201014205051.16205-1-ohilyard@iol.unh.edu>

1, need to add copyright and license in each file.
2, too many files in a patch, please split it to serval patches, and make them a patch set. A large patch is really hard to review.
3, if fixed some issues of a patch, please send out V2 based on master, not a fixes based on V1.
4,  have you tested the patch, we haven't got change to test it. The implement seems ok for me.

> +    action_functions =
> create_test_function_strings(get_test_configs_for_actions())
> +    print("\n".join(action_functions))

Why use print, but not dts api: self.logger.info, is there a special reason?



> -----Original Message-----
> From: Owen Hilyard <ohilyard@iol.unh.edu>
> Sent: 2020年10月15日 4:51
> To: dts@dpdk.org; Ma, LihongX <lihongx.ma@intel.com>
> Cc: ohilyard@iol.unh.edu; lylavoie@iol.unh.edu; Chen, Zhaoyan
> <zhaoyan.chen@intel.com>; Peng, Yuan <yuan.peng@intel.com>; Tu, Lijuan
> <lijuan.tu@intel.com>; shall@iol.unh.edu
> Subject: [PATCH] rte flow: added test suite and framework
> 
> The framework for the rte flow can be found in framework/flow. The plan
> for this test suite was to design a type system and then use the
> constraints created by the type system to generate all possible flow
> rules within reason (addresses and ports would only use a few options).
> The type system was designed and then it was found that this produces
> 2,549,026 patterns without dealing with any of the spec attributes of
> the pattern items. If all possible actions were to be tested, this
> brought the number of required test cases up to
> 11,479,792,543,757,705,936,896. As such, this brute-force approach was
> abandoned. Attempts were made to restrict the type system enough to
> create a reasonable number of rules, but eventually it was found to be
> a much better use of developer time to write the rules by hand with the
> aid of some runtime code generation to create most of the pattern test,
> having them all use the queue action due to it's easy to detect presence
> when verbose logging is turned on.
> 
> The type system is part of this commit because it still provides a
> partial framework for creating flow rules, modeled after the way packets
> may be created with scapy.
> 
> Protocols which are supported by testpmd but are not supported in scapy
> were not tested due to the time requirements of creating protocol
> implimentations.
> 
> Signed-off-by: Owen Hilyard <ohilyard@iol.unh.edu>
> Signed-off-by: Sarah Hall <shall@iol.unh.edu>
> ---
>  framework/flow/__init__.py           |    0
>  framework/flow/enums.py              |   91 +
>  framework/flow/exceptions.py         |   12 +
>  framework/flow/flow.py               |  155 +
>  framework/flow/flow_action_items.py  | 1018 +++++++
>  framework/flow/flow_items.py         |   84 +
>  framework/flow/flow_pattern_items.py | 1076 +++++++
>  framework/flow/flow_rule.py          |   31 +
>  framework/flow/generator.py          |  155 +
>  test_plans/index.rst                 |    1 +
>  test_plans/rte_flow_test_plan.rst    | 4114 ++++++++++++++++++++++++++
>  test_plans/rte_flow_unsupported.rst  |  130 +
>  tests/TestSuite_rte_flow.py          |  232 ++
>  13 files changed, 7099 insertions(+)
>  create mode 100644 framework/flow/__init__.py
>  create mode 100644 framework/flow/enums.py
>  create mode 100644 framework/flow/exceptions.py
>  create mode 100644 framework/flow/flow.py
>  create mode 100644 framework/flow/flow_action_items.py
>  create mode 100644 framework/flow/flow_items.py
>  create mode 100644 framework/flow/flow_pattern_items.py
>  create mode 100644 framework/flow/flow_rule.py
>  create mode 100644 framework/flow/generator.py
>  create mode 100644 test_plans/rte_flow_test_plan.rst
>  create mode 100644 test_plans/rte_flow_unsupported.rst
>  create mode 100644 tests/TestSuite_rte_flow.py
> 
> diff --git a/framework/flow/__init__.py b/framework/flow/__init__.py
> new file mode 100644
> index 00000000..e69de29b
> diff --git a/framework/flow/enums.py b/framework/flow/enums.py
> new file mode 100644
> index 00000000..b4981f2b
> --- /dev/null
> +++ b/framework/flow/enums.py
> @@ -0,0 +1,91 @@
> +from enum import Enum
> +
> +
> +class FlowRuleType(Enum):
> +    INGRESS = "ingress"
> +    EGRESS = "egress"
> +    BOTH = ""
> +
> +
> +class FlowItemType(Enum):
> +    UDP = "udp"
> +    TCP = "tcp"
> +    SCTP = "sctp"
> +    IPV4 = "ipv4"
> +    IPV6 = "ipv6"
> +    END = "end"
> +    VOID = "void"
> +    INVERT = "invert"
> +    ANY = "any"
> +    RAW = "raw"
> +    ETH = "eth"
> +    VLAN = "vlan"
> +    VXLAN = "vxlan"
> +    GRE = "gre"
> +    VXLAN_GPE = "vxlan_gpe"
> +    ARP_ETH_IPV4 = "arp_eth_ipv4"
> +    ICMP = "icmp"
> +    ICMP6 = "icmp6"
> +    MARK = "mark"
> +    META = "meta"
> +    TAG = "tag"
> +    FUZZY = "fuzzy"
> +
> +
> +class FlowActionType(Enum):
> +    # "Simple" actions that don't need parameters
> +    VOID = "void"
> +    PASSTHRU = "passthru"
> +    FLAG = "flag"
> +    DROP = "drop"
> +    COUNT = "count"
> +    MAC_SWAP = "mac_swap"
> +    DEC_TTL = "dec_ttl"
> +
> +    # Actions that do need parameters
> +    JUMP = "jump"
> +    MARK = "mark"
> +    QUEUE = "queue"
> +    RSS = "rss"
> +    PF = "pf"
> +    VF = "vf"
> +    PHY_PORT = "phy_port"
> +    PORT_ID = "port_id"
> +    METER = "meter"
> +    SECURITY = "security"
> +    OF_SET_MPLS_TTL = "of_set_mpls_ttl"
> +    OF_DEC_MPLS_TTL = "of_dec_mpls_ttl"
> +    OF_SET_NW_TTL = "of_set_nw_ttl"
> +    OF_DEC_NW_TTL = "of_dec_nw_ttl"
> +    OF_COPY_TTL_OUT = "of_copy_ttl_out"
> +    OF_COPY_TTL_IN = "of_copy_ttl_in"
> +    OF_POP_VLAN = "of_pop_vlan"
> +    OF_PUSH_VLAN = "of_push_vlan"
> +    OF_SET_VLAN_VID = "of_set_vlan_vid"
> +    OF_SET_VLAN_PCP = "of_set_vlan_pcp"
> +    OF_POP_MPLS = "of_pop_mpls"
> +    OF_PUSH_MPLS = "of_push_mpls"
> +    VXLAN_ENCAP = "vxlan_encap"
> +    VXLAN_DECAP = "vxlan_decap"
> +    NVGRE_ENCAP = "nvgre_encap"
> +    NVGRE_DECAP = "nvgre_decap"
> +    RAW_ENCAP = "raw_encap"
> +    RAW_DECAP = "raw_decap"
> +    SET_IPV4_SRC = "set_ipv4_src"
> +    SET_IPV4_DST = "set_ipv4_dst"
> +    SET_IPV6_SRC = "set_ipv6_src"
> +    SET_IPV6_DST = "set_ipv6_dst"
> +    SET_TP_SRC = "set_tp_src"
> +    SET_TP_DST = "set_tp_dst"
> +    SET_TTL = "set_ttl"
> +    SET_MAC_SRC = "set_mac_src"
> +    SET_MAC_DST = "set_mac_dst"
> +    INC_TCP_SEQ = "inc_tcp_seq"
> +    DEC_TCP_SEQ = "dec_tcp_seq"
> +    INC_TCP_ACK = "inc_tcp_ack"
> +    DEC_TCP_ACK = "dec_tcp_ack"
> +    SET_TAG = "set_tag"
> +    SET_META = "set_meta"
> +    SET_IPV4_DSCP = "set_ipv4_dscp"
> +    SET_IPV6_DSCP = "set_ipv6_dscp"
> +    AGE = "age"
> diff --git a/framework/flow/exceptions.py b/framework/flow/exceptions.py
> new file mode 100644
> index 00000000..746b204f
> --- /dev/null
> +++ b/framework/flow/exceptions.py
> @@ -0,0 +1,12 @@
> +class CompositionException(Exception):
> +
> +    def __init__(self):
> +        self.message = "There was an unexpected error in composition"
> +
> +
> +class InvalidFlowItemException(CompositionException):
> +    def __init__(self, first_item, second_item, flow=None):
> +        if flow is not None:
> +            self.message = f'"{first_item}" was not able to accept "{second_item}"
> as the next item in flow {flow}.'
> +        else:
> +            self.message = f'"{first_item}" was not able to accept "{second_item}".'
> diff --git a/framework/flow/flow.py b/framework/flow/flow.py
> new file mode 100644
> index 00000000..3fa02e18
> --- /dev/null
> +++ b/framework/flow/flow.py
> @@ -0,0 +1,155 @@
> +# Items which may be used to start the protocol chain once actions have been
> used
> +from __future__ import annotations
> +
> +import copy
> +import itertools
> +import operator
> +from functools import reduce
> +from typing import List, FrozenSet, Union, Iterable, Tuple
> +
> +from scapy.layers.l2 import Ether
> +
> +from framework.flow.enums import FlowItemType, FlowActionType
> +from framework.flow.exceptions import InvalidFlowItemException
> +from framework.flow.flow_action_items import ActionFlowItem
> +from framework.flow.flow_items import FlowItem
> +from framework.flow.flow_pattern_items import PatternFlowItem,
> TUNNELING_PROTOCOLS
> +
> +# Get reserved mac addresses
> +NEVER_MATCH_PACKET = Ether(src="", dst="") / ('\x00' * 64)
> +
> +
> +def _iterable_deep_compare(i1, i2):
> +    return reduce(
> +        lambda x, y: x and y,
> +        map(lambda x, y: x == y, i1, i2),
> +        True
> +    )
> +
> +
> +def expand_pattern_list_with_iterable_replacing_item(patterns:
> List[Iterable[FlowItem]],
> +                                                     it: Iterable[Tuple[FlowItem, FrozenSet[str],
> FrozenSet[str], str]],
> +                                                     item):
> +    """
> +    This function takes a list of patterns and splits each of them into 2
> +    parts, excluding the item at index. It then uses the provided
> +    iterator to fill in that value for all patterns.
> +
> +    Ex:
> +    if patterns is [['a', 'b', 'c'], ['c','b','a']], it is [1,2], and item is 'b',
> +    then this function will produce
> +
> +    [['a', 1], ['a', 2], ['a', 1], ['a', 2], ['a', 1], ['a', 2]]
> +
> +    if everything is converted into a list. It is not converted
> +    because that requires using the memory to store all of this at
> +    the same time, which could be fairly large.
> +    """
> +
> +    split_patterns = list(map(lambda pattern: (pattern[:pattern.index(item)],
> pattern[pattern.index(item) + 1:],),
> +                              filter(lambda pattern: item in pattern, patterns)))
> +    # Tee the iterators so I can consume all of them
> +
> +    iterators = itertools.tee(it, len(patterns))
> +    for pattern_before, pattern_after in split_patterns:
> +        for iterator in iterators:
> +            for dataset in iterator:
> +                backup_dataset = copy.deepcopy(dataset)
> +                yield (
> +                    [*pattern_before, backup_dataset[0], *pattern_after],
> +                    *backup_dataset[1:],
> +                )
> +            # yield from map(
> +            #     lambda flow_item_test_properties: (
> +            #         [*pattern_before, flow_item_test_properties[0], *pattern_after],
> +            #         *flow_item_test_properties[1:],
> +            #     ), iterator
> +            # )
> +
> +    yield from filter(lambda pattern: item not in pattern, patterns)
> +
> +
> +class Flow(object):
> +    action_items: List[ActionFlowItem]
> +    pattern_items: List[PatternFlowItem]
> +    entry_points: FrozenSet[FlowItemType]
> +
> +    def __init__(self, action_items=None, pattern_items=None, ):
> +        if action_items is None:
> +            action_items = []
> +
> +        if pattern_items is None:
> +            pattern_items = []
> +
> +        self.action_items = action_items
> +        self.pattern_items = pattern_items
> +
> +    def __truediv__(self, item: Union[FlowItem, Flow]):
> +        """
> +        Used in a similar way to scapy's packet composition. Returns a new flow
> with the mutated state.
> +        @param item: The other flow item.
> +        @return: A Flow containing both items
> +        """
> +        if isinstance(item, Flow):
> +            return Flow(pattern_items=[*self.pattern_items, *item.pattern_items],
> +                        action_items=[*self.action_items, *item.action_items])
> +        elif isinstance(item, PatternFlowItem):
> +            if len(self.pattern_items) == 0:
> +                return Flow(pattern_items=[*self.pattern_items, item],
> action_items=[*self.action_items])
> +            elif item.type in self.pattern_items[-1].valid_next_items:
> +                return Flow(pattern_items=[*self.pattern_items, item],
> action_items=[*self.action_items])
> +            else:
> +                raise InvalidFlowItemException(self.pattern_items[-1], item, flow=self)
> +        elif isinstance(item, ActionFlowItem):
> +            if len(self.action_items) == 0:
> +                return Flow(pattern_items=[*self.pattern_items],
> action_items=[*self.action_items, item])
> +
> +            for action in self.action_items:
> +                if item.type not in action.allowed_with:
> +                    raise InvalidFlowItemException(action, item, flow=self)
> +            return Flow(pattern_items=[*self.pattern_items],
> action_items=[*self.action_items, item])
> +
> +    def __str__(self):
> +        return f"ingress pattern %s actions queue index 1 / end" % (
> +                    " / ".join(str(item) for item in self.pattern_items) + " / end")
> +
> +    def __repr__(self):
> +        return str(self)
> +
> +    def __eq__(self, other):
> +        return isinstance(other, Flow) and \
> +               len(self.action_items) == len(other.action_items) and \
> +               len(self.pattern_items) == len(other.pattern_items) and \
> +               _iterable_deep_compare(self.pattern_items, other.pattern_items) and
> \
> +               _iterable_deep_compare(self.action_items, other.action_items)
> +
> +    def to_scapy_packet(self):
> +        return reduce(operator.truediv, map(lambda x: x.to_scapy_packet(),
> self.pattern_items))
> +
> +    def get_test_property_flows(self, pattern_item_types_to_update=None,
> action_item_types_to_update=None) -> \
> +            Iterable[Flow]:
> +        if pattern_item_types_to_update is None and
> action_item_types_to_update is None:
> +            pattern_item_types_to_update = [self.pattern_items[-1]]
> +        elif pattern_item_types_to_update is None:
> +            pattern_item_types_to_update = []
> +        elif action_item_types_to_update is None:
> +            action_item_types_to_update = []
> +
> +        # So that if this object is mutated before the generator is finished, it won't
> change anything
> +        base_pattern_items = copy.deepcopy(self.pattern_items)
> +        base_action_items = copy.deepcopy(self.action_items)
> +
> +        test_flows: Iterable[Iterable[FlowItem]] = [base_pattern_items]
> +
> +        tunnelling_protocols = list(filter(lambda i: type(i) in
> TUNNELING_PROTOCOLS, base_pattern_items))
> +        if len(tunnelling_protocols) > 0:
> +            test_flows =
> expand_pattern_list_with_iterable_replacing_item([*test_flows],
> +
> tunnelling_protocols[0].get_property_stream(),
> +                                                                          tunnelling_protocols[0])
> +        else:
> +            test_flows =
> expand_pattern_list_with_iterable_replacing_item([*test_flows],
> +                                                                          self.pattern_items[
> +                                                                              -1].get_property_stream(),
> +                                                                          self.pattern_items[-1])
> +        for pattern in test_flows:
> +            yield Flow(pattern_items=pattern[0], action_items=base_action_items),
> *pattern[1:]
> diff --git a/framework/flow/flow_action_items.py
> b/framework/flow/flow_action_items.py
> new file mode 100644
> index 00000000..50201ee2
> --- /dev/null
> +++ b/framework/flow/flow_action_items.py
> @@ -0,0 +1,1018 @@
> +from typing import FrozenSet, Dict, Tuple
> +
> +from framework.flow.enums import FlowActionType
> +from framework.flow.flow_pattern_items import FlowItem
> +
> +ALWAYS_ALLOWED_ACTIONS = {FlowActionType.VOID}
> +
> +ENTRY_POINTS = {
> +    FlowActionType.VOID,
> +    FlowActionType.PASSTHRU,
> +    FlowActionType.FLAG,
> +    FlowActionType.DROP,
> +    FlowActionType.COUNT,
> +    FlowActionType.MAC_SWAP,
> +    FlowActionType.DEC_TTL,
> +    FlowActionType.JUMP,
> +    FlowActionType.MARK,
> +    FlowActionType.QUEUE,
> +    FlowActionType.RSS,
> +    FlowActionType.PF,
> +    FlowActionType.VF,
> +    FlowActionType.PHY_PORT,
> +    FlowActionType.PORT_ID,
> +    FlowActionType.SECURITY,
> +    FlowActionType.OF_SET_MPLS_TTL,
> +    FlowActionType.OF_DEC_MPLS_TTL,
> +    FlowActionType.OF_SET_NW_TTL,
> +    FlowActionType.OF_DEC_NW_TTL,
> +    FlowActionType.OF_COPY_TTL_OUT,
> +    FlowActionType.OF_COPY_TTL_IN,
> +    FlowActionType.OF_POP_VLAN,
> +    FlowActionType.OF_PUSH_VLAN,
> +    FlowActionType.OF_SET_VLAN_VID,
> +    FlowActionType.OF_SET_VLAN_PCP,
> +    FlowActionType.OF_POP_MPLS,
> +    FlowActionType.OF_PUSH_MPLS,
> +    FlowActionType.VXLAN_ENCAP,
> +    FlowActionType.VXLAN_DECAP,
> +    FlowActionType.NVGRE_ENCAP,
> +    FlowActionType.NVGRE_DECAP,
> +    FlowActionType.RAW_ENCAP,
> +    FlowActionType.RAW_DECAP,
> +    FlowActionType.SET_IPV4_SRC,
> +    FlowActionType.SET_IPV4_DST,
> +    FlowActionType.SET_IPV6_SRC,
> +    FlowActionType.SET_IPV6_DST,
> +    FlowActionType.SET_TP_SRC,
> +    FlowActionType.SET_TP_DST,
> +    FlowActionType.SET_TTL,
> +    FlowActionType.SET_MAC_SRC,
> +    FlowActionType.SET_MAC_DST,
> +    FlowActionType.INC_TCP_SEQ,
> +    FlowActionType.DEC_TCP_SEQ,
> +    FlowActionType.INC_TCP_ACK,
> +    FlowActionType.DEC_TCP_ACK,
> +    FlowActionType.SET_TAG,
> +    FlowActionType.SET_META,
> +    FlowActionType.SET_IPV4_DSCP,
> +    FlowActionType.SET_IPV6_DSCP,
> +    FlowActionType.AGE,
> +}
> +
> +
> +class ActionFlowItem(FlowItem):
> +    allowed_with: FrozenSet[FlowActionType] = \
> +        frozenset({item for item in FlowActionType})
> +
> +    valid_next_items: FrozenSet[FlowActionType] = \
> +        frozenset({item for item in FlowActionType})
> +
> +    test_case: Dict[str, Tuple[str, frozenset, frozenset]] = dict()
> +
> +class FlowActionVoid(ActionFlowItem):
> +    type = FlowActionType.VOID
> +
> +    test_case = {
> +         'test': ('ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions void
> / end',
> +                  frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)"}),
> +                  frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)"})),
> +    }
> +
> +
> +class FlowActionPassthru(ActionFlowItem):
> +    type = FlowActionType.PASSTHRU
> +    test_case = {
> +        'test':  ('ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> passthru / end',
> +                  frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)"}),
> +                  frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)"})),
> +    }
> +
> +
> +class FlowActionFlag(ActionFlowItem):
> +    type = FlowActionType.FLAG
> +    test_case = {
> +        'test': ('ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions flag
> / end',
> +                 frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)"}),
> +                 frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)",
> +                            "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)",
> +                            "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)",
> +                            "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)"})),
> +    }
> +
> +
> +class FlowActionDrop(ActionFlowItem):
> +    type = FlowActionType.DROP
> +    test_case = {
> +        'test': ('ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions drop
> / end',
> +                 frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)"}),
> +                 frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)",
> +                            "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)",
> +                            "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)",
> +                            "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)"})),
> +    }
> +
> +
> +class FlowActionCount(ActionFlowItem):
> +    type = FlowActionType.COUNT
> +    test_case = {
> +        'test_shared': ('ingress pattern eth / ipv4 src is 192.168.0.1'
> +                        ' / udp / end actions count shared 0 id 1 / end',
> +                        frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' *
> 64)"}),
> +                        frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' *
> 64)",
> +                                   "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\x00' * 64)",
> +                                   "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\x00' * 64)",
> +                                   "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)"})),
> +        'test_id': ('ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> count id 1 / end',
> +                    frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' *
> 64)"}),
> +                    frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)",
> +                              "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)",
> +                               "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)",
> +                               "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)"})),
> +    }
> +
> +
> +class FlowActionMac_swap(ActionFlowItem):
> +    type = FlowActionType.MAC_SWAP
> +
> +    test_case = {
> +         'test': ('ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> mac_swap / end',
> +                  frozenset({"Ether(src=\"90:61:ae:fd:41:43\", dst =
> \"ab:cd:ef:12:34:56\") "
> +                            "/ IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)"}),
> +                  frozenset({"Ether(src=\"90:61:ae:fd:41:43\", dst =
> \"ab:cd:ef:12:34:56\") "
> +                            "/ IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)",
> +                             "Ether(src=\"90:61:ae:fd:41:43\", dst = \"ab:cd:ef:12:34:56\") "
> +                             "/ IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)",
> +                             "Ether(src=\"90:61:ae:fd:41:43\", dst = \"ab:cd:ef:12:34:56\") "
> +                             "/ IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)",
> +                             "Ether(src=\"90:61:ae:fd:41:43\", dst = \"ab:cd:ef:12:34:56\") "
> +                             "/ IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)"})),
> +     }
> +
> +
> +class FlowActionDec_ttl(ActionFlowItem):
> +    type = FlowActionType.DEC_TTL
> +
> +    test_case = {
> +        'test': ('ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> dec_ttl / end',
> +                 frozenset({"Ether() / IP(src=\"192.168.0.1\", ttl = 128) / UDP() /
> ('\\x00' * 64)"}),
> +                 frozenset({"Ether() / IP(src=\"192.168.0.2\", ttl = 128) / UDP() /
> ('\\x00' * 64)",
> +                            "Ether() / IP(src=\"10.0.30.99\", ttl = 128) / UDP() / ('\\x00' *
> 64)",
> +                            "Ether() / IP(src=\"8.8.8.8\", ttl = 128 ) / UDP() / ('\\x00' * 64)",
> +                            "Ether() / IP(src=\"132.177.0.99\", ttl = 128) / UDP() / ('\\x00' *
> 64)"})),
> +    }
> +
> +
> +class FlowActionJump(ActionFlowItem):
> +    type = FlowActionType.JUMP
> +
> +    test_case = {
> +         'test': ('ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> jump group 1 / end',
> +                  frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)"}),
> +                  frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)"})),
> +    }
> +
> +
> +class FlowActionMark(ActionFlowItem):
> +    type = FlowActionType.MARK
> +    test_case = {
> +        'test': ('ingress pattern eth / ipv4 src is 192.168.0.1 '
> +                 '/ udp / end actions mark id 0xABCDEF / end',
> +                 frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)"}),
> +                 frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)",
> +                            "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)",
> +                            "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)",
> +                            "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)"})),
> +    }
> +
> +
> +class FlowActionQueue(ActionFlowItem):
> +    type = FlowActionType.QUEUE
> +    test_case = {
> +        'test': ('ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> queue index 1 / end',
> +                 frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)"}),
> +                 frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)",
> +                            "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)",
> +                            "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)",
> +                            "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)"})),
> +    }
> +
> +
> +class FlowActionRss(ActionFlowItem):
> +    type = FlowActionType.RSS
> +
> +    # RSS already has a test suite.
> +    '''
> +     test_case = {
> +         'case1': ('ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions /
> end',
> +                   frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)"}),
> +                   frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)",
> +                              "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)",
> +                              "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)",
> +                              "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)"})),
> +     }
> +     '''
> +
> +
> +class FlowActionPf(ActionFlowItem):
> +    type = FlowActionType.PF
> +    test_case = {
> +        'test': ('ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions pf /
> end',
> +                 frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)"}),
> +                 frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)",
> +                            "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)",
> +                            "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)",
> +                            "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)"})),
> +    }
> +
> +
> +class FlowActionVf(ActionFlowItem):
> +    type = FlowActionType.VF
> +    test_case = {
> +        'test_original': ('ingress pattern eth / ipv4 src is 192.168.0.1 /'
> +                          ' udp / end actions vf original 1/ end',
> +                          frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' *
> 64)"}),
> +                          frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' *
> 64)",
> +                                     "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\x00' * 64)",
> +                                     "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\x00' * 64)",
> +                                     "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' *
> 64)"})),
> +        'test_id': ('ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> vf id 1 / end',
> +                    frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' *
> 64)"}),
> +                    frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)",
> +                               "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)",
> +                               "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)",
> +                               "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)"})),
> +    }
> +
> +
> +class FlowActionPhy_port(ActionFlowItem):
> +    type = FlowActionType.PHY_PORT
> +
> +    test_case = {
> +         # original port index
> +         'test_original': ('ingress pattern eth / ipv4 src is 192.168.0.1'
> +                           ' / udp / end actions phy_port original / end',
> +                           frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' *
> 64)"}),
> +                           frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' *
> 64)",
> +                                      "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)",
> +                                      "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)",
> +                                      "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' *
> 64)"})),
> +         # physical port index
> +         'test_index': ('ingress pattern eth / ipv4 src is 192.168.0.1 '
> +                        '/ udp / end actions phy_port index 1 / end',
> +                        frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' *
> 64)"}),
> +                        frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' *
> 64)",
> +                                   "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)",
> +                                   "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)",
> +                                   "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)"})),
> +    }
> +
> +
> +class FlowActionPort_id(ActionFlowItem):
> +    type = FlowActionType.PORT_ID
> +
> +    test_case = {
> +        # original DPDK port ID
> +        'test_original': ('ingress pattern eth / ipv4 src is 192.168.0.1 '
> +                          '/ udp / end actions port_id original / end',
> +                          frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' *
> 64)"}),
> +                          frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' *
> 64)",
> +                                     "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)",
> +                                     "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)",
> +                                     "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' *
> 64)"})),
> +        # DPDK port ID
> +        'test_id': ('ingress pattern eth / ipv4 src is 192.168.0.1 '
> +                    '/ udp / end actions port_id id 1 / end',
> +                    frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' *
> 64)"}),
> +                    frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)",
> +                               "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)",
> +                               "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)",
> +                               "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)"})),
> +     }
> +
> +
> +class FlowActionMeter(ActionFlowItem):
> +    type = FlowActionType.METER
> +    test_case = {
> +        'test': ('ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> meter mtr_id 1 / end',
> +                 frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)"}),
> +                 frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)",
> +                            "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)",
> +                            "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)",
> +                            "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)"})),
> +    }
> +
> +
> +class FlowActionSecurity(ActionFlowItem):
> +    type = FlowActionType.SECURITY
> +    test_case = {
> +        'test': ('ingress pattern eth / ipv4 src is 192.168.0.1'
> +                 ' / udp / end actions security security_session 1 / end',
> +                 frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)"}),
> +                 frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)",
> +                            "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)",
> +                            "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)",
> +                            "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)"})),
> +    }
> +
> +
> +class FlowActionOf_set_mpls_ttl(ActionFlowItem):
> +    type = FlowActionType.OF_SET_MPLS_TTL
> +
> +    test_case = {
> +         'test': ('ingress pattern eth / ipv4 src is 192.168.0.1 '
> +                  '/ udp / end actions of_set_mpls_ttl mpls_ttl 64 / end',
> +                  frozenset({"Ether() / IP(src=\"192.168.0.1\") / MPLS(label = 0xab,
> ttl=128)"
> +                             " / UDP() / ('\\x00' * 64)"}),
> +                  frozenset({"Ether() / IP(src=\"192.168.0.2\") / MPLS(label = 0xab,
> ttl=128) / UDP() / ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"10.0.30.99\") / MPLS(label = 0xab, ttl=128) /
> UDP() / ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"8.8.8.8\") / MPLS(label = 0xab, ttl=128) /
> UDP() / ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"132.177.0.99\") / MPLS(label = 0xab,
> ttl=128)"
> +                             " / UDP() / ('\\x00' * 64)"})),
> +     }
> +
> +
> +class FlowActionOf_dec_mpls_ttl(ActionFlowItem):
> +    type = FlowActionType.OF_DEC_MPLS_TTL
> +
> +    test_case = {
> +        'test': (
> +            'ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> of_dec_mpls_ttl / end',
> +            frozenset({"Ether() / IP(src=\"192.168.0.1\") / MPLS(label = 0xab, ttl=128)
> / UDP() / ('\\x00' * 64)"}),
> +            frozenset({"Ether() / IP(src=\"192.168.0.2\") / MPLS(label = 0xab, ttl=128)
> / UDP() / ('\\x00' * 64)",
> +                       "Ether() / IP(src=\"10.0.30.99\") / MPLS(label = 0xab, ttl=128) /
> UDP() / ('\\x00' * 64)",
> +                       "Ether() / IP(src=\"8.8.8.8\") / MPLS(label = 0xab, ttl=128) / UDP() /
> ('\\x00' * 64)",
> +                       "Ether() / IP(src=\"132.177.0.99\") / MPLS(label = 0xab, ttl=128) /
> UDP() / ('\\x00' * 64)"})),
> +    }
> +
> +
> +class FlowActionOf_set_nw_ttl(ActionFlowItem):
> +    type = FlowActionType.OF_SET_NW_TTL
> +
> +    test_case = {
> +         'test': ('ingress pattern eth / ipv4 src is 192.168.0.1 '
> +                  '/ udp / end actions of_set_nw_ttl nw_ttl 64 / end',
> +                  frozenset({"Ether() / IP(src=\"192.168.0.1\", ttl=128) / UDP() / ('\\x00'
> * 64)"}),
> +                  frozenset({"Ether() / IP(src=\"192.168.0.2\", ttl=128) / UDP() / ('\\x00'
> * 64)",
> +                             "Ether() / IP(src=\"10.0.30.99\", ttl=128) / UDP() / ('\\x00' *
> 64)",
> +                             "Ether() / IP(src=\"8.8.8.8\", ttl=128) / UDP() / ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"132.177.0.99\", ttl=128) / UDP() / ('\\x00' *
> 64)"})),
> +    }
> +
> +
> +class FlowActionOf_dec_nw_ttl(ActionFlowItem):
> +    type = FlowActionType.OF_DEC_NW_TTL
> +    test_case = {
> +        'test': (
> +            'ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> of_dec_nw_ttl / end',
> +            frozenset({"Ether() / IP(src=\"192.168.0.1\", ttl=128) / UDP() / ('\\x00' *
> 64)"}),
> +            frozenset({"Ether() / IP(src=\"192.168.0.2\", ttl=128) / UDP() / ('\\x00' *
> 64)",
> +                       "Ether() / IP(src=\"10.0.30.99\", ttl=128) / UDP() / ('\\x00' * 64)",
> +                       "Ether() / IP(src=\"8.8.8.8\", ttl=128) / UDP() / ('\\x00' * 64)",
> +                       "Ether() / IP(src=\"132.177.0.99\", ttl=128) / UDP() / ('\\x00' *
> 64)"})),
> +    }
> +
> +
> +class FlowActionOf_copy_ttl_out(ActionFlowItem):
> +    type = FlowActionType.OF_COPY_TTL_OUT
> +
> +    test_case = {
> +         'test': ('ingress pattern eth / ipv4 src is 192.168.0.1 '
> +                  '/ udp / end actions of_copy_ttl_out / end',
> +                  frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)"}),
> +                  frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)"})),
> +    }
> +
> +
> +class FlowActionOf_copy_ttl_in(ActionFlowItem):
> +    type = FlowActionType.OF_COPY_TTL_IN
> +
> +    test_case = {
> +         'test': ('ingress pattern eth / ipv4 src is 192.168.0.1 '
> +                  '/ udp / end actions of_copy_ttl_out / end',
> +                  frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)"}),
> +                  frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)"})),
> +    }
> +
> +
> +class FlowActionOf_pop_vlan(ActionFlowItem):
> +    type = FlowActionType.OF_POP_VLAN
> +
> +    test_case = {
> +         'test': ('ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> of_pop_vlan / end',
> +                  frozenset({"Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"192.168.0.1\") "
> +                             "/ UDP() / ('\\x00' * 64)"}),
> +                  frozenset({"Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"192.168.0.2\") "
> +                             "/ UDP() / ('\\x00' * 64)",
> +                             "Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"10.0.30.99\") "
> +                             "/ UDP() / ('\\x00' * 64)",
> +                             "Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"8.8.8.8\") "
> +                             "/ UDP() / ('\\x00' * 64)",
> +                             "Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"132.177.0.99\")"
> +                             " / UDP() / ('\\x00' * 64)"})),
> +    }
> +
> +
> +class FlowActionOf_push_vlan(ActionFlowItem):
> +    type = FlowActionType.OF_PUSH_VLAN
> +    test_case = {
> +         'test': ('ingress pattern eth / ipv4 src is 192.168.0.1'
> +                  ' / udp / end actions of_push_vlan ethertype 0x8100 / end',
> +                  frozenset({"Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"192.168.0.1\") "
> +                             "/ UDP() / ('\\x00' * 64)"}),
> +                  frozenset({"Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"192.168.0.2\") "
> +                             "/ UDP() / ('\\x00' * 64)",
> +                             "Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"10.0.30.99\") "
> +                             "/ UDP() / ('\\x00' * 64)",
> +                             "Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"8.8.8.8\") "
> +                             "/ UDP() / ('\\x00' * 64)",
> +                             "Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"132.177.0.99\")"
> +                             " / UDP() / ('\\x00' * 64)"})),
> +    }
> +
> +
> +class FlowActionOf_set_vlan_vid(ActionFlowItem):
> +    type = FlowActionType.OF_SET_VLAN_VID
> +
> +    test_case = {
> +        'test': ('ingress pattern eth / ipv4 src is 192.168.0.1 '
> +                 '/ udp / end actions of_set_vlan_vid vlan_vid 0xbbb / end',
> +                 frozenset({
> +                               "Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"192.168.0.1\")"
> +                               " / UDP() / ('\\x00' * 64)"}),
> +                 frozenset({
> +                               "Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"192.168.0.2\") "
> +                               "/ UDP() / ('\\x00' * 64)",
> +                               "Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"10.0.30.99\") "
> +                               "/ UDP() / ('\x00' * 64)",
> +                               "Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"8.8.8.8\") "
> +                               "/ UDP() / ('\x00' * 64)",
> +                               "Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"132.177.0.99\") "
> +                               "/ UDP() / ('\\x00' * 64)"})),
> +    }
> +
> +
> +class FlowActionOf_set_vlan_pcp(ActionFlowItem):
> +    type = FlowActionType.OF_SET_VLAN_PCP
> +    test_case = {
> +        'test': ('ingress pattern eth / ipv4 src is 192.168.0.1'
> +                 ' / udp / end actions of_set_vlan_vid vlan_pcp 0x7 / end',
> +                 frozenset({
> +                               "Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"192.168.0.1\") "
> +                               "/ UDP() / ('\\x00' * 64)"}),
> +                 frozenset({
> +                               "Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"192.168.0.2\") "
> +                               "/ UDP() / ('\\x00' * 64)",
> +                               "Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"10.0.30.99\") "
> +                               "/ UDP() / ('\x00' * 64)",
> +                               "Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"8.8.8.8\") "
> +                               "/ UDP() / ('\x00' * 64)",
> +                               "Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"132.177.0.99\") "
> +                               "/ UDP() / ('\\x00' * 64)"})),
> +    }
> +
> +
> +class FlowActionOf_pop_mpls(ActionFlowItem):
> +    type = FlowActionType.OF_POP_MPLS
> +    test_case = {
> +        'test': (
> +            'ingress pattern eth / ipv4 src is 192.168.0.1 '
> +            '/ udp / end actions of_pop_mpls ethertype 0x0806 / end',
> +            frozenset({"Ether() / IP(src=\"192.168.0.1\") / MPLS(label = 0xab, ttl=128)
> / UDP() / ('\\x00' * 64)"}),
> +            frozenset({"Ether() / IP(src=\"192.168.0.2\") / MPLS(label = 0xab, ttl=128)
> / UDP() / ('\\x00' * 64)",
> +                       "Ether() / IP(src=\"10.0.30.99\") / MPLS(label = 0xab, ttl=128) /
> UDP() / ('\x00' * 64)",
> +                       "Ether() / IP(src=\"8.8.8.8\") / MPLS(label = 0xab, ttl=128) / UDP() /
> ('\x00' * 64)",
> +                       "Ether() / IP(src=\"132.177.0.99\") / MPLS(label = 0xab, ttl=128) /
> UDP() / ('\\x00' * 64)"})),
> +    }
> +
> +
> +class FlowActionOf_push_mpls(ActionFlowItem):
> +    type = FlowActionType.OF_PUSH_MPLS
> +
> +    test_case = {
> +        'test': (
> +            'ingress pattern eth / ipv4 src is 192.168.0.1'
> +            ' / udp / end actions of_push_mpls ethertype 0x0806 / end',
> +            frozenset({"Ether() / IP(src=\"192.168.0.1\") / MPLS(label = 0xab, ttl=128)
> / UDP() / ('\\x00' * 64)"}),
> +            frozenset({"Ether() / IP(src=\"192.168.0.2\") / MPLS(label = 0xab, ttl=128)
> / UDP() / ('\\x00' * 64)",
> +                       "Ether() / IP(src=\"10.0.30.99\") / MPLS(label = 0xab, ttl=128) /
> UDP() / ('\x00' * 64)",
> +                       "Ether() / IP(src=\"8.8.8.8\") / MPLS(label = 0xab, ttl=128) / UDP() /
> ('\x00' * 64)",
> +                       "Ether() / IP(src=\"132.177.0.99\") / MPLS(label = 0xab, ttl=128) /
> UDP() / ('\\x00' * 64)"})),
> +    }
> +
> +
> +class FlowActionVxlan_encap(ActionFlowItem):
> +    type = FlowActionType.VXLAN_ENCAP
> +
> +    test_case = {
> +         # VXLAN encap definition is the VNI?
> +         'test': ('ingress pattern eth / ipv4 src is 192.168.0.1'
> +                  ' / udp / end actions vxlan_encap definition 0x112233 / end',
> +                  frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)"}),
> +                  frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\x00' * 64)",
> +                             "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\x00' * 64)",
> +                             "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)"})),
> +     }
> +
> +
> +class FlowActionVxlan_decap(ActionFlowItem):
> +    type = FlowActionType.VXLAN_DECAP
> +
> +    test_case = {
> +         'test': ('ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> vxlan_decap / end',
> +                  frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / VXLAN() /
> ('\\x00' * 64)"}),
> +                  frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / VXLAN() /
> ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"10.0.30.99\") / UDP() / VXLAN() / ('\\x00' *
> 64)",
> +                             "Ether() / IP(src=\"8.8.8.8\") / UDP() / VXLAN() / ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"132.177.0.99\") / UDP() / VXLAN() / ('\\x00' *
> 64)"})),
> +     }
> +
> +
> +class FlowActionNvgre_encap(ActionFlowItem):
> +    type = FlowActionType.NVGRE_ENCAP
> +    # NVGRE PACKETS NOT SUPPORTED BY SCAPY.
> +    '''
> +     test_case = {
> +         'test': ('ingress pattern eth / ipv4 src is 192.168.0.1
> +         / udp / end actions nvgre_encap definition 0x112233 / end',
> +                   frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() /  NVGRE() /
> ('\\x00' * 64)"}),
> +                   frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() /  NVGRE() /
> ('\\x00' * 64)",
> +                              "Ether() / IP(src=\"10.0.30.99\") / UDP() /  NVGRE() / ('\\x00' *
> 64)",
> +                              "Ether() / IP(src=\"8.8.8.8\") / UDP() /  NVGRE() / ('\\x00' * 64)",
> +                              "Ether() / IP(src=\"132.177.0.99\") / UDP() /  NVGRE() / ('\\x00'
> * 64)"})),
> +     }
> +     '''
> +
> +
> +class FlowActionNvgre_decap(ActionFlowItem):
> +    type = FlowActionType.NVGRE_DECAP
> +    # NVGRE PACKETS NOT SUPPORTED BY SCAPY.
> +    '''
> +     test_case = {
> +         'test': ('ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> nvgre_decap / end',
> +                   frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / NVGRE() /
> ('\\x00' * 64)"}),
> +                   frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / NVGRE() /
> ('\\x00' * 64)",
> +                              "Ether() / IP(src=\"10.0.30.99\") / UDP() / NVGRE() / ('\\x00' *
> 64)",
> +                              "Ether() / IP(src=\"8.8.8.8\") / UDP() / NVGRE() / ('\\x00' * 64)",
> +                              "Ether() / IP(src=\"132.177.0.99\") / UDP() / NVGRE() / ('\\x00'
> * 64)"})),
> +     }
> +     '''
> +
> +
> +class FlowActionRaw_encap(ActionFlowItem):
> +    type = FlowActionType.RAW_ENCAP
> +    # Assume we are encapsulating with a VLAN header with the following values:
> +    # TPID: 0x8100
> +    # Prio: 0x5
> +    # PCP: 0
> +    # VID: 0xaaa
> +    # This makes the full header: 0x8100aaaa
> +    test_case = {
> +        'test_data': ('ingress pattern eth / ipv4 src is 192.168.0.1 '
> +                      '/ udp / end actions raw_encap data 0x8100aaaa / end',
> +                      frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' *
> 64)"}),
> +                      frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' *
> 64)",
> +                                 "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\x00' * 64)",
> +                                 "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\x00' * 64)",
> +                                 "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)"})),
> +
> +        'test_preserve': ('ingress pattern eth / ipv4 src is 192.168.0.1 '
> +                          '/ udp / end actions raw_encap data 0x8100aaaa preserve
> 0xffffffff / end',
> +                          frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' *
> 64)"}),
> +                          frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' *
> 64)",
> +                                     "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)",
> +                                     "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)",
> +                                     "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' *
> 64)"})),
> +        # Is "size" in bits or bytes? Unclear in documentation, defaulting to bits.
> +        'test_size': ('ingress pattern eth / ipv4 src is 192.168.0.1 '
> +                      '/ udp / end actions raw_encap data 0x8100aaaa size 32 / end',
> +                      frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' *
> 64)"}),
> +                      frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' *
> 64)",
> +                                 "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\x00' * 64)",
> +                                 "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\x00' * 64)",
> +                                 "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)"})),
> +    }
> +
> +
> +class FlowActionRaw_decap(ActionFlowItem):
> +    type = FlowActionType.RAW_DECAP
> +    test_case = {
> +        'test_data': (
> +            'ingress pattern eth / ipv4 src is 192.168.0.1 '
> +            '/ udp / end actions raw_decap data 0x8100aaaa / end',
> +            frozenset({"Ether()  / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)"}),
> +            frozenset({"Ether() /  Dot1Q(prio = 0x5, id = 0x0, vlan = 0xbbb) /
> IP(src=\"192.168.0.2\")"
> +                       " / UDP() / ('\\x00' * 64)",
> +                       "Ether() /  Dot1Q(prio = 0x5, id = 0x0, vlan = 0xbbb) /
> IP(src=\"10.0.30.99\") "
> +                       "/ UDP() / ('\x00' * 64)",
> +                       "Ether() /  Dot1Q(prio = 0x5, id = 0x0, vlan = 0xbbb) /
> IP(src=\"8.8.8.8\")"
> +                       " / UDP() / ('\x00' * 64)",
> +                       "Ether() /  Dot1Q(prio = 0x5, id = 0x0, vlan = 0xbbb) /
> IP(src=\"132.177.0.99\") "
> +                       "/ UDP() / ('\\x00' * 64)"})),
> +
> +        # Is "size" in bits or bytes? Unclear in documentation, defaulting to bits.
> +        'test_size': (
> +            'ingress pattern eth / ipv4 src is 192.168.0.1 '
> +            '/ udp / end actions raw_decap data 0x8100aaaa size 32 / end',
> +            frozenset({"Ether() /  Dot1Q(prio = 0x5, id = 0x0, vlan = 0xbbb) /
> IP(src=\"192.168.0.1\") "
> +                       "/ UDP() / ('\\x00' * 64)"}),
> +            frozenset({"Ether() /  Dot1Q(prio = 0x5, id = 0x0, vlan = 0xbbb) /
> IP(src=\"192.168.0.2\") "
> +                       "/ UDP() / ('\\x00' * 64)",
> +                       "Ether() /  Dot1Q(prio = 0x5, id = 0x0, vlan = 0xbbb) /
> IP(src=\"10.0.30.99\")"
> +                       " / UDP() / ('\x00' * 64)",
> +                       "Ether() /  Dot1Q(prio = 0x5, id = 0x0, vlan = 0xbbb) /
> IP(src=\"8.8.8.8\") "
> +                       "/ UDP() / ('\x00' * 64)",
> +                       "Ether() /  Dot1Q(prio = 0x5, id = 0x0, vlan = 0xbbb) /
> IP(src=\"132.177.0.99\") "
> +                       "/ UDP() / ('\\x00' * 64)"})),
> +    }
> +
> +
> +class FlowActionSet_ipv4_src(ActionFlowItem):
> +    type = FlowActionType.SET_IPV4_SRC
> +
> +    test_case = {
> +         'test': ('ingress pattern eth / ipv4 src is 192.168.0.1 '
> +                  '/ udp / end actions set_ipv4_src ipv4_addr 172.16.0.10  / end',
> +                  frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)"}),
> +                  frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)"})),
> +     }
> +
> +
> +class FlowActionSet_ipv4_dst(ActionFlowItem):
> +    type = FlowActionType.SET_IPV4_DST
> +
> +    test_case = {
> +         'test': ('ingress pattern eth / ipv4 dst is 192.168.0.1'
> +                  ' / udp / end actions set_ipv4_dst ipv4_addr 172.16.0.10 / end',
> +                  frozenset({"Ether() / IP(dst=\"192.168.0.1\") / UDP() / ('\\x00' * 64)"}),
> +                  frozenset({"Ether() / IP(dst=\"192.168.0.2\") / UDP() / ('\\x00' * 64)",
> +                             "Ether() / IP(dst=\"10.0.30.99\") / UDP() / ('\\x00' * 64)",
> +                             "Ether() / IP(dst=\"8.8.8.8\") / UDP() / ('\\x00' * 64)",
> +                             "Ether() / IP(dst=\"132.177.0.99\") / UDP() / ('\\x00' * 64)"})),
> +    }
> +
> +
> +class FlowActionSet_ipv6_src(ActionFlowItem):
> +    type = FlowActionType.SET_IPV6_SRC
> +
> +    test_case = {
> +         'test': ('ingress pattern eth / ipv6 src is
> 2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c2 '
> +                  '/ udp / end actions set_ipv6_src ipv6_addr
> 2001:0000:9d38:6ab8:1c48:9999:aaaa:bbbb',
> +                  frozenset({"Ether() /
> IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c2\") "
> +                             "/ UDP() / ('\\x00' * 64)"}),
> +                  frozenset({"Ether() /
> IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c3\") / UDP() / ('\\x00' *
> 64)",
> +                            "Ether() /
> IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c4\") / UDP() / ('\x00' * 64)",
> +                             "Ether() /
> IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c5\") / UDP() / ('\x00' * 64)",
> +                             "Ether() /
> IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c6\") "
> +                             "/ UDP() / ('\\x00' * 64)"})),
> +    }
> +
> +
> +class FlowActionSet_ipv6_dst(ActionFlowItem):
> +    type = FlowActionType.SET_IPV6_DST
> +
> +    test_case = {
> +         'test': ('ingress pattern eth / ipv6 dst is
> 2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c2 '
> +                  '/ udp / end actions set_ipv6_dst ipv6_addr
> 2001:0000:9d38:6ab8:1c48:9999:aaaa:bbbb',
> +                  frozenset({"Ether() /
> IPv6(dst=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c2\")"
> +                             " / UDP() / ('\\x00' * 64)"}),
> +                  frozenset({"Ether() /
> IPv6(dst=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c3\") / UDP() / ('\\x00' *
> 64)",
> +                            "Ether() /
> IPv6(dst=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c4\") / UDP() / ('\x00' * 64)",
> +                             "Ether() /
> IPv6(dst=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c5\") / UDP() / ('\x00' * 64)",
> +                             "Ether() /
> IPv6(dst=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c6\") "
> +                             "/ UDP() / ('\\x00' * 64)"})),
> +      }
> +
> +
> +class FlowActionSet_tp_src(ActionFlowItem):
> +    type = FlowActionType.SET_TP_SRC
> +
> +    test_case = {
> +        # UDP
> +        'test_udp': ('ingress pattern eth / ipv4 src is 192.168.0.1'
> +                     ' / udp / end actions set_tp_src port 1998 / end',
> +                     frozenset({"Ether() / IP(src=\"192.168.0.1\") UDP(sport=3838) /
> ('\\x00' * 64)"}),
> +                     frozenset({"Ether() / IP(src=\"192.168.0.2\") UDP(sport=3838) /
> ('\\x00' * 64)",
> +                                "Ether() / IP(src=\"10.0.30.99\") UDP(sport=3838) / ('\x00' *
> 64)",
> +                                "Ether() / IP(src=\"8.8.8.8\") UDP(sport=3838) / ('\x00' * 64)",
> +                                "Ether() / IP(src=\"132.177.0.99\") UDP(sport=3838) / ('\\x00'
> * 64)"})),
> +
> +        # TCP
> +        'test_tcp': (
> +          'ingress pattern eth / ipv4 src is 192.168.0.1 / tcp / end actions set_tp_src
> port 1998 / end',
> +          frozenset({"Ether() / IP(src=\"192.168.0.1\") TCP(sport=3838) / ('\\x00' *
> 64)"}),
> +          frozenset({"Ether() / IP(src=\"192.168.0.2\") TCP(sport=3838) / ('\\x00' *
> 64)",
> +                     "Ether() / IP(src=\"10.0.30.99\") TCP(sport=3838) / ('\x00' * 64)",
> +                     "Ether() / IP(src=\"8.8.8.8\") TCP(sport=3838) / ('\x00' * 64)",
> +                     "Ether() / IP(src=\"132.177.0.99\") TCP(sport=3838) / ('\\x00' *
> 64)"})),
> +    }
> +
> +
> +class FlowActionSet_tp_dst(ActionFlowItem):
> +    type = FlowActionType.SET_TP_DST
> +
> +    test_case = {
> +        # UDP
> +        'test_udp': ('ingress pattern eth / ipv4 src is 192.168.0.1 '
> +                     '/ udp / end actions set_tp_dst port 1998 / end',
> +                     frozenset({"Ether() / IP(src=\"192.168.0.1\") UDP(dport=3838) /
> ('\\x00' * 64)"}),
> +                     frozenset({"Ether() / IP(src=\"192.168.0.2\") UDP(dport=3838) /
> ('\\x00' * 64)",
> +                                "Ether() / IP(src=\"10.0.30.99\") UDP(dport=3838) / ('\x00' *
> 64)",
> +                                "Ether() / IP(src=\"8.8.8.8\") UDP(dport=3838) / ('\x00' * 64)",
> +                                "Ether() / IP(src=\"132.177.0.99\") UDP(dport=3838) / ('\\x00'
> * 64)"})),
> +
> +        # TCP
> +        'test_tcp': (
> +          'ingress pattern eth / ipv4 src is 192.168.0.1 / tcp / end actions set_tp_dst
> port 1998 / end',
> +          frozenset({"Ether() / IP(src=\"192.168.0.1\") TCP(dport=3838) / ('\\x00' *
> 64)"}),
> +          frozenset({"Ether() / IP(src=\"192.168.0.2\") TCP(dport=3838) / ('\\x00' *
> 64)",
> +                     "Ether() / IP(src=\"10.0.30.99\") TCP(dport=3838) / ('\x00' * 64)",
> +                     "Ether() / IP(src=\"8.8.8.8\") TCP(dport=3838) / ('\x00' * 64)",
> +                     "Ether() / IP(src=\"132.177.0.99\") TCP(dport=3838) / ('\\x00' *
> 64)"})),
> +
> +    }
> +
> +
> +class FlowActionSet_ttl(ActionFlowItem):
> +    type = FlowActionType.SET_TTL
> +
> +    test_case = {
> +         'test': ('ingress pattern eth / ipv4 src is 192.168.0.1'
> +                  ' / udp / end actions set_ttl ttl_value 64 / end',
> +                  frozenset({"Ether() / IP(src=\"192.168.0.1\" , ttl=128 ) / UDP() /
> ('\\x00' * 64)"}),
> +                  frozenset({"Ether() / IP(src=\"192.168.0.2\" , ttl=128 ) / UDP() /
> ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"10.0.30.99\" , ttl=128 ) / UDP() / ('\x00' *
> 64)",
> +                             "Ether() / IP(src=\"8.8.8.8\", ttl=128 ) / UDP() / ('\x00' * 64)",
> +                             "Ether() / IP(src=\"132.177.0.99\", ttl=128 ) / UDP() / ('\\x00' *
> 64)"})),
> +    }
> +
> +
> +class FlowActionSet_mac_src(ActionFlowItem):
> +    type = FlowActionType.SET_MAC_SRC
> +
> +    test_case = {
> +         'test': ('ingress pattern eth / ipv4 src is 192.168.0.1'
> +                  ' / udp / end actions set_mac_src mac_addr 10:20:30:40:50:60 / end',
> +                  frozenset({"Ether(src=\"90:61:ae:fd:41:43\") / IP(src=\"192.168.0.1\")
> / UDP() / ('\\x00' * 64)"}),
> +                  frozenset({"Ether(src=\"90:61:ae:fd:41:43\") / IP(src=\"192.168.0.2\")
> / UDP() / ('\\x00' * 64)",
> +                            "Ether(src=\"90:61:ae:fd:41:43\") / IP(src=\"10.0.30.99\") /
> UDP() / ('\\x00' * 64)",
> +                             "Ether(src=\"90:61:ae:fd:41:43\") / IP(src=\"8.8.8.8\") / UDP() /
> ('\\x00' * 64)",
> +                             "Ether(src=\"90:61:ae:fd:41:43\") / IP(src=\"132.177.0.99\") /
> UDP() / ('\\x00' * 64)"})),
> +     }
> +
> +
> +class FlowActionSet_mac_dst(ActionFlowItem):
> +    type = FlowActionType.SET_MAC_DST
> +    test_case = {
> +             'test': ('ingress pattern eth / ipv4 src is 192.168.0.1'
> +                      ' / udp / end actions set_mac_dst mac_addr 10:20:30:40:50:60 /
> end',
> +                      frozenset({"Ether(dst=\"90:61:ae:fd:41:43\") /
> IP(src=\"192.168.0.1\") "
> +                                 "/ UDP() / ('\\x00' * 64)"}),
> +                      frozenset({"Ether(dst=\"90:61:ae:fd:41:43\") /
> IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)",
> +                                "Ether(dst=\"90:61:ae:fd:41:43\") / IP(src=\"10.0.30.99\") /
> UDP() / ('\x00' * 64)",
> +                                 "Ether(dst=\"90:61:ae:fd:41:43\") / IP(src=\"8.8.8.8\") / UDP()
> / ('\x00' * 64)",
> +                                 "Ether(dst=\"90:61:ae:fd:41:43\") / IP(src=\"132.177.0.99\")
> "
> +                                 "/ UDP() / ('\\x00' * 64)"})),
> +         }
> +
> +
> +class FlowActionInc_tcp_seq(ActionFlowItem):
> +    type = FlowActionType.INC_TCP_SEQ
> +
> +    test_case = {
> +         'test': ('ingress pattern eth / ipv4 src is 192.168.0.1 / tcp / end actions
> inc_tcp_seq / end',
> +                  frozenset({"Ether() / IP(src=\"192.168.0.1\") / TCP(seq=2) / ('\\x00' *
> 64)"}),
> +                  frozenset({"Ether() / IP(src=\"192.168.0.2\") / TCP(seq=2) / ('\\x00' *
> 64)",
> +                             "Ether() / IP(src=\"10.0.30.99\") / TCP(seq=2) / ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"8.8.8.8\") / TCP(seq=2) / ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"132.177.0.99\") / TCP(seq=2) / ('\\x00' *
> 64)"})),
> +     }
> +
> +
> +class FlowActionDec_tcp_seq(ActionFlowItem):
> +    type = FlowActionType.DEC_TCP_SEQ
> +
> +    test_case = {
> +         'test': ('ingress pattern eth / ipv4 src is 192.168.0.1 / tcp / end actions
> dec_tcp_seq / end',
> +                  frozenset({"Ether() / IP(src=\"192.168.0.1\") / TCP(seq=2) / ('\\x00' *
> 64)"}),
> +                  frozenset({"Ether() / IP(src=\"192.168.0.2\") / TCP(seq=2) / ('\\x00' *
> 64)",
> +                             "Ether() / IP(src=\"10.0.30.99\") / TCP(seq=2) / ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"8.8.8.8\") / TCP(seq=2) / ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"132.177.0.99\") / TCP(seq=2) / ('\\x00' *
> 64)"})),
> +    }
> +
> +
> +class FlowActionInc_tcp_ack(ActionFlowItem):
> +    type = FlowActionType.INC_TCP_ACK
> +
> +    test_case = {
> +         'test': ('ingress pattern eth / ipv4 src is 192.168.0.1 / tcp / end actions
> inc_tcp_ack / end',
> +                  frozenset({"Ether() / IP(src=\"192.168.0.1\") / TCP(ack=2) / ('\\x00' *
> 64)"}),
> +                  frozenset({"Ether() / IP(src=\"192.168.0.2\") / TCP(ack=2) / ('\\x00' *
> 64)",
> +                             "Ether() / IP(src=\"10.0.30.99\") / TCP(ack=2) / ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"8.8.8.8\") / TCP(ack=2) / ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"132.177.0.99\") / TCP(ack=2) / ('\\x00' *
> 64)"})),
> +     }
> +
> +
> +class FlowActionDec_tcp_ack(ActionFlowItem):
> +    type = FlowActionType.DEC_TCP_ACK
> +
> +    test_case = {
> +         'test': ('ingress pattern eth / ipv4 src is 192.168.0.1 / tcp / end actions
> dec_tcp_ack / end',
> +                  frozenset({"Ether() / IP(src=\"192.168.0.1\") / TCP(ack=2) / ('\\x00' *
> 64)"}),
> +                  frozenset({"Ether() / IP(src=\"192.168.0.2\") / TCP(ack=2) / ('\\x00' *
> 64)",
> +                             "Ether() / IP(src=\"10.0.30.99\") / TCP(ack=2) / ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"8.8.8.8\") / TCP(ack=2) / ('\\x00' * 64)",
> +                             "Ether() / IP(src=\"132.177.0.99\") / TCP(ack=2) / ('\\x00' *
> 64)"})),
> +    }
> +
> +
> +class FlowActionSet_tag(ActionFlowItem):
> +    type = FlowActionType.SET_TAG
> +
> +    test_case = {
> +         'test_data': ('ingress pattern eth / ipv4 src is 192.168.0.1 '
> +                       '/ udp / end actions set_tag data 0xabc / end',
> +                       frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' *
> 64)"}),
> +                       frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' *
> 64)",
> +                                  "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\x00' * 64)",
> +                                  "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\x00' * 64)",
> +                                  "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)"})),
> +         # bit-mask applies to "data"
> +         'test_mask': ('ingress pattern eth / ipv4 src is 192.168.0.1 '
> +                       '/ udp / end actions set_tag data 0xabc mask 0xcba / end',
> +                       frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' *
> 64)"}),
> +                       frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' *
> 64)",
> +                                  "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)",
> +                                  "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)",
> +                                  "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)"})),
> +         'test_index': ('ingress pattern eth / ipv4 src is 192.168.0.1 '
> +                        '/ udp / end actions set_tag data 0xabc index 1 / end',
> +                        frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' *
> 64)"}),
> +                        frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' *
> 64)",
> +                                   "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\x00' * 64)",
> +                                   "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\x00' * 64)",
> +                                   "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)"})),
> +    }
> +
> +
> +class FlowActionSet_meta(ActionFlowItem):
> +    type = FlowActionType.SET_META
> +
> +    test_case = {
> +         'test_data': ('ingress pattern eth / ipv4 src is 192.168.0.1 '
> +                       '/ udp / end actions set_meta data 0xabc / end',
> +                       frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' *
> 64)"}),
> +                       frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' *
> 64)",
> +                                  "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)",
> +                                  "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)",
> +                                  "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)"})),
> +         # bit-mask applies to "data"
> +         'test_mask': ('ingress pattern eth / ipv4 src is 192.168.0.1 '
> +                       '/ udp / end actions set_meta data 0xabc mask 0xcb / end',
> +                       frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' *
> 64)"}),
> +                       frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' *
> 64)",
> +                                  "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\x00' * 64)",
> +                                  "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\x00' * 64)",
> +                                  "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)"})),
> +    }
> +
> +
> +class FlowActionSet_ipv4_dscp(ActionFlowItem):
> +    type = FlowActionType.SET_IPV4_DSCP
> +
> +    test_case = {
> +         'test': ('ingress pattern eth / ipv4 src is 192.168.0.1 '
> +                  '/ udp / end actions set_ipv4_dscp dscp 2 / end',
> +                  frozenset({"Ether() / IP(src=\"192.168.0.1\", tos = 0) / UDP() / ('\\x00'
> * 64)"}),
> +                  frozenset({"Ether() / IP(src=\"192.168.0.2\", tos = 0) / UDP() / ('\\x00'
> * 64)",
> +                             "Ether() / IP(src=\"10.0.30.99\", tos = 0) / UDP() / ('\x00' * 64)",
> +                             "Ether() / IP(src=\"8.8.8.8\", tos = 0) / UDP() / ('\x00' * 64)",
> +                             "Ether() / IP(src=\"132.177.0.99\", tos = 0) / UDP() / ('\\x00' *
> 64)"})),
> +    }
> +
> +
> +class FlowActionSet_ipv6_dscp(ActionFlowItem):
> +    type = FlowActionType.SET_IPV6_DSCP
> +
> +    test_case = {
> +         'test': ('ingress pattern eth / ipv6 src is
> 2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c2 '
> +                  '/ udp / end actions set_ipv6_dscp dscp 0x30',
> +                  frozenset({"Ether() /
> IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c2\", tc = 0) "
> +                             "/ UDP() / ('\\x00' * 64)"}),
> +                  frozenset({"Ether() /
> IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c3\", tc = 0) "
> +                             "/ UDP() / ('\\x00' * 64)",
> +                            "Ether() /
> IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c4\", tc = 0) "
> +                             "/ UDP() / ('\x00' * 64)",
> +                             "Ether() /
> IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c5\", tc = 0) "
> +                             "/ UDP() / ('\x00' * 64)",
> +                             "Ether() /
> IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c6\", tc = 0) "
> +                             "/ UDP() / ('\\x00' * 64)"})),
> +     }
> +
> +
> +class FlowActionAge(ActionFlowItem):
> +    type = FlowActionType.AGE
> +
> +    test_case = {
> +         'test_timeout': ('ingress pattern eth / ipv4 src is 192.168.0.1 '
> +                          '/ udp / end actions age timeout 128 / end',
> +                          frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' *
> 64)"}),
> +                          frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' *
> 64)",
> +                                     "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\x00' * 64)",
> +                                     "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\x00' * 64)",
> +                                     "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' *
> 64)"})),
> +         # 8 bits reserved, must be zero
> +         'test_reserved': ('ingress pattern eth / ipv4 src is 192.168.0.1 '
> +                           '/ udp / end actions age timeout 128 reserved 0 / end',
> +                           frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' *
> 64)"}),
> +                           frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' *
> 64)",
> +                                      "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\x00' * 64)",
> +                                      "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\x00' * 64)",
> +                                      "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' *
> 64)"})),
> +         # The user flow context, NULL means the rte_flow pointer.
> +         'test_context': ('ingress pattern eth / ipv4 src is 192.168.0.1 '
> +                          '/ udp / end actions age timeout 128 context NULL / end',
> +                          frozenset({"Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' *
> 64)"}),
> +                          frozenset({"Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' *
> 64)",
> +                                    "Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)",
> +                                     "Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)",
> +                                     "Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' *
> 64)"})),
> +
> +    }
> +
> +
> +ACTION_ITEMS_TYPE_CLASS_MAPPING: Dict[FlowActionType, ActionFlowItem]
> = {
> +    FlowActionType.PASSTHRU: FlowActionPassthru,
> +    FlowActionType.FLAG: FlowActionFlag,
> +    FlowActionType.DROP: FlowActionDrop,
> +    FlowActionType.COUNT: FlowActionCount,
> +    FlowActionType.MAC_SWAP: FlowActionMac_swap,
> +    FlowActionType.DEC_TTL: FlowActionDec_ttl,
> +    FlowActionType.JUMP: FlowActionJump,
> +    FlowActionType.MARK: FlowActionMark,
> +    FlowActionType.QUEUE: FlowActionQueue,
> +    FlowActionType.RSS: FlowActionRss,
> +    FlowActionType.PF: FlowActionPf,
> +    FlowActionType.VF: FlowActionVf,
> +    FlowActionType.PHY_PORT: FlowActionPhy_port,
> +    FlowActionType.PORT_ID: FlowActionPort_id,
> +    FlowActionType.METER: FlowActionMeter,
> +    FlowActionType.SECURITY: FlowActionSecurity,
> +    FlowActionType.OF_SET_MPLS_TTL: FlowActionOf_set_mpls_ttl,
> +    FlowActionType.OF_DEC_MPLS_TTL: FlowActionOf_dec_mpls_ttl,
> +    FlowActionType.OF_SET_NW_TTL: FlowActionOf_set_nw_ttl,
> +    FlowActionType.OF_DEC_NW_TTL: FlowActionOf_dec_nw_ttl,
> +    FlowActionType.OF_COPY_TTL_OUT: FlowActionOf_copy_ttl_out,
> +    FlowActionType.OF_COPY_TTL_IN: FlowActionOf_copy_ttl_in,
> +    FlowActionType.OF_POP_VLAN: FlowActionOf_pop_vlan,
> +    FlowActionType.OF_PUSH_VLAN: FlowActionOf_push_vlan,
> +    FlowActionType.OF_SET_VLAN_VID: FlowActionOf_set_vlan_vid,
> +    FlowActionType.OF_SET_VLAN_PCP: FlowActionOf_set_vlan_pcp,
> +    FlowActionType.OF_POP_MPLS: FlowActionOf_pop_mpls,
> +    FlowActionType.OF_PUSH_MPLS: FlowActionOf_push_mpls,
> +    FlowActionType.VXLAN_ENCAP: FlowActionVxlan_encap,
> +    FlowActionType.VXLAN_DECAP: FlowActionVxlan_decap,
> +    FlowActionType.NVGRE_ENCAP: FlowActionNvgre_encap,
> +    FlowActionType.NVGRE_DECAP: FlowActionNvgre_decap,
> +    FlowActionType.RAW_ENCAP: FlowActionRaw_encap,
> +    FlowActionType.RAW_DECAP: FlowActionRaw_decap,
> +    FlowActionType.SET_IPV4_SRC: FlowActionSet_ipv4_src,
> +    FlowActionType.SET_IPV4_DST: FlowActionSet_ipv4_dst,
> +    FlowActionType.SET_IPV6_SRC: FlowActionSet_ipv6_src,
> +    FlowActionType.SET_IPV6_DST: FlowActionSet_ipv6_dst,
> +    FlowActionType.SET_TP_SRC: FlowActionSet_tp_src,
> +    FlowActionType.SET_TP_DST: FlowActionSet_tp_dst,
> +    FlowActionType.SET_TTL: FlowActionSet_ttl,
> +    FlowActionType.SET_MAC_SRC: FlowActionSet_mac_src,
> +    FlowActionType.SET_MAC_DST: FlowActionSet_mac_dst,
> +    FlowActionType.INC_TCP_SEQ: FlowActionInc_tcp_seq,
> +    FlowActionType.DEC_TCP_SEQ: FlowActionDec_tcp_seq,
> +    FlowActionType.INC_TCP_ACK: FlowActionInc_tcp_ack,
> +    FlowActionType.DEC_TCP_ACK: FlowActionDec_tcp_ack,
> +    FlowActionType.SET_TAG: FlowActionSet_tag,
> +    FlowActionType.SET_META: FlowActionSet_meta,
> +    FlowActionType.SET_IPV4_DSCP: FlowActionSet_ipv4_dscp,
> +    FlowActionType.SET_IPV6_DSCP: FlowActionSet_ipv6_dscp,
> +    FlowActionType.AGE: FlowActionAge
> +}
> diff --git a/framework/flow/flow_items.py b/framework/flow/flow_items.py
> new file mode 100644
> index 00000000..ed5e8d9c
> --- /dev/null
> +++ b/framework/flow/flow_items.py
> @@ -0,0 +1,84 @@
> +from __future__ import annotations
> +
> +import copy
> +import itertools
> +from functools import reduce
> +from typing import FrozenSet, Union, Any, Set, Dict, Tuple, Iterable, Hashable
> +
> +from framework.flow.enums import FlowItemType, FlowActionType
> +from framework.flow.exceptions import InvalidFlowItemException
> +from framework.flow import flow_action_items
> +from framework.flow import flow_pattern_items
> +
> +PATTERN_ACTION_ITEMS = {FlowItemType.INVERT, FlowItemType.VOID,
> FlowItemType.MARK, FlowItemType.META}
> +
> +
> +class FlowItem(object):
> +    type: Union[FlowItemType, FlowActionType]
> +    # Defines what items this may not appear with
> +    allowed_with: FrozenSet[Union[FlowItemType, FlowActionType]]
> +    # OSI Model layer of the protocol
> +    # This should be the lowest layer a protocol is used in, for example
> +    # QUIC would be considered L5 since it needs to go after UDP (L4),
> +    # even though it has capabilities in L6.
> +    layer: int
> +    valid_next_items: FrozenSet[Union[FlowItemType, FlowActionType]]
> +
> +    # Types subject to change, should only be accessed through
> +    possible_properties: Dict[str, Tuple[str, FrozenSet[str], FrozenSet[str]]]
> +    properties: str
> +
> +    def get_property_stream(self) -> Iterable[Tuple[FlowItem, FrozenSet[str],
> FrozenSet[str], str]]:
> +        """
> +        This function will return a generator that will provide all
> +        configured property combinations.
> +
> +        This function will not mutate the instance it is called on.
> +
> +        @return: a generator that will provide all
> +        permutations of possible properties this object has as a flow
> +        item with properties
> +        """
> +        base_copy = copy.deepcopy(self)
> +        for key, value in self.possible_properties.items():
> +            new_copy = copy.deepcopy(base_copy)
> +            new_copy.properties = value[0]  # The properties string
> +            yield new_copy, *value[1:], f"{self.type.value}_{key}"
> +
> +    def __init__(self):
> +        self.properties = ""
> +
> +    def __truediv__(self, other: FlowItem):
> +        """
> +        Used in a similar way to scapy's packet composition.
> +        @param other: The other flow item.
> +        @return: A Flow containing both items
> +        """
> +        if type(self) != type(other):
> +            raise InvalidFlowItemException(self, other)
> +        elif other.type in self.valid_next_items:
> +            # This import is in here so there is no circular import
> +            from framework.flow.flow import Flow
> +            if isinstance(self, flow_pattern_items.PatternFlowItem):
> +                return Flow(pattern_items=[self, other])
> +            elif isinstance(self, flow_action_items.ActionFlowItem):
> +                return Flow(action_items=[self, other])
> +            else:
> +                raise TypeError(
> +                    f"{type(self):s} is not one of
> {flow_pattern_items.PatternFlowItem:s},
> {flow_action_items.ActionFlowItem:s}.")
> +        else:
> +            raise InvalidFlowItemException(self, other)
> +
> +    def __eq__(self, other) -> bool:
> +        return type(self) == type(other) and \
> +               self.type == other.type and \
> +               self.properties == other.properties
> +
> +    def __str__(self):
> +        if self.properties != "":
> +            return self.properties
> +        else:
> +            return self.type.value
> +
> +    def __repr__(self):
> +        return str(self)
> diff --git a/framework/flow/flow_pattern_items.py
> b/framework/flow/flow_pattern_items.py
> new file mode 100644
> index 00000000..77e2de0d
> --- /dev/null
> +++ b/framework/flow/flow_pattern_items.py
> @@ -0,0 +1,1076 @@
> +# Allows the type system to handle referencing a class inside it's definition
> +from typing import FrozenSet, Dict, List, Tuple, Iterable
> +
> +from scapy.layers.inet import UDP, TCP, IP, ICMP
> +from scapy.layers.inet6 import IPv6
> +from scapy.layers.l2 import Ether, Dot1Q, GRE, ARP
> +from scapy.layers.sctp import SCTP
> +from scapy.layers.vxlan import VXLAN
> +from scapy.packet import Packet
> +
> +from framework.flow.enums import FlowItemType
> +from framework.flow.exceptions import InvalidFlowItemException
> +from framework.flow.flow_items import FlowItem
> +
> +ALWAYS_ALLOWED_ITEMS = {
> +    FlowItemType.RAW,
> +    FlowItemType.VOID
> +}
> +L3_FLOW_TYPES = {FlowItemType.IPV4, FlowItemType.IPV6}
> +L4_FLOW_ITEMS = {FlowItemType.UDP, FlowItemType.TCP,
> FlowItemType.SCTP, FlowItemType.GRE, }
> +
> +PATTERN_OPERATION_TYPES = {
> +    FlowItemType.MARK,
> +    FlowItemType.META,
> +    FlowItemType.TAG,
> +    FlowItemType.FUZZY,
> +    FlowItemType.INVERT,
> +}
> +
> +TUNNELING_PROTOCOL_TYPES = {
> +    FlowItemType.VLAN,
> +    FlowItemType.VXLAN,
> +    FlowItemType.GRE,
> +    FlowItemType.VXLAN_GPE
> +}
> +
> +
> +class PatternFlowItem(FlowItem):
> +    allowed_with: FrozenSet[FlowItemType] = \
> +        frozenset({item for item in FlowItemType})
> +
> +    valid_next_items: List[FlowItemType] = \
> +        [item for item in FlowItemType]
> +
> +    # Only used for building a tree upward
> +    valid_parent_items: List[FlowItemType] = \
> +        [item for item in FlowItemType]
> +
> +    possible_properties: List[Tuple[str, Iterable, Iterable]] = {}
> +
> +    def __truediv__(self, other: FlowItem):
> +        """
> +        Used in a similar way to scapy's packet composition.
> +        @param other: The other flow item.
> +        @return: A Flow containing both items
> +        """
> +        if other.type in self.valid_next_items or \
> +                other.type == FlowItemType.END:
> +            # This import is in here so there is no circular import
> +            from framework.flow.flow import Flow
> +            return Flow(pattern_items=[self, other])
> +        else:
> +            raise InvalidFlowItemException(self, other)
> +
> +    # def to_scapy_packet(self):
> +    #    scapy_class: type = ITEM_TYPE_SCAPY_CLASS_MAPPING[self.type]
> +
> +
> +class FlowItemEnd(PatternFlowItem):
> +    type = FlowItemType.END
> +    valid_next_items = list({})
> +
> +
> +class FlowItemVoid(PatternFlowItem):
> +    type = FlowItemType.VOID
> +
> +
> +class FlowItemInvert(PatternFlowItem):
> +    type = FlowItemType.INVERT
> +
> +
> +class FlowItemAny(PatternFlowItem):
> +    type = FlowItemType.ANY
> +
> +
> +class FlowItemRaw(PatternFlowItem):
> +    type = FlowItemType.RAW
> +
> +
> +class FlowItemArp_eth_ipv4(PatternFlowItem):
> +    type = FlowItemType.ARP_ETH_IPV4
> +    valid_next_items = list({FlowItemType.RAW, FlowItemType.VOID})
> +    valid_parent_items: List[FlowItemType] = [FlowItemType.IPV4]
> +    """
> +    - ``hdr``: hardware type, normally 1. => hwtype
> +    - ``pro``: protocol type, normally 0x0800. => ptype = 2048
> +    - ``hln``: hardware address length, normally 6. => hwlen
> +    - ``pln``: protocol address length, normally 4. => plen
> +    - ``op``: opcode (1 for request, 2 for reply). => op
> +    - ``sha``: sender hardware address. => hwsrc
> +    - ``spa``: sender IPv4 address => psrc
> +    - ``tha``: target hardware address. => hwdst
> +    - ``tpa``: target IPv4 address. => pdst
> +    - Default ``mask`` matches SHA, SPA, THA and TPA.
> +    """
> +    possible_properties = {
> +        'hdr':
> +            ('arp_eth_ipv4 hdr is 1',
> +             frozenset({"Ether() / ARP(hwtype=1) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / ARP(hwtype=2) / ('\\x00' * 64)",
> +                        "Ether() / ARP(hwtype=3) / ('\\x00' * 64)",
> +                        "Ether() / ARP(hwtype=6) / ('\\x00' * 64)",
> +                        "Ether() / ARP(hwtype-15) / ('\\x00' * 64)"
> +                        })),
> +        'pro':
> +            ('arp_eth_ipv4 pro is 0x0800',
> +             frozenset({"Ether() / ARP(ptype=0x0800) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / ARP(ptype=0x0800) / ('\\x00' * 64)",
> +                        "Ether() / ARP(ptype=0x0842) / ('\\x00' * 64)",
> +                        "Ether() / ARP(ptype=0x6004) / ('\\x00' * 64)",
> +                        "Ether() / ARP(ptype=0x809b) / ('\\x00' * 64)"
> +                        })),
> +
> +        'hln':
> +            ('arp_eth_ipv4 hln is 6',
> +             frozenset({"Ether() / ARP(hwlen=6) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / ARP(hwlen=12) / ('\\x00' * 64)",
> +                        "Ether() / ARP(hwlen=2) / ('\\x00' * 64)",
> +                        "Ether() / ARP(hwlen=8) / ('\\x00' * 64)",
> +                        "Ether() / ARP(hwlen=4) / ('\\x00' * 64)"
> +                        })),
> +
> +        'pln':
> +            ('arp_eth_ipv4 pln is 4',
> +             frozenset({"Ether() / ARP(plen=4) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / ARP(plen=6) / ('\\x00' * 64)",
> +                        "Ether() / ARP(plen=2) / ('\\x00' * 64)",
> +                        "Ether() / ARP(plen=8) / ('\\x00' * 64)",
> +                        "Ether() / ARP(plen=12) / ('\\x00' * 64)"
> +                        })),
> +
> +        'op':
> +            ('arp_eth_ipv4 op is 1',
> +             frozenset({"Ether() / ARP(op=1) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / ARP(op=2) / ('\\x00' * 64)",
> +                        "Ether() / ARP(op=3) / ('\\x00' * 64)",
> +                        "Ether() / ARP(op=4) / ('\\x00' * 64)",
> +                        "Ether() / ARP(op=5) / ('\\x00' * 64)"
> +                        })),
> +
> +        'sha':
> +            ('arp_eth_ipv4 sha is 90:61:ae:fd:41:43',
> +             frozenset({"Ether() / ARP(hwsrc=\"90:61:ae:fd:41:43\") / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / ARP(hwsrc=\"90:61:ae:fd:41:44\") / ('\\x00' * 64)",
> +                        "Ether() / ARP(hwsrc=\"90:61:ae:fd:41:45\") / ('\\x00' * 64)",
> +                        "Ether() / ARP(hwsrc=\"90:61:ae:fd:41:46\") / ('\\x00' * 64)",
> +                        "Ether() / ARP(hwsrc=\"90:61:ae:fd:41:47\") / ('\\x00' * 64)"
> +                        })),
> +
> +        'spa':
> +            ('arp_eth_ipv4 spa is 192.168.0.80',
> +             frozenset({"Ether() / ARP(psrc=\"192.168.0.80\") / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / ARP(psrc=\"10.0.30.10\") / ('\\x00' * 64)",
> +                        "Ether() / ARP(psrc=\"8.8.8.8\") / ('\\x00' * 64)",
> +                        "Ether() / ARP(psrc=\"132.177.0.5\") / ('\\x00' * 64)",
> +                        "Ether() / ARP(psrc=\"123.4.5.6\") / ('\\x00' * 64)"
> +                        })),
> +        'tha':
> +            ('arp_eth_ipv4 tha is 00:00:00:00:00:00',
> +             frozenset({"Ether() / ARP(hwdst=00:00:00:00:00:00) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / ARP(hwdst=90:61:ae:fd:41:45) / ('\\x00' * 64)",
> +                        "Ether() / ARP(hwdst=90:61:ae:fd:41:46) / ('\\x00' * 64)",
> +                        "Ether() / ARP(hwdst=90:61:ae:fd:41:47) / ('\\x00' * 64)",
> +                        "Ether() / ARP(hwdst=90:61:ae:fd:41:48) / ('\\x00' * 64)"
> +                        })),
> +
> +        'tpa':
> +            ('arp_eth_ipv4 tpa is 192.168.0.1',
> +             frozenset({"Ether() / ARP(pdst=192.168.0.1) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / ARP(pdst=10.0.30.10) / ('\\x00' * 64)",
> +                        "Ether() / ARP(pdst=8.8.8.8) / ('\\x00' * 64)",
> +                        "Ether() / ARP(pdst=132.177.0.5) / ('\\x00' * 64)",
> +                        "Ether() / ARP(pdst=123.4.5.6) / ('\\x00' * 64)"
> +                        })),
> +
> +    }
> +
> +
> +class FlowItemEth(PatternFlowItem):
> +    type = FlowItemType.ETH
> +    valid_next_items = list(ALWAYS_ALLOWED_ITEMS | L3_FLOW_TYPES |
> {FlowItemType.VLAN, FlowItemType.ARP_ETH_IPV4})
> +    valid_parent_items: List[FlowItemType] = list({})
> +    # Matches an Ethernet header (not Ethernet frame).
> +
> +    """
> +    - ``dst``: destination MAC.
> +    - ``src``: source MAC.
> +    - ``type``: EtherType or TPID. (TPID value is 0x8100, any others are normal
> EtherType)
> +    - Default ``mask`` matches destination and source addresses only.
> +    """
> +    possible_properties = {
> +        'dst':
> +            ('eth dst is 90:61:ae:fd:41:43',
> +             frozenset({"Ether(dst=\"90:61:ae:fd:41:43\") / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether(dst=\"90:61:ae:fd:41:44\") / ('\\x00' * 64)",
> +                        "Ether(dst=\"90:61:ae:fd:41:45\") / ('\\x00' * 64)",
> +                        "Ether(dst=\"90:61:ae:fd:41:46\") / ('\\x00' * 64)",
> +                        "Ether(dst=\"91:61:ae:fd:41:43\") / ('\\x00' * 64)"
> +                        })),
> +        'src':
> +            ('eth src is 90:61:ae:fd:41:43',
> +             frozenset({"Ether(src=\"90:61:ae:fd:41:43\") / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether(src=\"90:61:ae:fd:41:44\") / ('\\x00' * 64)",
> +                        "Ether(src=\"90:61:ae:fd:41:45\") / ('\\x00' * 64)",
> +                        "Ether(src=\"90:61:ae:fd:41:46\") / ('\\x00' * 64)",
> +                        "Ether(src=\"91:61:ae:fd:41:43\") / ('\\x00' * 64)"
> +                        })),
> +        'type':
> +            ('eth type is 0x0800',  # IPv4 EtherType
> +             frozenset({"Ether(type=0x0800) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether(type=0x0842) / ('\\x00' * 64)",
> +                        "Ether(type=0x8100) / ('\\x00' * 64)",  # Possibly a special case?
> TPID/VLAN
> +                        "Ether(type=0x9100) / ('\\x00' * 64)",  # Possibly special, VLAN
> double tagging
> +                        "Ether(type=0x8863) / ('\\x00' * 64)",
> +                        "Ether(type=0x9000) / ('\\x00' * 64)"
> +                        })),
> +    }
> +
> +
> +class FlowItemGre(PatternFlowItem):
> +    type = FlowItemType.GRE
> +    valid_next_items = list(L3_FLOW_TYPES | ALWAYS_ALLOWED_ITEMS)
> +    valid_parent_items: List[FlowItemType] = [FlowItemType.IPV4,
> FlowItemType.IPV6]
> +    """
> +    - ``c_rsvd0_ver``: checksum, reserved 0 and version.
> +    - ``protocol``: protocol type.
> +    - Default ``mask`` matches protocol only.
> +    """
> +    possible_properties = {
> +        'c_rsvd0_ver':
> +           ('gre c_rsvd0_ver is 0',
> +            frozenset({"Ether() / GRE(chksum_present=0, version=0) / ('\\x00' *
> 64)"}),
> +
> +           frozenset({"Ether() / GRE(chksum_present=1, version=0)) / ('\\x00' * 64)",
> #this is the only other option
> +                      })),
> +        'protocol':
> +            ('gre protocol is 0x0800',
> +             frozenset({"Ether() / GRE(proto=0x0800) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / GRE(proto=0x0842) / ('\\x00' * 64)",
> +                        "Ether() / GRE(proto=0x8100) / ('\\x00' * 64)",
> +                        "Ether() / GRE(proto=0x0806) / ('\\x00' * 64)",
> +                        "Ether() / GRE(proto=0x809B) / ('\\x00' * 64)"
> +                        }))
> +    }
> +
> +
> +class FlowItemIcmp(PatternFlowItem):
> +    type = FlowItemType.ICMP
> +    valid_next_items = list({FlowItemType.RAW, FlowItemType.VOID})
> +    valid_parent_items: List[FlowItemType] = [FlowItemType.IPV4]
> +    """
> +    - ``hdr``: ICMP header definition (``rte_icmp.h``).
> +    This definition includes:
> +    icmp_type (8 bits; for IPv4 echo request it's "8")
> +    icmp_code (8 bits)
> +
> +    THE FOLLOWING ARE NOT SUPPORTED IN TESTPMD:
> +    icmp_cksum (16 bits)
> +    icmp_ident (16 bits)
> +    icmp_seq_nb (16 bits)
> +    - Default ``mask`` matches ICMP type and code only.
> +    """
> +    possible_properties = {
> +
> +        'icmp_type':
> +            ('icmp type is 3',
> +             frozenset({"Ether() / ICMP(type=3) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / ICMP(type=3) / ('\\x00' * 64)",
> +                        "Ether() / ICMP(type=11) / ('\\x00' * 64)",
> +                        "Ether() / ICMP(type=13) / ('\\x00' * 64)",
> +                        "Ether() / ICMP(type=0) / ('\\x00' * 64)"
> +                        })),
> +        'icmp_code':
> +            ('icmp type is 3 code is 3',  # Assume type 3 code 3; code
> meanings/options are dependent on type.
> +
> +             frozenset({"Ether() / ICMP(type=3, code=3) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / ICMP(type=3, code=0) / ('\\x00' * 64)",
> +                        "Ether() / ICMP(type=3, code=2) / ('\\x00' * 64)",
> +                        "Ether() / ICMP(type=11, code=1) / ('\\x00' * 64)",
> +                        "Ether() / ICMP(type=12, code=2) / ('\\x00' * 64)"
> +                        })),
> +        'icmp_cksum':
> +           ('icmp cksum is 0x0800',
> +            frozenset({"Ether() / ICMP() / UDP() / ('\x00' * 64)"}),
> +
> +            frozenset({"Ether() / ICMP() / UDP() / ('\x00' * 64)",
> +                       "Ether() / ICMP() / UDP() / ('\x00' * 64)",
> +                       "Ether() / ICMP() / UDP() / ('\x00' * 64)",
> +                       "Ether() / ICMP() / UDP() / ('\x00' * 64)"
> +                       })),
> +        'icmp_ident':
> +           ('icmp ident is 0x0800',
> +            frozenset({"Ether() / ICMP() / UDP() / ('\x00' * 64)"}),
> +
> +            frozenset({"Ether() / ICMP() / UDP() / ('\x00' * 64)",
> +                       "Ether() / ICMP() / UDP() / ('\x00' * 64)",
> +                       "Ether() / ICMP() / UDP() / ('\x00' * 64)",
> +                       "Ether() / ICMP() / UDP() / ('\x00' * 64)"
> +                       })),
> +        'icmp_seq_nb':
> +           ('icmp seq_nb is 0x0800',
> +            frozenset({"Ether() / ICMP(proto=0x0800) / UDP() / ('\x00' * 64)"}),
> +
> +            frozenset({"Ether() / ICMP() / UDP() / ('\x00' * 64)",
> +                       "Ether() / ICMP() / UDP() / ('\x00' * 64)",
> +                       "Ether() / ICMP() / UDP() / ('\x00' * 64)",
> +                       "Ether() / ICMP() / UDP() / ('\x00' * 64)"
> +                        })),
> +    }
> +
> +
> +class FlowItemIcmp6(PatternFlowItem):
> +    type = FlowItemType.ICMP6
> +    valid_next_items = list({FlowItemType.RAW, FlowItemType.VOID})
> +    valid_parent_items: List[FlowItemType] = [FlowItemType.IPV6]
> +    """
> +    - ``type``: ICMPv6 type.
> +    - ``code``: ICMPv6 code.
> +    - ``checksum``: ICMPv6 checksum.
> +    - Default ``mask`` matches ``type`` and ``code``.
> +    """
> +    # ICMP6 NOT SUPPORTED BY TESTPMD.
> +    # DO NOT UNCOMMENT THE FOLLOWING TEST CASES UNTIL IT IS
> SUPPORTED.
> +    possible_properties = {
> +        'type':
> +            ('icmp6 type is 1',  # Destination Unreachable
> +             frozenset({"Ether() / ICMPv6DestUnreach(type=1) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / ICMPv6DestUnreach(type=128) / ('\\x00' * 64)",
> +                        "Ether() / ICMPv6DestUnreach(type=129) / ('\\x00' * 64)",
> +                        "Ether() / ICMPv6DestUnreach(type=3) / ('\\x00' * 64)",
> +                        "Ether() / ICMPv6DestUnreach(type=135) / ('\\x00' * 64)"
> +                        })),
> +        'code':  # ICMP code is dependent on type; these are possible Destination
> Unreachable codes
> +            ('icmp6 code is 0',
> +             frozenset({"Ether() / ICMPv6DestUnreach(code=0) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / ICMPv6DestUnreach(code=1) / ('\\x00' * 64)",
> +                        "Ether() / ICMPv6DestUnreach(code=2) / ('\\x00' * 64)",
> +                        "Ether() / ICMPv6DestUnreach(code=3) / ('\\x00' * 64)",
> +                        "Ether() / ICMPv6DestUnreach(code=4) / ('\\x00' * 64)"
> +                        })),
> +
> +        'checksum':
> +            ('icmp6 cksum is 0x1234',
> +             frozenset({"Ether() / ICMPv6DestUnreach(cksum=0x1234) / ('\\x00' *
> 64)"}),
> +
> +             frozenset({"Ether() / ICMPv6DestUnreach(cksum=0x4321) / ('\\x00' *
> 64)",
> +                        "Ether() / ICMPv6DestUnreach(cksum=0xffff) / ('\\x00' * 64)",
> +                        "Ether() / ICMPv6DestUnreach(cksum=0x1233) / ('\\x00' * 64)",
> +                        "Ether() / ICMPv6DestUnreach(cksum=0x1010) / ('\\x00' * 64)"
> +                        })),
> +    }
> +
> +
> +class FlowItemIpv4(PatternFlowItem):
> +    type = FlowItemType.IPV4
> +    valid_next_items = list(L4_FLOW_ITEMS | {FlowItemType.ICMP} |
> ALWAYS_ALLOWED_ITEMS)
> +    valid_parent_items: List[FlowItemType] = [FlowItemType.ETH,
> FlowItemType.GRE]
> +    """
> +    Note: IPv4 options are handled by dedicated pattern items.
> +
> +    - ``hdr``: IPv4 header definition (``rte_ip.h``).
> +    - Default ``mask`` matches source and destination addresses only.
> +    """
> +
> +    possible_properties = {
> +
> +        'tos':
> +            ('ipv4 tos is 0',
> +             frozenset({"Ether() / IP(tos=0) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / IP(tos=2) / ('\\x00' * 64)",
> +                        "Ether() / IP(tos=4) / ('\\x00' * 64)",
> +                        "Ether() / IP(tos=8) / ('\\x00' * 64)",
> +                        "Ether() / IP(tos=16) / ('\\x00' * 64)"
> +                        })),
> +        'ttl':
> +            ('ipv4 ttl is 64',
> +             frozenset({"Ether() / IP(ttl=64) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / IP(ttl=128) / ('\\x00' * 64)",
> +                        "Ether() / IP(ttl=255) / ('\\x00' * 64)",
> +                        "Ether() / IP(ttl=32)  / ('\\x00' * 64)",
> +                        "Ether() / IP(ttl=100) / ('\\x00' * 64)"
> +                        })),
> +        'proto':
> +            ('ipv4 proto is 0x06',  # TCP
> +             frozenset({"Ether() / IP(proto=0x06) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / IP(proto=0x01) / ('\\x00' * 64)",
> +                        "Ether() / IP(proto=0x11) / ('\\x00' * 64)",
> +                        "Ether() / IP(proto=0x12) / ('\\x00' * 64)",
> +                        "Ether() / IP(proto=0x58) / ('\\x00' * 64)"
> +                        })),
> +        'src':
> +            ('ipv4 src is 192.168.0.5',
> +             frozenset({"Ether() / IP(src=\"192.168.0.5\") / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / IP(src=\"10.10.10.10\") / ('\\x00' * 64)",
> +                        "Ether() / IP(src=\"132.177.127.6\") / ('\\x00' * 64)",
> +                        "Ether() / IP(src=\"192.168.0.4\") / ('\\x00' * 64)",
> +                        "Ether() / IP(src=\"192.168.0.250\") / ('\\x00' * 64)"
> +                        })),
> +        'dst':
> +            ('ipv4 dst is 192.168.0.5',
> +             frozenset({"Ether() / IP(dst=\"192.168.0.5\") / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / IP(dst=\"10.10.10.10\") / ('\\x00' * 64)",
> +                        "Ether() / IP(dst=\"132.177.127.6\") / ('\\x00' * 64)",
> +                        "Ether() / IP(dst=\"192.168.0.4\") / ('\\x00' * 64)",
> +                        "Ether() / IP(dst=\"192.168.0.250\") / ('\\x00' * 64)"
> +                        })),
> +        # CHECKSUM PROPERTY NOT SUPPORTED BY TESTPMD; DO NOT
> UNCOMMENT UNTIL SUPPORTED
> +        # 'checksum':
> +        #     ('ipv4 chksum is 0x1234',
> +        #     frozenset({"Ether() / ICMPv6DestUnreach(cksum=0x1234) / ('\\x00' *
> 64)"}),
> +
> +        #     frozenset({"Ether() / ICMPv6DestUnreach(cksum=0x4321) / ('\\x00' *
> 64)",
> +        #                "Ether() / ICMPv6DestUnreach(cksum=0xffff) / ('\\x00' * 64)",
> +        #                "Ether() / ICMPv6DestUnreach(cksum=0x1233) / ('\\x00' * 64)",
> +        #                "Ether() / ICMPv6DestUnreach(cksum=0x1010) / ('\\x00' * 64)"
> +        #                })),
> +
> +
> #################################################################
> #########
> +    }
> +
> +
> +class FlowItemIpv6(PatternFlowItem):
> +    type = FlowItemType.IPV6
> +    valid_next_items = list(L4_FLOW_ITEMS | {FlowItemType.ICMP6} |
> ALWAYS_ALLOWED_ITEMS)
> +    valid_parent_items: List[FlowItemType] = [FlowItemType.ETH,
> FlowItemType.GRE]
> +    """
> +    Note: IPv6 options are handled by dedicated pattern items, see `Item:
> +    IPV6_EXT`_.
> +
> +    - ``hdr``: IPv6 header definition (``rte_ip.h``).
> +    - Default ``mask`` matches source and destination addresses only.
> +    """
> +
> +    possible_properties = {
> +        # THE FOLLOWING PROPERTIES ARE UNSUPPORTED BY TESTPMD AT THE
> TIME OF WRITING.
> +        # They are still tested to future proof this test suite.
> +        'vtc_flow':
> +            ('ipv6 vtc_flow is 0x0',
> +             frozenset({"Ether() / IPv6(tc=0, fl=0, version=0) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / IPv6(tc=1, fl=0, version=0) / ('\\x00' * 64)",
> +                        "Ether() / IPv6(tc=0, fl=0xABCD, version=0) / ('\\x00' * 64)",
> +                        "Ether() / IPv6(tc=0, fl=0, version=1) / ('\\x00' * 64)",
> +                        "Ether() / IPv6(tc=6, fl=0x9999, version=1) / ('\\x00' * 64)"
> +                        })),
> +        'payload_len':
> +            ('ipv6 payload_len is 64',
> +             frozenset({"Ether() / IPv6(plen=64) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / IPv6(plen=32) / ('\\x00' * 64)",
> +                        "Ether() / IPv6(plen=128) / ('\\x00' * 64)",
> +                        "Ether() / IPv6(plen=5000) / ('\\x00' * 64)",
> +                        "Ether() / IPv6(plen=4) / ('\\x00' * 64)"
> +                        })),
> +        # END UNSUPPORTED PROPERTIES
> +        'tc':
> +            ('ipv6 tc is 0',
> +             frozenset({"Ether() / IPv6(tc=0) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / IPv6(tc=1) / ('\\x00' * 64)",
> +                        "Ether() / IPv6(tc=2) / ('\\x00' * 64)",
> +                        "Ether() / IPv6(tc=4) / ('\\x00' * 64)",
> +                        "Ether() / IPv6(tc=6) / ('\\x00' * 64)"
> +                        })),
> +        'flow':
> +            ('ipv6 flow is 0xABCD',
> +             frozenset({"Ether() / IPv6(fl=0xABCD) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / IPv6(fl=0xABCE) / ('\\x00' * 64)",
> +                        "Ether() / IPv6(fl=0x0001) / ('\\x00' * 64)",
> +                        "Ether() / IPv6(fl=0xFFFF) / ('\\x00' * 64)",
> +                        "Ether() / IPv6(fl=0x1234) / ('\\x00' * 64)"
> +                        })),
> +        'proto':  # next header (nh)
> +            ('ipv6 proto is 6',  # TCP
> +             frozenset({"Ether() / IPv6(nh=6) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / IPv6(nh=17) / ('\\x00' * 64)",
> +                        "Ether() / IPv6(nh=41) / ('\\x00' * 64)",
> +                        "Ether() / IPv6(nh=0) / ('\\x00' * 64)",
> +                        "Ether() / IPv6(nh=60) / ('\\x00' * 64)"
> +                        })),
> +        'hop':  # hop limit
> +            ('ipv6 hop is 64',
> +             frozenset({"Ether() / IPv6(hlim=64) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / IPv6(hlim=128) / ('\\x00' * 64)",
> +                        "Ether() / IPv6(hlim=32) / ('\\x00' * 64)",
> +                        "Ether() / IPv6(hlim=255) / ('\\x00' * 64)",
> +                        "Ether() / IPv6(hlim=100) / ('\\x00' * 64)"
> +                        })),
> +        'dst':
> +            ('ipv6 dst is 2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c2',
> +             frozenset({"Ether() /
> IPv6(dst=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c2\") / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() /
> IPv6(dst=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c3\") / ('\\x00' * 64)",
> +                        "Ether() /
> IPv6(dst=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c4\") / ('\\x00' * 64)",
> +                        "Ether() /
> IPv6(dst=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c5\") / ('\\x00' * 64)",
> +                        "Ether() /
> IPv6(dst=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c6\") / ('\\x00' * 64)"
> +                        })),
> +        'src':
> +            ('ipv6 src is 2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c2',
> +             frozenset({"Ether() /
> IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c2\") / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() /
> IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c3\") / ('\\x00' * 64)",
> +                        "Ether() /
> IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c4\") / ('\\x00' * 64)",
> +                        "Ether() /
> IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c5\") / ('\\x00' * 64)",
> +                        "Ether() /
> IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c6\") / ('\\x00' * 64)"
> +                        })),
> +    }
> +
> +
> +class FlowItemSctp(PatternFlowItem):
> +    type = FlowItemType.SCTP
> +    valid_next_items = list(ALWAYS_ALLOWED_ITEMS)
> +    valid_parent_items: List[FlowItemType] = [FlowItemType.IPV4,
> FlowItemType.IPV6]
> +    """
> +
> +    **chunks?
> +
> +    - ``hdr``: SCTP header definition (``rte_sctp.h``).
> +    - Default ``mask`` matches source and destination ports only.
> +    """
> +    possible_properties = {
> +
> +        'src':
> +            ('sctp src is 3838',
> +             frozenset({"Ether() / IP() / SCTP(sport=3838) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / IP() / SCTP(sport=3939) / ('\\x00' * 64)",
> +                        "Ether() / IP() / SCTP(sport=5000) / ('\\x00' * 64)",
> +                        "Ether() / IP() / SCTP(sport=1998) / ('\\x00' * 64)",
> +                        "Ether() / IP() / SCTP(sport=1028) / ('\\x00' * 64)"
> +                        })),
> +
> +        'dst':
> +            ('sctp dst is 3838',
> +             frozenset({"Ether() / IP() / SCTP(dport=3838) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / IP() / SCTP(dport=3939) / ('\\x00' * 64)",
> +                        "Ether() / IP() / SCTP(dport=5000) / ('\\x00' * 64)",
> +                        "Ether() / IP() / SCTP(dport=1998) / ('\\x00' * 64)",
> +                        "Ether() / IP() / SCTP(dport=1028) / ('\\x00' * 64)"
> +                        })),
> +        'tag':
> +            ('sctp tag is 12345',
> +             frozenset({"Ether() / IP() / SCTP(tag=12345) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / IP() / SCTP(tag=12346) / ('\\x00' * 64)",
> +                        "Ether() / IP() / SCTP(tag=12) / ('\\x00' * 64)",
> +                        "Ether() / IP() / SCTP(tag=9999) / ('\\x00' * 64)",
> +                        "Ether() / IP() / SCTP(tag=42) / ('\\x00' * 64)"
> +                        })),
> +
> +        'cksum':
> +            ('sctp cksum is 0x01535b67',
> +             frozenset({"Ether() / IP() / SCTP(chksum=0x01535b67) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / IP() / SCTP(chksum=0x01535b68) / ('\\x00' * 64)",
> +                        "Ether() / IP() / SCTP(chksum=0xdeadbeef) / ('\\x00' * 64)",
> +                        "Ether() / IP() / SCTP(chksum=0x12345678) / ('\\x00' * 64)",
> +                        "Ether() / IP() / SCTP(chksum=0x385030fe) / ('\\x00' * 64)"
> +                        }))
> +    }
> +
> +
> +class FlowItemTcp(PatternFlowItem):
> +    type = FlowItemType.TCP
> +    valid_next_items = list(ALWAYS_ALLOWED_ITEMS)
> +    valid_parent_items: List[FlowItemType] = [FlowItemType.IPV4,
> FlowItemType.IPV6]
> +    """
> +    - ``hdr``: TCP header definition (``rte_tcp.h``).
> +    - Default ``mask`` matches source and destination ports only.
> +
> +    #define 	RTE_TCP_CWR_FLAG   0x80
> +
> +    #define 	RTE_TCP_ECE_FLAG   0x40
> +
> +    #define 	RTE_TCP_URG_FLAG   0x20
> +
> +    #define 	RTE_TCP_ACK_FLAG   0x10
> +
> +    #define 	RTE_TCP_PSH_FLAG   0x08
> +
> +    #define 	RTE_TCP_RST_FLAG   0x04
> +
> +    #define 	RTE_TCP_SYN_FLAG   0x02
> +
> +    #define 	RTE_TCP_FIN_FLAG   0x01
> +
> +    Can we set multiple flags at once in testing (ex. SYN, ACK)?
> +    Probably, and we can definitely test them if necessary.
> +
> +    """
> +    possible_properties = {
> +        # THE FOLLOWING PROPERTIES ARE UNSUPPORTED BY TESTPMD AT THE
> TIME OF WRITING.
> +        # They are still tested to future proof this test suite.
> +        'data_off':
> +            ('tcp data_off is 0',
> +             frozenset({"Ether() / IP() / TCP(dataofs=0) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() /  IP() / TCP(dataofs=1) / ('\\x00' * 64)",
> +                        "Ether() /  IP() / TCP(dataofs=2) / ('\\x00' * 64)",
> +                        "Ether() /  IP() / TCP(dataofs=3) / ('\\x00' * 64)",
> +                        "Ether() /  IP() / TCP(dataofs=4) / ('\\x00' * 64)"
> +                        })),
> +        'rx_win':
> +            ('tcp rx_win is 64',
> +             frozenset({"Ether() /  IP() / TCP(window=64)/ ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() /  IP() / TCP(window=16)/ ('\\x00' * 64)",
> +                        "Ether() /  IP() / TCP(window=128) / ('\\x00' * 64)",
> +                        "Ether() /  IP() / TCP(window=32) / ('\\x00' * 64)",
> +                        "Ether() /  IP() / TCP(window=255) / ('\\x00' * 64)"
> +                        })),
> +        'cksum':
> +            ('tcp cksum is 0x1234',
> +             frozenset({"Ether() /  IP() / TCP(chksum=0x1234) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / IP() / TCP(chksum=0x4321) / ('\\x00' * 64)",
> +                        "Ether() /  IP() / TCP(chksum=0xffff) / ('\\x00' * 64)",
> +                        "Ether() /  IP() / TCP(chksum=0x9999) / ('\\x00' * 64)",
> +                        "Ether() /  IP() / TCP(chksum=0x1233)  / ('\\x00' * 64)"
> +                        })),
> +        # END UNSUPPORTED PROPERTIES
> +        'src':
> +            ('tcp src is 3838',
> +             frozenset({"Ether() / IP() / TCP(sport=3838) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / IP() / TCP(sport=3939) / ('\\x00' * 64)",
> +                        "Ether() / IP() / TCP(sport=5000) / ('\\x00' * 64)",
> +                        "Ether() / IP() / TCP(sport=1998) / ('\\x00' * 64)",
> +                        "Ether() / IP() / TCP(sport=1028) / ('\\x00' * 64)"
> +                        })),
> +
> +        'dst':
> +            ('tcp dst is 3838',
> +             frozenset({"Ether() / IP() / TCP(dport=3838) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / IP() / TCP(dport=3939) / ('\\x00' * 64)",
> +                        "Ether() / IP() / TCP(dport=5000) / ('\\x00' * 64)",
> +                        "Ether() / IP() / TCP(dport=1998) / ('\\x00' * 64)",
> +                        "Ether() / IP() / TCP(dport=1028) / ('\\x00' * 64)"
> +                        })),
> +        'flags':
> +            ('tcp flags is 0x02',
> +             frozenset({"Ether() / IP() / TCP(flags=0x02) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / IP() / TCP(flags=0x01) / ('\\x00' * 64)",
> +                        "Ether() / IP() / TCP(flags=0x04) / ('\\x00' * 64)",
> +                        "Ether() / IP() / TCP(flags=0x08) / ('\\x00' * 64)",
> +                        "Ether() / IP() / TCP(flags=0x10) / ('\\x00' * 64)"
> +                        }))
> +
> +    }
> +
> +
> +class FlowItemUdp(PatternFlowItem):
> +    type = FlowItemType.UDP
> +    valid_next_items = list({FlowItemType.VXLAN, FlowItemType.VXLAN_GPE} |
> ALWAYS_ALLOWED_ITEMS)
> +    valid_parent_items: List[FlowItemType] = [FlowItemType.IPV4,
> FlowItemType.IPV6]
> +    """
> +    - ``hdr``: UDP header definition (``rte_udp.h``).
> +    - Default ``mask`` matches source and destination ports only.
> +    """
> +
> +    possible_properties = {
> +        # THE FOLLOWING PROPERTIES ARE UNSUPPORTED BY TESTPMD AT THE
> TIME OF WRITING.
> +        # They are still tested to future proof this test suite.
> +        'dgram_len':
> +            ('udp dgram_len is 64',
> +             frozenset({"Ether() / IP() / UDP(len=64) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() /  IP() / UDP(len=128) / ('\\x00' * 64)",
> +                        "Ether() /  IP() / UDP(len=32) / ('\\x00' * 64)",
> +                        "Ether() /  IP() / UDP(len=16) / ('\\x00' * 64)",
> +                        "Ether() /  IP() / UDP(len=255) / ('\\x00' * 64)"
> +                        })),
> +        'dgram_cksum':
> +            ('udp dgram_cksum is 0x1234',
> +             frozenset({"Ether() /  IP() / UDP(chksum=0x1234) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / IP() / UDP(chksum=0x4321) / ('\\x00' * 64)",
> +                        "Ether() /  IP() / UDP(chksum=0xffff) / ('\\x00' * 64)",
> +                        "Ether() /  IP() / UDP(chksum=0x9999) / ('\\x00' * 64)",
> +                        "Ether() /  IP() / UDP(chksum=0x1233)  / ('\\x00' * 64)"
> +                        })),
> +        # END UNSUPPORTED PROPERTIES
> +
> +        'src':
> +            ('udp src is 3838',
> +             frozenset({"Ether() / IP() / UDP(sport=3838) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / IP() / UDP(sport=3939) / ('\\x00' * 64)",
> +                        "Ether() / IP() / UDP(sport=5000) / ('\\x00' * 64)",
> +                        "Ether() / IP() / UDP(sport=1998) / ('\\x00' * 64)",
> +                        "Ether() / IP() / UDP(sport=1028) / ('\\x00' * 64)"
> +                        })),
> +
> +        'dst':
> +            ('udp dst is 3838',
> +             frozenset({"Ether() / IP() / UDP(dport=3838) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / IP() / UDP(dport=3939) / ('\\x00' * 64)",
> +                        "Ether() / IP() / UDP(dport=5000) / ('\\x00' * 64)",
> +                        "Ether() / IP() / UDP(dport=1998) / ('\\x00' * 64)",
> +                        "Ether() / IP() / UDP(dport=1028) / ('\\x00' * 64)"
> +                        })),
> +
> +    }
> +
> +
> +class FlowItemVlan(PatternFlowItem):
> +    type = FlowItemType.VLAN
> +    valid_next_items = list(ALWAYS_ALLOWED_ITEMS)
> +    valid_parent_items: List[FlowItemType] = [FlowItemType.ETH]
> +    """
> +    The corresponding standard outer EtherType (TPID) values are
> +    ``RTE_ETHER_TYPE_VLAN`` or ``RTE_ETHER_TYPE_QINQ``. It can be
> overridden by the
> +    preceding pattern item.
> +    If a ``VLAN`` item is present in the pattern, then only tagged packets will
> +    match the pattern.
> +
> +    - ``tci``: tag control information.
> +    - ``inner_type``: inner EtherType or TPID.
> +    - Default ``mask`` matches the VID part of TCI only (lower 12 bits).
> +
> +    tci in testpmd = pcp, dei, and vid, altogether.
> +
> +    pcp in testpmd = prio in scapy
> +    dei in testpmd = id in scapy?
> +    vid in testpmd = vlan in scapy
> +
> +    tpid in testpmd = type in scapy
> +
> +
> +    """
> +    possible_properties = {
> +
> +        'tci':
> +            ('vlan tci is 0xaaaa',
> +             frozenset({"Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) / ('\\x00' *
> 64)"}),
> +
> +             frozenset({"Ether() /  Dot1Q(prio = 0x0, id = 0x1, vlan = 0xbbb) / ('\\x00'
> * 64)",
> +                        "Ether() /  Dot1Q(prio = 0x5, id = 0x0, vlan = 0xccc) / ('\\x00' * 64)",
> +                        "Ether() /  Dot1Q(prio = 0x5, id = 0x1, vlan = 0xaaa) / ('\\x00' *
> 64)",
> +                        "Ether() /  Dot1Q(prio = 0x4, id = 0x0, vlan = 0xaaa) / ('\\x00' *
> 64)"
> +                        })),
> +
> +        'pcp':
> +            ('vlan pcp is 0x0',
> +             frozenset({"Ether() / Dot1Q(prio=0x0) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() /  Dot1Q(prio=0x1) /  ('\\x00' * 64)",
> +                        "Ether() /  Dot1Q(prio=0x2) /  ('\\x00' * 64)",
> +                        "Ether() /  Dot1Q(prio=0x3) / ('\\x00' * 64)",
> +                        "Ether() /  Dot1Q(prio=0x7) / ('\\x00' * 64)"
> +                        })),
> +        'dei':
> +            ('vlan dei is 0',
> +             frozenset({"Ether() / Dot1Q(id=0) /  ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() /  Dot1Q(id=1) / ('\\x00' * 64)"
> +                        })),
> +
> +        'vid':
> +            ('vlan vid is 0xabc',
> +             frozenset({"Ether() / Dot1Q(vlan=0xabc) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() /  Dot1Q(vlan=0xaaa) / ('\\x00' * 64)",
> +                        "Ether() /  Dot1Q(vlan=0x123) / ('\\x00' * 64)",
> +                        "Ether() /  Dot1Q(vlan=0x1f5) / ('\\x00' * 64)",
> +                        "Ether() /  Dot1Q(vlan=0x999) / ('\\x00' * 64)"
> +                        })),
> +
> +        'tpid':
> +            ('vlan tpid is 0x8100',  # standard value
> +             frozenset({"Ether() / Dot1Q(type=0x8100) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() /  Dot1Q(type=0x0800) / ('\\x00' * 64)",
> +                        "Ether() /  Dot1Q(type=0x0842) / ('\\x00' * 64)",
> +                        "Ether() /  Dot1Q(type=0x809b) / ('\\x00' * 64)",
> +                        "Ether() /  Dot1Q(type=0x86dd) / ('\\x00' * 64)"
> +                        })),
> +    }
> +
> +
> +class FlowItemVxlan(PatternFlowItem):
> +    type = FlowItemType.VXLAN
> +    valid_next_items = frozenset({FlowItemType.ETH} |
> ALWAYS_ALLOWED_ITEMS)
> +    valid_parent_items: FrozenSet[FlowItemType] =
> frozenset({FlowItemType.UDP})
> +    """
> +    - ``flags``: normally 0x08 (I flag).
> +    - ``rsvd0``: reserved, normally 0x000000.
> +    - ``vni``: VXLAN network identifier.
> +    - ``rsvd1``: reserved, normally 0x00.
> +    - Default ``mask`` matches VNI only.
> +
> +    TESTPMD ONLY SUPPORTS VNI.
> +    """
> +
> +
> +possible_properties = {
> +    # THE FOLLOWING PROPERTIES ARE UNSUPPORTED BY TESTPMD AT THE
> TIME OF WRITING.
> +    # They are still tested to future proof this test suite.
> +    'rsvd0':
> +        ('vxlan rsvd0 is 0x000000',
> +         frozenset({"Ether() / IP() / VXLAN(reserved0=0) / ('\\x00' * 64)"}),
> +
> +         frozenset({"Ether() /  IP() / VXLAN(reserved0=1) /  ('\\x00' * 64)",
> +                    "Ether() /  IP() /  VXLAN(reserved0=2) /  ('\\x00' * 64)",
> +                    "Ether() /  IP() /  VXLAN(reserved0=3) /  ('\\x00' * 64)",
> +                    "Ether() /  IP()  / VXLAN(reserved0=4) /  ('\\x00' * 64)"
> +                    })),
> +    'rsvd1':
> +        ('vxlan rsvd1 is 0x00',
> +         frozenset({"Ether() /  IP() /  VXLAN(reserved0=0) /  ('\\x00' * 64)"}),
> +
> +         frozenset({"Ether() / IP() /  VXLAN(reserved0=1) /  ('\\x00' * 64)",
> +                    "Ether() /  IP() /  VXLAN(reserved0=2) /  ('\\x00' * 64)",
> +                    "Ether() /  IP() / VXLAN(reserved0=3) /  ('\\x00' * 64)",
> +                    "Ether() /  IP() /  VXLAN(reserved0=4) /  ('\\x00' * 64)"
> +                    })),
> +    'flags':
> +        ('vxlan flags is 0x08',
> +         frozenset({"Ether() /  IP() /  VXLAN(flags=0x08) /  ('\\x00' * 64)"}),
> +
> +         frozenset({"Ether() / IP() /  VXLAN(flags=0x80) /  ('\\x00' * 64)",
> +                    "Ether() /  IP() /  VXLAN(flags=0x00) /  ('\\x00' * 64)",
> +                    "Ether() /  IP() / VXLAN(flags=0x99) /  ('\\x00' * 64)",
> +                    "Ether() /  IP() /  VXLAN(flags=0x01) /  ('\\x00' * 64)"
> +                    })),
> +    # END UNSUPPORTED PROPERTIES
> +    'vni':  # a 3-byte value
> +        ('vxlan vni is 0x112233',
> +         frozenset({"Ether() / IP() / VXLAN(vni=0x112233) / ('\\x00' * 64)"}),
> +
> +         frozenset({"Ether() / IP() / VXLAN(vni=0x112234) / ('\\x00' * 64)",
> +                    "Ether() / IP() / VXLAN(vni=0x123456) / ('\\x00' * 64)",
> +                    "Ether() / IP() / VXLAN(vni=0xaabbcc) / ('\\x00' * 64)",
> +                    "Ether() / IP() / VXLAN(vni=0x999999) / ('\\x00' * 64)"
> +                    })),
> +}
> +
> +
> +class FlowItemVxlan_gpe(PatternFlowItem):
> +    type = FlowItemType.VXLAN_GPE
> +    valid_next_items = list({FlowItemType.ETH} | ALWAYS_ALLOWED_ITEMS)
> +    valid_parent_items: List[FlowItemType] = [FlowItemType.UDP]
> +    """
> +    - ``flags``: normally 0x0C (I and P flags).
> +    - ``rsvd0``: reserved, normally 0x0000.
> +    - ``protocol``: protocol type. => NextProtocol?
> +    - ``vni``: VXLAN network identifier.
> +    - ``rsvd1``: reserved, normally 0x00.
> +    - Default ``mask`` matches VNI only.
> +
> +    NOT CURRENTLY SUPPORTED BY TESTPMD.
> +    """
> +
> +    # THE FOLLOWING PROPERTIES ARE UNSUPPORTED BY TESTPMD AT THE
> TIME OF WRITING.
> +    # They are still tested to future proof this test suite.
> +    possible_properties = {
> +
> +        'rsvd0':
> +            ('vxlan rsvd0 is 0x000000',
> +             frozenset({"Ether() / IP() / VXLAN(reserved0=0) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() /  IP() / VXLAN(reserved0=1) /  ('\\x00' * 64)",
> +                        "Ether() /  IP() /  VXLAN(reserved0=2) /  ('\\x00' * 64)",
> +                        "Ether() /  IP() /  VXLAN(reserved0=3) /  ('\\x00' * 64)",
> +                        "Ether() /  IP()  / VXLAN(reserved0=4) /  ('\\x00' * 64)"
> +                        })),
> +        'rsvd1':
> +            ('vxlan rsvd1 is 0x00',
> +             frozenset({"Ether() /  IP() /  VXLAN(reserved0=0) /  ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / IP() /  VXLAN(reserved0=1) /  ('\\x00' * 64)",
> +                        "Ether() /  IP() /  VXLAN(reserved0=2) /  ('\\x00' * 64)",
> +                        "Ether() /  IP() / VXLAN(reserved0=3) /  ('\\x00' * 64)",
> +                        "Ether() /  IP() /  VXLAN(reserved0=4) /  ('\\x00' * 64)"
> +                        })),
> +        'flags':
> +            ('vxlan flags is 0x08',
> +             frozenset({"Ether() /  IP() /  VXLAN(flags=0x08) /  ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / IP() /  VXLAN(flags=0x80) /  ('\\x00' * 64)",
> +                        "Ether() /  IP() /  VXLAN(flags=0x00) /  ('\\x00' * 64)",
> +                        "Ether() /  IP() / VXLAN(flags=0x99) /  ('\\x00' * 64)",
> +                        "Ether() /  IP() /  VXLAN(flags=0x01) /  ('\\x00' * 64)"
> +                        })),
> +
> +        'vni':  # a 3-byte value
> +            ('vxlan vni is 0x112233',
> +             frozenset({"Ether() / IP() / VXLAN(vni=0x112233) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / IP() / VXLAN(vni=0x112234) / ('\\x00' * 64)",
> +                        "Ether() / IP() / VXLAN(vni=0x123456) / ('\\x00' * 64)",
> +                        "Ether() / IP() / VXLAN(vni=0xaabbcc) / ('\\x00' * 64)",
> +                        "Ether() / IP() / VXLAN(vni=0x999999) / ('\\x00' * 64)"
> +                        })),
> +        'protocol':
> +            ('vxlan protocol is 0x01',
> +             frozenset({"Ether() / IP() / VXLAN(NextProtocol=0x01) / ('\\x00' * 64)"}),
> +
> +             frozenset({"Ether() / IP() / VXLAN(NextProtocol=0x01) / ('\\x00' * 64)",
> +                        "Ether() / IP() / VXLAN(NextProtocol=0x11) / ('\\x00' * 64)",
> +                        "Ether() / IP() / VXLAN(NextProtocol=0x22) / ('\\x00' * 64)",
> +                        "Ether() / IP() / VXLAN(NextProtocol=0x33) / ('\\x00' * 64)"
> +                        })),
> +    }
> +
> +
> +class FlowItemFuzzy(PatternFlowItem):
> +    type = FlowItemType.FUZZY
> +    layer = 1  # This field needs to go before ethernet, and we ignore layer 1 in
> these filters
> +    valid_next_items = list({FlowItemType.ETH, FlowItemType.RAW,
> FlowItemType.VOID})
> +    """
> +   +----------+---------------+--------------------------------------------------+
> +   | Field    |   Subfield    | Value                                            |
> +
> +==========+===============+=====================================
> =============+
> +   | ``spec`` | ``threshold`` | 0 as perfect match, 0xffffffff as fuzziest match |
> +   +----------+---------------+--------------------------------------------------+
> +   | ``last`` | ``threshold`` | upper range value                                |
> +   +----------+---------------+--------------------------------------------------+
> +   | ``mask`` | ``threshold`` | bit-mask apply to "spec" and "last"              |
> +   +----------+---------------+--------------------------------------------------+
> +    """
> +
> +
> +class FlowItemMark(PatternFlowItem):
> +    type = FlowItemType.MARK
> +    """
> +    +----------+----------+---------------------------+
> +    | Field    | Subfield | Value                     |
> +    +==========+==========+===========================+
> +    | ``spec`` | ``id``   | integer value             |
> +    +----------+--------------------------------------+
> +    | ``last`` | ``id``   | upper range value         |
> +    +----------+----------+---------------------------+
> +    | ``mask`` | ``id``   | zeroed to match any value |
> +    +----------+----------+---------------------------+
> +    """
> +
> +
> +class FlowItemMeta(PatternFlowItem):
> +    type = FlowItemType.META
> +    """
> +    Matches an application specific 32 bit metadata item.
> +
> +    - Default ``mask`` matches the specified metadata value.
> +    """
> +
> +
> +class FlowItemTag(PatternFlowItem):
> +    type = FlowItemType.TAG
> +    """
> +    Matches tag item set by other flows. Multiple tags are supported by
> specifying
> +    ``index``.
> +
> +    - Default ``mask`` matches the specified tag value and index.
> +
> +   +----------+----------+----------------------------------------+
> +   | Field    | Subfield  | Value                                 |
> +
> +==========+===========+=======================================+
> +   | ``spec`` | ``data``  | 32 bit flow tag value                 |
> +   |          +-----------+---------------------------------------+
> +   |          | ``index`` | index of flow tag                     |
> +   +----------+-----------+---------------------------------------+
> +   | ``last`` | ``data``  | upper range value                     |
> +   |          +-----------+---------------------------------------+
> +   |          | ``index`` | field is ignored                      |
> +   +----------+-----------+---------------------------------------+
> +   | ``mask`` | ``data``  | bit-mask applies to "spec" and "last" |
> +   |          +-----------+---------------------------------------+
> +   |          | ``index`` | field is ignored                      |
> +   +----------+-----------+---------------------------------------+
> +    """
> +
> +
> +PATTERN_ITEMS_TYPE_CLASS_MAPPING: Dict[FlowItemType,
> PatternFlowItem] = {
> +    FlowItemType.UDP: FlowItemUdp,
> +    FlowItemType.TCP: FlowItemTcp,
> +    FlowItemType.SCTP: FlowItemSctp,
> +    FlowItemType.IPV4: FlowItemIpv4,
> +    FlowItemType.IPV6: FlowItemIpv6,
> +    FlowItemType.ETH: FlowItemEth,
> +    FlowItemType.VLAN: FlowItemVlan,
> +    FlowItemType.VXLAN: FlowItemVxlan,
> +    FlowItemType.GRE: FlowItemGre,
> +    FlowItemType.VXLAN_GPE: FlowItemVxlan_gpe,
> +    FlowItemType.ARP_ETH_IPV4: FlowItemArp_eth_ipv4,
> +    FlowItemType.ICMP: FlowItemIcmp,
> +    FlowItemType.ICMP6: FlowItemIcmp6,
> +    FlowItemType.MARK: FlowItemMark,
> +    FlowItemType.META: FlowItemMeta,
> +    FlowItemType.TAG: FlowItemTag,
> +    FlowItemType.FUZZY: FlowItemFuzzy,
> +    FlowItemType.END: FlowItemEnd,
> +    FlowItemType.VOID: FlowItemVoid,
> +    FlowItemType.INVERT: FlowItemInvert,
> +    FlowItemType.ANY: FlowItemAny,
> +    FlowItemType.RAW: FlowItemRaw,
> +}
> +
> +ITEM_TYPE_SCAPY_CLASS_MAPPING: Dict[FlowItemType, Packet] = {
> +    FlowItemType.UDP: UDP,
> +    FlowItemType.TCP: TCP,
> +    FlowItemType.SCTP: SCTP,
> +    FlowItemType.IPV4: IP,
> +    FlowItemType.IPV6: IPv6,
> +    FlowItemType.ETH: Ether,
> +    FlowItemType.VLAN: Dot1Q,
> +    FlowItemType.VXLAN: VXLAN,
> +    FlowItemType.GRE: GRE,
> +    FlowItemType.VXLAN_GPE: VXLAN,
> +    FlowItemType.ARP_ETH_IPV4: ARP,  # The type rules prevent this from being
> under anything except Ether / IPv4
> +    FlowItemType.ICMP: ICMP,
> +    FlowItemType.ICMP6: ICMP,
> +    FlowItemType.MARK: None,
> +    FlowItemType.META: None,
> +    FlowItemType.TAG: None,
> +    FlowItemType.FUZZY: None,
> +    FlowItemType.END: None,
> +    FlowItemType.VOID: None,
> +    FlowItemType.INVERT: None,
> +    FlowItemType.ANY: None,
> +    FlowItemType.RAW: None,
> +}
> +
> +TUNNELING_PROTOCOLS = {
> +    FlowItemVlan,
> +    FlowItemVxlan,
> +    FlowItemGre,
> +    FlowItemVxlan_gpe
> +}
> +
> +PATTERN_OPERATIONS = {
> +    FlowItemMark,
> +    FlowItemMeta,
> +    FlowItemTag,
> +    FlowItemFuzzy,
> +    FlowItemInvert,
> +}
> diff --git a/framework/flow/flow_rule.py b/framework/flow/flow_rule.py
> new file mode 100644
> index 00000000..70b308da
> --- /dev/null
> +++ b/framework/flow/flow_rule.py
> @@ -0,0 +1,31 @@
> +from typing import Union
> +
> +from framework.flow.enums import *
> +from framework.flow.flow import Flow
> +import framework.flow.flow_action_items as flow_action_items
> +
> +class FlowPattern(Flow):
> +    entry_points = {FlowItemType.ETH, FlowItemType.FUZZY}
> +
> +    def __str__(self):
> +        return f"pattern {super(FlowPattern, self).__str__()} / end"
> +
> +
> +class FlowActions(Flow):
> +    entry_points = flow_action_items.ENTRY_POINTS
> +
> +    def __str__(self):
> +        return f"action {super(FlowActions, self).__str__()} / end"
> +
> +
> +class FlowRule(object):
> +    port: int
> +    group: Union[int, None]
> +    priority: Union[int, None]
> +
> +    ingress: bool
> +    egress: bool
> +    transfer: bool
> +
> +    pattern: FlowPattern
> +    actions: FlowActions
> diff --git a/framework/flow/generator.py b/framework/flow/generator.py
> new file mode 100644
> index 00000000..8267f7af
> --- /dev/null
> +++ b/framework/flow/generator.py
> @@ -0,0 +1,155 @@
> +from __future__ import annotations
> +
> +import copy
> +import itertools
> +import os
> +import sys
> +import time
> +from typing import List, Set, Generator, Iterable, FrozenSet, Tuple
> +
> +import numpy as np
> +
> +from framework.flow.flow import Flow
> +from framework.flow.flow_action_items import
> ACTION_ITEMS_TYPE_CLASS_MAPPING
> +from framework.flow.flow_pattern_items import
> PATTERN_ITEMS_TYPE_CLASS_MAPPING, PatternFlowItem, \
> +    PATTERN_OPERATION_TYPES, TUNNELING_PROTOCOL_TYPES,
> ALWAYS_ALLOWED_ITEMS, FlowItemEnd, FlowItemVxlan, FlowItemIpv4, \
> +    FlowItemEth, FlowItemGre, L3_FLOW_TYPES, FlowItemVlan, FlowItemUdp
> +from framework.flow.flow_rule import FlowItemType
> +
> +
> +def get_valid_next_protocols(current_protocol, protocol_stack, type_denylist):
> +    return list(filter(
> +        lambda patent_item: patent_item not in type_denylist and patent_item
> not in {p.type for p in protocol_stack},
> +        current_protocol.valid_parent_items))
> +
> +
> +def _generate(type_denylist=None) -> List[List[PatternFlowItem]]:
> +    if type_denylist is None:
> +        type_denylist = set()
> +    UNUSED_PATTERN_ITEMS = {PATTERN_ITEMS_TYPE_CLASS_MAPPING[i] for
> i in type_denylist}
> +
> +    patterns: List[List[PatternFlowItem]] = []
> +    for pattern_item in [clazz for clazz in
> PATTERN_ITEMS_TYPE_CLASS_MAPPING.values() if
> +                         clazz not in UNUSED_PATTERN_ITEMS]:
> +        protocol_stack = []
> +        if protocol_stack.count(pattern_item) >= 2:
> +            continue
> +
> +        current_protocol = pattern_item()
> +        valid_next_protocols = get_valid_next_protocols(current_protocol,
> protocol_stack, type_denylist)
> +        while len(valid_next_protocols) > 0:
> +            protocol_stack.append(current_protocol)
> +            current_protocol =
> PATTERN_ITEMS_TYPE_CLASS_MAPPING[list(valid_next_protocols)[0]]()
> +            valid_next_protocols = get_valid_next_protocols(current_protocol,
> protocol_stack, type_denylist)
> +
> +        protocol_stack.append(current_protocol)
> +
> +        patterns.append(list(reversed(protocol_stack)))  # This will place the lowest
> level protocols first
> +    return patterns
> +
> +
> +def convert_protocol_stack_to_flow_pattern(protocol_stack):
> +    return Flow(pattern_items=protocol_stack)
> +
> +
> +def _get_patterns_with_type_denylist(type_denylist: Set):
> +    return [convert_protocol_stack_to_flow_pattern(protocol_stack) for
> protocol_stack in (_generate(
> +        type_denylist=type_denylist
> +    ))]
> +
> +
> +def _get_normal_protocol_patterns() -> List[Flow]:
> +    return _get_patterns_with_type_denylist(
> +        PATTERN_OPERATION_TYPES | ALWAYS_ALLOWED_ITEMS |
> {FlowItemType.ANY,
> +                                                          FlowItemType.END})
> +
> +
> +def _get_tunnelled_protocol_patterns(patterns: List[Flow]) -> Generator[Flow]:
> +    VXLAN_FLOW = Flow(pattern_items=[FlowItemEth(), FlowItemIpv4(),
> FlowItemUdp(), FlowItemVxlan()])
> +    for pattern in patterns:
> +        yield VXLAN_FLOW / pattern
> +
> +    GRE_FLOW = Flow(pattern_items=[FlowItemEth(), FlowItemIpv4(),
> FlowItemGre()])
> +    for pattern in patterns:
> +        if len(pattern.pattern_items) >= 2:
> +            if pattern.pattern_items[1].type in L3_FLOW_TYPES:
> +                yield GRE_FLOW / pattern
> +
> +
> +def add_vlans_to_patterns(flows: Iterable[Iterable[Flow]]) -> Generator[Flow]:
> +    for flow in flows:
> +        pattern_items_vlan = copy.deepcopy(flow.pattern_items)
> +        pattern_items_qinq = copy.deepcopy(flow.pattern_items)
> +        eth_indexes = np.where(np.array(flow.pattern_items) == FlowItemEth())[0]
> +        for index in eth_indexes:
> +            pattern_items_vlan.insert(index + 1, FlowItemVlan())
> +            pattern_items_qinq.insert(index + 1, FlowItemVlan())
> +            pattern_items_qinq.insert(index + 1, FlowItemVlan())
> +        yield flow
> +        yield Flow(pattern_items=pattern_items_vlan,
> action_items=flow.action_items)
> +        yield Flow(pattern_items=pattern_items_qinq,
> action_items=flow.action_items)
> +
> +
> +def get_patterns() -> Iterable[Iterable[Flow]]:
> +    patterns: List[Flow] = _get_normal_protocol_patterns()
> +
> +    # The flow with only an ethernet header was a consequence of the
> +    # generation algorithm, but isn't that useful to test since we can't
> +    # create a failing case without getting each NIC to write arbitrary
> +    # bytes over the link.
> +    eth_only_flow = Flow(pattern_items=[FlowItemEth()])
> +    patterns.remove(eth_only_flow)
> +
> +    # tunnelled_patterns = _get_tunnelled_protocol_patterns(patterns)
> +
> +    return patterns
> +
> +
> +def add_properties_to_patterns(patterns: Iterable[Flow]) ->
> Iterable[Tuple[Flow, FrozenSet[str], FrozenSet[str], str]]:
> +    test_property_flow_iters = map(lambda f: f.get_test_property_flows(),
> patterns)
> +    for iterator in test_property_flow_iters:
> +        yield from iterator
> +
> +
> +def get_patterns_with_properties() -> Iterable[Tuple[Flow, FrozenSet[str],
> FrozenSet[str], str]]:
> +    base_patterns = get_patterns()
> +    return add_properties_to_patterns(base_patterns)
> +
> +
> +def create_test_function_strings(test_configurations: Iterable[Tuple[Flow,
> FrozenSet[str], FrozenSet[str], str]]) -> \
> +        Iterable[str]:
> +    """
> +    This will break if the __str__ methods of frozenset ever changes or if %
> formatting syntax is removed.
> +
> +    @param test_configurations: An iterable with test configurations to convert
> into test case strings.
> +    @return: An iterable containing strings that are function parameters.
> +    """
> +    function_template = \
> +        """
> +def test_%s(self):
> +    self.do_test_with_queue_action("%s", %s, %s)
> +        """
> +    return map(lambda test_configuration: function_template % (
> +        test_configuration[-1], test_configuration[0], test_configuration[1],
> test_configuration[2],),
> +               test_configurations)
> +
> +def get_test_configs_for_actions() -> Iterable[Tuple[str, FrozenSet[str],
> FrozenSet[str], str]]:
> +    return itertools.chain.from_iterable(
> +            [
> +                [(*test_case, f"{action_type.value}_{test_case_name}",) \
> +                 for test_case_name, test_case in case.test_case.items()] \
> +                for action_type, case in
> ACTION_ITEMS_TYPE_CLASS_MAPPING.items()
> +            ]
> +        )
> +# Used for testing pattern generation, it will output all patterns
> +# and their pass/fail packets to stdout
> +def main():
> +    pattern_tests = list(get_patterns_with_properties())
> +    pattern_functions = create_test_function_strings(pattern_tests)
> +    # print("\n".join(pattern_functions))
> +
> +    action_functions =
> create_test_function_strings(get_test_configs_for_actions())
> +    print("\n".join(action_functions))
> +
> +if __name__ == "__main__":
> +    main()
> \ No newline at end of file
> diff --git a/test_plans/index.rst b/test_plans/index.rst
> index 6a0750d1..77ac8248 100644
> --- a/test_plans/index.rst
> +++ b/test_plans/index.rst
> @@ -136,6 +136,7 @@ The following are the test plans for the DPDK DTS
> automated test system.
>      rss_key_update_test_plan
>      rxtx_offload_test_plan
>      rteflow_priority_test_plan
> +    rte_flow_test_plan
>      runtime_vf_queue_number_kernel_test_plan
>      runtime_vf_queue_number_maxinum_test_plan
>      runtime_vf_queue_number_test_plan
> diff --git a/test_plans/rte_flow_test_plan.rst
> b/test_plans/rte_flow_test_plan.rst
> new file mode 100644
> index 00000000..b53f64b8
> --- /dev/null
> +++ b/test_plans/rte_flow_test_plan.rst
> @@ -0,0 +1,4114 @@
> +.. # BSD LICENSE
> +    #
> +    # Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
> +    # Copyright © 2018[, 2020] The University of New Hampshire. All rights
> reserved.
> +    # All rights reserved.
> +    #
> +    # Redistribution and use in source and binary forms, with or without
> +    # modification, are permitted provided that the following conditions
> +    # are met:
> +    #
> +    #   * Redistributions of source code must retain the above copyright
> +    #     notice, this list of conditions and the following disclaimer.
> +    #   * Redistributions in binary form must reproduce the above copyright
> +    #     notice, this list of conditions and the following disclaimer in
> +    #     the documentation and/or other materials provided with the
> +    #     distribution.
> +    #   * Neither the name of Intel Corporation nor the names of its
> +    #     contributors may be used to endorse or promote products derived
> +    #     from this software without specific prior written permission.
> +    #
> +    # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> CONTRIBUTORS
> +    # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
> NOT
> +    # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
> FITNESS FOR
> +    # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
> COPYRIGHT
> +    # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> INCIDENTAL,
> +    # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> NOT
> +    # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
> OF USE,
> +    # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
> ON ANY
> +    # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
> TORT
> +    # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
> THE USE
> +    # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> DAMAGE.
> +
> +rte_flow Tests
> +========================================
> +This document contains the test plan for the rte_flow API.
> +
> +Prerequisites
> +=============
> +The DUT must have one 10G Ethernet ports connected to one port on
> +Tester that are controlled by packet generator::
> +
> +    dut_port_0 <---> tester_port_0
> +
> +Assume the DUT 10G Ethernet ports' pci device id is as the following::
> +
> +    dut_port_0 : "0000:05:00.0"
> +    mac_address: "00:00:00:00:01:00"
> +
> +Bind the port to dpdk igb_uio driver::
> +
> +    ./usertools/dpdk-devbind.py -b igb_uio 05:00.0
> +
> +You will also need to have Python 3.6 installed along with scapy to create test
> packets.
> +
> +Pattern Item and Property Tests
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +We create a flow rule for each property in each pattern item. We then send
> one packet that is expected to pass,
> +and about four packets that are expected to fail.
> +
> +We only test one pattern item and one property at a time.
> +
> +Flow rules are created using **testpmd** and packets are created/sent using
> **scapy**.
> +
> +NOTE: Some pattern items and properties could not be tested
> +due to the fact that testpmd does not support them. See **dpdk-
> dts/test_plans/unsupported.rst**
> +for a listing of these items and properties.
> +
> +Item: ETH
> +~~~~~~~~~
> +
> +
> +Test Case: dst (destination MAC) rule
> +-------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the Ethernet destination MAC is equal to
> 90:61:ae:fd:41:43, send the packet to queue 1):
> +
> +::
> +
> +    flow create 0 ingress pattern eth dst is 90:61:ae:fd:41:43 / end actions queue
> index 1 / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether(dst="90:61:ae:fd:41:43") / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +           Pkt1 = Ether(dst=\"90:61:ae:fd:41:44") / ('\\x00' * 64)
> +           Pkt2 = Ether(dst=\"90:61:ae:fd:41:45") / ('\\x00' * 64)
> +           Pkt3 = Ether(dst=\"90:61:ae:fd:41:46") / ('\\x00' * 64)
> +           Pkt4 = Ether(dst=\"91:61:ae:fd:41:43") / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that only the pass packet was received by queue 1.
> +
> +Test Case: src (source MAC) rule
> +---------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the Ethernet source MAC is equal to
> 90:61:ae:fd:41:43, send the packet to queue 1)
> +
> +::
> +
> +    flow create 0 ingress pattern eth src is 90:61:ae:fd:41:43 / end actions queue
> index 1 / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether(dst="90:61:ae:fd:41:43") / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +            Pkt1 = Ether(dst=\"90:61:ae:fd:41:44") / ('\\x00' * 64)
> +            Pkt2 = Ether(dst=\"90:61:ae:fd:41:45") / ('\\x00' * 64)
> +            Pkt3 = Ether(dst=\"90:61:ae:fd:41:46") / ('\\x00' * 64)
> +            Pkt4 = Ether(dst=\"91:61:ae:fd:41:43") / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that only the pass packet was received by queue 1.
> +
> +
> +Test Case: type (EtherType or TPID) rule
> +-----------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the Ethernet type is 0x0800, send the packet to
> queue 1):
> +
> +::
> +
> +    flow create 0 ingress pattern eth type is 0x0800 / end actions queue index 1 /
> end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +            Pkt0 = Ether(type=0x0800) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +            Pkt1 = Ether(type=0x0842) / ('\\x00' * 64)
> +            Pkt2 = Ether(type=0x8100) / ('\\x00' * 64)
> +            Pkt3 = Ether(type=0x9100) / ('\\x00' * 64)
> +            Pkt4 = Ether(type=0x8863) / ('\\x00' * 64)
> +            Pkt5 = Ether(type=0x9000) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that only the pass packet was received by queue 1.
> +
> +Item: GRE
> +~~~~~~~~~
> +
> +Test Case: protocol (protocol type) rule
> +-----------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the GRE protocol is equal to 0x0800,send the packet
> to queue 1) :
> +
> +::
> +
> +
> +    flow create 0 ingress pattern gre protocol is 0x0800 / end actions queue
> index 1 / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +            Pkt0 = Ether() / GRE(proto=0x0800) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +            Pkt1 = Ether() / GRE(proto=0x0842) / ('\\x00' * 64)
> +            Pkt2 = Ether() / GRE(proto=0x8100) / ('\\x00' * 64)
> +            Pkt3 = Ether() / GRE(proto=0x0806) / ('\\x00' * 64)
> +            Pkt4 = Ether() / GRE(proto=0x809B) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that only the pass packet was received by queue 1.
> +
> +
> +Item: ICMP
> +~~~~~~~~~~
> +
> +Test Case: icmp_type (ICMP message type) rule
> +----------------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the ICMP type is 3, send the packet to queue 1) :
> +
> +::
> +
> +
> +    flow create 0 ingress pattern icmp type is 3 / end actions queue index 1 / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +            Pkt0 = Ether() / ICMP(type=3) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +            Pkt1 = Ether() / ICMP(type=3) / ('\\x00' * 64)
> +            Pkt2 = Ether() / ICMP(type=13) / ('\\x00' * 64)
> +            Pkt3 = Ether() / ICMP(type=11) / ('\\x00' * 64)
> +            Pkt4 = Ether() / ICMP(type=12) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that only the pass packet was received by queue 1.
> +
> +
> +Test Case: icmp_code (ICMP message code) rule
> +-----------------------------------------------
> +
> +NOTE: ICMP code meaning is dependent on type.
> +We tested type 3, code 3.
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the ICMP type is 3 and the ICMP code is 3, send the
> packet to queue 1) :
> +
> +::
> +
> +    flow create 0 ingress pattern icmp type is 3 code is 3 / end actions queue
> index 1 / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> + Pkt0 = Ether() / ICMP(type=3, code=3) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / ICMP(type=3, code=3) / ('\\x00' * 64)
> +    Pkt2 = Ether() / ICMP(type=3, code=0) / ('\\x00' * 64)
> +    Pkt3 = Ether() / ICMP(type=11, code=1) / ('\\x00' * 64)
> +    Pkt4 = Ether() / ICMP(type=12, code=2) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that only the pass packet was received by queue 1.
> +
> +
> +Item: IPv4
> +~~~~~~~~~~~
> +
> +Test Case: tos (Type of Service) rule
> +----------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 type of service is 0, send the packet to
> queue 1) :
> +
> +::
> +
> +
> +    flow create 0 ingress pattern ipv4 tos is 0 / end actions queue index 1 / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(tos=0) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(tos=2) / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(tos=4) / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(tos=8) / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(tos=16) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that only the pass packet was received by queue 1.
> +
> +
> +Test Case: ttl (time to live) rule
> +-------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 packet's time to live is 64, send the packet
> to queue 1) :
> +
> +::
> +
> +
> +   flow create 0 ingress pattern ipv4 ttl is 64 / end actions queue index 1 / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(ttl=64) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +   Pkt1 = Ether() / IP(ttl=128) / ('\\x00' * 64)
> +   Pkt2 = Ether() / IP(ttl=255) / ('\\x00' * 64)
> +   Pkt3 = Ether() / IP(ttl=32) / ('\\x00' * 64)
> +   Pkt4 = Ether() / IP(ttl=100) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that only the pass packet was received by queue 1.
> +
> +Test Case: proto (IPv4 protocol) rule
> +----------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 protocol is 0x06, send the packet to queue
> 1) :
> +
> +::
> +
> + flow create 0 ingress pattern ipv4 proto is 0x06 / end actions queue index 1 /
> end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(proto=0x06) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +   Pkt1 = Ether() / IP(proto=0x01) / ('\\x00' * 64)
> +   Pkt2 = Ether() / IP(proto=0x11) / ('\\x00' * 64)
> +   Pkt3 = Ether() / IP(proto=0x12) / ('\\x00' * 64)
> +   Pkt4 = Ether() / IP(proto=0x58) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that only the pass packet was received by queue 1.
> +
> +
> +Test Case: src (IPv4 source) rule
> +------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.5, send the packet to
> queue 1) :
> +
> +::
> +
> +   flow create 0 ingress pattern ipv4 src is 192.168.0.5 / end actions queue index
> 1 / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=192.168.0.5) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=10.10.10.10) / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=132.177.127.6) / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=192.168.0.4) / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=192.168.0.250) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that only the pass packet was received by queue 1.
> +
> +Test Case: dst (IPv4 destination) rule
> +------------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 destination is 192.168.0.5, send the packet
> to queue 1) :
> +
> +::
> +
> +    flow create 0 ingress pattern ipv4 dst is 192.168.0.5 / end actions queue
> index 1 / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=192.168.0.5) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(dst=10.10.10.10) / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(dst=132.177.127.6) / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(dst=192.168.0.4) / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(dst=192.168.0.250) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that only the pass packet was received by queue 1.
> +
> +
> +Item: IPv6
> +~~~~~~~~~~~
> +
> +Test Case: tc (Traffic Class) rule
> +------------------------------------
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv6 traffic class is 0, send the packet to queue
> 1) :
> +
> +::
> +
> +    flow create 0 ingress pattern ipv6 tc is 0 / end actions queue index 1 / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IPv6(tc=0) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IPv6(tc=1) / ('\\x00' * 64)
> +    Pkt2 = Ether() / IPv6(tc=2) / ('\\x00' * 64)
> +    Pkt3 = Ether() / IPv6(tc=4) / ('\\x00' * 64)
> +    Pkt4 = Ether() / IPv6(tc=6) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that only the pass packet was received by queue 1.
> +
> +
> +Test Case: flow (Flow Code) rule
> +--------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv6 flow code is 0xABCD, send the packet to
> queue 1) :
> +
> +::
> +
> +    flow create 0 ingress pattern ipv6 flow is 0xABCD / end actions queue index 1
> / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IPv6(fl=0xABCD) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +   Pkt1 = Ether() / IPv6(fl=0xABCE) / ('\\x00' * 64)
> +   Pkt2 = Ether() / IPv6(fl=0x0001) / ('\\x00' * 64)
> +   Pkt3 = Ether() / IPv6(fl=0xFFFF) / ('\\x00' * 64)
> +   Pkt4 = Ether() / IPv6(fl=0x1234) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that only the pass packet was received by queue 1.
> +
> +
> +Test Case: proto (IPv6 protocol/next header protocol) rule
> +--------------------------------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv6 protocol is 0x06, send the packet to queue
> 1) :
> +
> +::
> +
> +    flow create 0 ingress pattern ipv6 proto is 0x06 / end actions queue index 1 /
> end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IPv6(nh=6) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +   Pkt1 = Ether() / IPv6(nh=17) / ('\\x00' * 64)
> +   Pkt2 = Ether() / IPv6(nh=41) / ('\\x00' * 64)
> +   Pkt3 = Ether() / IPv6(nh=0) / ('\\x00' * 64)
> +   Pkt4 = Ether() / IPv6(nh=60) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that only the pass packet was received by queue 1.
> +
> +
> +Test Case: hop (Hop Limit) rule
> +---------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv6 hop limit is 64, send the packet to queue 1) :
> +::
> +
> +    flow create 0 ingress pattern ipv6 hop is 64 / end actions queue index 1 / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IPv6(hlim=64) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +   Pkt1 = Ether() / IPv6(hlim=128) / ('\\x00' * 64)
> +   Pkt2 = Ether() / IPv6(hlim=32) / ('\\x00' * 64)
> +   Pkt3 = Ether() / IPv6(hlim=255) / ('\\x00' * 64)
> +   Pkt4 = Ether() / IPv6(hlim=100) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that only the pass packet was received by queue 1.
> +
> +Test Case: dst (IPv6 destination) rule
> +---------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv6 destination is 2001:...:b1c2, send the packet
> to queue 1) :
> +
> +::
> +
> +   flow create 0 ingress pattern ipv6 dst is
> 2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c2 / end actions queue index 1 / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IPv6(dst=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c2\") /
> ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IPv6(dst=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c3\") /
> ('\\x00' * 64)
> +    Pkt2 = Ether() / IPv6(dst=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c4\") /
> ('\\x00' * 64)
> +    Pkt3 = Ether() / IPv6(dst=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c5\") /
> ('\\x00' * 64)
> +    Pkt4 = Ether() / IPv6(dst=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c6\") /
> ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that only the pass packet was received by queue 1.
> +
> +Test Case: src (IPv6 source) rule
> +-----------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv6 destination is 2001:...b1c2, send the packet
> to queue 1) :
> +
> +::
> +
> +    flow create 0 ingress pattern ipv6 src is
> 2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c2 / end actions queue index 1 / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c2\") /
> ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c3\") /
> ('\\x00' * 64)
> +    Pkt2 = Ether() / IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c4\") /
> ('\\x00' * 64)
> +    Pkt3 = Ether() / IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c5\") /
> ('\\x00' * 64)
> +    Pkt4 = Ether() / IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c6\") /
> ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that only the pass packet was received by queue 1.
> +
> +
> +Item: SCTP
> +~~~~~~~~~~~
> +
> +Test Case: src (source port) rule
> +-------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the SCTP source port is 3838, send the packet to
> queue 1) :
> +
> +::
> +
> +    flow create 0 ingress pattern sctp src is 3838 / end actions queue index 1 /
> end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP() / SCTP(sport=3838) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP() / SCTP(sport=3939) / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP() / SCTP(sport=5000) / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP() / SCTP(sport=1998) / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP() / SCTP(sport=1028) / ('\\x00' * 64)
> +
> +..
> +
> +Test Case: dst (destination port) rule
> +-----------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the SCTP destination port is 3838, send the packet to
> queue 1) :
> +
> +::
> +
> +    flow create 0 ingress pattern sctp dst is 3838 / end actions queue index 1 /
> end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP() / SCTP(dport=3838) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP() / SCTP(dport=3939) / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP() / SCTP(dport=5000) / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP() / SCTP(dport=1998) / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP() / SCTP(dport=1028) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that only the pass packet was received by queue 1.
> +
> +Test Case: tag (SCTP header tag) rule
> +--------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the SCTP tag is equal to 12345, send the packet to
> queue 1) :
> +
> +::
> +
> +    flow create 0 ingress pattern sctp tag is 12345 / end actions queue index 1 /
> end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP() / SCTP(tag=12345) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +   Pkt1 = Ether() / IP() / SCTP(tag=12346) / ('\\x00' * 64)
> +   Pkt2 = Ether() / IP() / SCTP(tag=12) / ('\\x00' * 64)
> +   Pkt3 = Ether() / IP() / SCTP(tag=9999) / ('\\x00' * 64)
> +   Pkt4 = Ether() / IP() / SCTP(tag=42) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that only the pass packet was received by queue 1.
> +
> +
> +Test Case: cksum (SCTP header checksum) rule
> +-----------------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the SCTP checksum is equal to 0x1535b67, send the
> packet to queue 1) :
> +
> +::
> +
> +    flow create 0 ingress pattern sctp cksum is 0x01535b67 / end actions queue
> index 1 / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP() / SCTP(chksum=0x01535b67)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +   Pkt1 = Ether() / IP() / SCTP(chksum=0x01535b68)
> +   Pkt2 = Ether() / IP() / SCTP(chksum=0xdeadbeef)
> +   Pkt3 = Ether() / IP() / SCTP(chksum=0x12345678)
> +   Pkt4 = Ether() / IP() / SCTP(chksum=0x385030fe)
> +
> +..
> +
> +5. Check to make sure that only the pass packet was received by queue 1.
> +
> +Item: TCP
> +~~~~~~~~~~~
> +
> +Test Case: src (source port) rule
> +--------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the TCP source port is equal to 3838, send the
> packet to queue 1) :
> +
> +::
> +
> +    flow create 0 ingress pattern tcp src is 3838 / end actions queue index 1 / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP() / TCP(sport=3838) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP() / TCP(sport=3939) / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP() / TCP(sport=5000) / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP() / TCP(sport=1998) / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP() / TCP(sport=1028) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that only the pass packet was received by queue 1.
> +
> +
> +Test Case: dst (destination port) rule
> +-----------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the TCP destination port is equal to 3838, send the
> packet to queue 1) :
> +
> +::
> +
> +    flow create 0 ingress pattern tcp dst is 3838 / end actions queue index 1 /
> end
> +
> +..
> +
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP() / TCP(dport=3838) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP() / TCP(dport=3939) / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP() / TCP(dport=5000) / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP() / TCP(dport=1998) / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP() / TCP(dport=1028) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that only the pass packet was received by queue 1.
> +
> +Test Case: flags (TCP flags) rule
> +-----------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the TCP flags are equal to 0x02, send the packet to
> queue 1) :
> +
> +::
> +
> +    flow create 0 ingress pattern tcp flags is 0x02 / end actions queue index 1 /
> end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP() / TCP(flags=0x02) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP() / TCP(flags=0x01) / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP() / TCP(flags=0x04) / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP() / TCP(flags=0x08) / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP() / TCP(flags=0x10) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that only the pass packet was received by queue 1.
> +
> +Item: UDP
> +~~~~~~~~~~~
> +
> +Test Case: src (source port) rule
> +-------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the UDP source port is equal to 3838, send the
> packet to queue 1) :
> +
> +::
> +
> +    flow create 0 ingress pattern udp src is 3838 / end actions queue index 1 /
> end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +    Pkt0 = Ether() / IP() / UDP(sport=3838) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP() / UDP(sport=3939) / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP() / UDP(sport=5000) / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP() / UDP(sport=1998) / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP() / UDP(sport=1028) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that only the pass packet was received by queue 1.
> +
> +
> +Test Case: dst (destination port) rule
> +-----------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the UDP destination port is equal to 3838, send the
> packet to queue 1) :
> +
> +::
> +
> +    flow create 0 ingress pattern udp dst is 3838 / end actions queue index 1 /
> end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP() / UDP(dport=3838) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP() / UDP(dport=3939) / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP() / UDP(dport=5000) / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP() / UDP(dport=1998) / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP() / UDP(dport=1028) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that only the pass packet was received by queue 1.
> +
> +Item: VLAN
> +~~~~~~~~~~~
> +
> +Test Case: tci (Tag Control Information) rule
> +-----------------------------------------------
> +
> +NOTE: The VLAN tci is the combination of the fields pcp, dei, and vid.
> +We test them altogether as the tci and we test each field individually.
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the vlan tag control information value is 0xaaaa,
> send the packet to queue 1) :
> +
> +::
> +
> +
> +    flow create 0 ingress pattern vlan tci is 0xaaaa / end actions queue index 1 /
> end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / Dot1Q(prio = 0x0, id = 0x0, vlan = 0xbbb) / ('\\x00' * 64)
> +    Pkt2 = Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xccc) / ('\\x00' * 64)
> +    Pkt3 = Ether() / Dot1Q(prio = 0x5, id = 0x1, vlan = 0xaaa) / ('\\x00' * 64)
> +    Pkt4 = Ether() / Dot1Q(prio = 0x4, id = 0x0, vlan = 0xaaa) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that only the pass packet was received by queue 1.
> +
> +
> +Test Case: pcp (Priority Code Point) rule
> +--------------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the VLAN priority code point is equal to 0x0, send
> the packet to queue 1) :
> +
> +::
> +
> +    flow create 0 ingress pattern vlan pcp is 0x0 / end actions queue index 1 /
> end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / Dot1Q(prio=0x0) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / Dot1Q(prio=0x1) / ('\\x00' * 64)
> +    Pkt2 = Ether() / Dot1Q(prio=0x2) / ('\\x00' * 64)
> +    Pkt3 = Ether() / Dot1Q(prio=0x3) / ('\\x00' * 64)
> +    Pkt4 = Ether() / Dot1Q(prio=0x7) / ('\\x00' * 64)
> +
> +..
> +
> +Test Case: dei (Drop Eligible Indicator) rule
> +-----------------------------------------------
> +NOTE: The only two possible values for dei are 0 and 1.
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the VLAN drop eligible indicator is equal to 0, send
> the packet to queue 1) :
> +
> +::
> +
> +    flow create 0 ingress pattern vlan dei is 0 / end actions queue index 1 / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / Dot1Q(id=0)) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / Dot1Q(id=1) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that only the pass packet was received by queue 1.
> +
> +Test Case: vid (VLAN identifier) rule
> +-----------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the VLAN identifier is equal to 0xabc, send the
> packet to queue 1) :
> +
> +::
> +
> +    flow create 0 ingress pattern vlan vid is 0xabc / end actions queue index 1 /
> end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / Dot1Q(vlan=0xabc) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / Dot1Q(vlan=0xaaa) / ('\\x00' * 64)
> +    Pkt2 = Ether() / Dot1Q(vlan=0x123) / ('\\x00' * 64)
> +    Pkt3 = Ether() / Dot1Q(vlan=0x1f5) / ('\\x00' * 64)
> +    Pkt4 = Ether() / Dot1Q(vlan=0x999) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that only the pass packet was received by queue 1.
> +
> +
> +Test Case: tpid (Tag Protocol Identifier) rule
> +--------------------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the VLAN tag protocol identifier is equal to 0x8100,
> send the packet to queue 1) :
> +
> +::
> +
> +    flow create 0 ingress pattern vlan tpid is 0x8100 / end actions queue index 1 /
> end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / Dot1Q(type=0x8100) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / Dot1Q(type=0x0800) / ('\\x00' * 64)
> +    Pkt2 = Ether() / Dot1Q(type=0x0842) / ('\\x00' * 64)
> +    Pkt3 = Ether() / Dot1Q(type=0x809b) / ('\\x00' * 64)
> +    Pkt4 = Ether() / Dot1Q(type=0x86dd) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that only the pass packet was received by queue 1.
> +
> +
> +Item: VXLAN
> +~~~~~~~~~~~
> +
> +Test Case: vni (VXLAN network identifier) rule
> +------------------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the VXLAN network identifier is equal to 0x112233,
> send the packet to queue 1) :
> +
> +::
> +
> +    flow create 0 ingress pattern vxlan vni is 0x112233 / end actions queue index
> 1 / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP() / VXLAN(vni=0x112233) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP() / VXLAN(vni=0x112234) / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP() / VXLAN(vni=0x123456) / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP() / VXLAN(vni=0xaabbcc) / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP() / VXLAN(vni=0x999999) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that only the pass packet was received by queue 1.
> +
> +Action Item Tests
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +We create a simple flow rule that filters packets by matching IPv4 address
> (more rules are sometimes applied
> +depending on the action being tested). We then send one packet that is
> expected to pass,
> +and about four packets that are expected to fail. We check if the packet that is
> expected to pass
> +has the action we are testing applied to it.
> +
> +We only test one action and one of the action's properties at a time, unless
> one property requires the context
> +of another.
> +
> +Flow rules are created using **testpmd** and packets are created/sent using
> **scapy**.
> +
> +NOTE: NVGRE_ENCAP and NVGRE_DECAP could not be tested at this time
> because Scapy does not support NVGRE.
> +
> +We did not create an RSS test suite because one has already been created.
> +
> +
> +Action: PASSTHRU
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: passthru test
> +------------------------------------------------
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, let the packet pass
> through) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> passthru / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet was allowed to pass through.
> +
> +Action: FLAG
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: flag test
> +------------------------------------------------
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, flag the packet) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> flag / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet was flagged.
> +
> +Action: DROP
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: drop test
> +------------------------------------------------
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, drop the packet) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> drop / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet was dropped.
> +
> +Action: COUNT
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: test_shared
> +------------------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, add unshared
> counter action with id of 1) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> count shared 0 id 1 / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has a counter action added to it.
> +
> +Test Case: test_id
> +------------------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, add counter action
> with id of 1) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> count id 1 / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has a counter action added to it.
> +
> +Action: MAC_SWAP
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: mac_swap test
> +------------------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, swap dst and src
> MAC addresses) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> mac_swap / end
> +
> +..
> +
> +3. Send a packet that matches the rule, with defined src and dst MAC addresses:
> +
> +::
> +
> +    Pkt0 = Ether(src=\"90:61:ae:fd:41:43\", dst = \"ab:cd:ef:12:34:56\") /
> IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule, with defined src and dst MAC
> addresses:
> +
> +::
> +
> +    Pkt1 = Ether(src=\"90:61:ae:fd:41:43\", dst = \"ab:cd:ef:12:34:56\") /
> IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether(src=\"90:61:ae:fd:41:43\", dst = \"ab:cd:ef:12:34:56\") /
> IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether(src=\"90:61:ae:fd:41:43\", dst = \"ab:cd:ef:12:34:56\") /
> IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether(src=\"90:61:ae:fd:41:43\", dst = \"ab:cd:ef:12:34:56\") /
> IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its source and destination
> MAC addresses swapped.
> +
> +Action: DEC_TTL
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: dec_ttl test
> +------------------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, decrease its TTL) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> dec_ttl / end
> +
> +..
> +
> +3. Send a packet that matches the rule, with a defined ttl:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\", ttl = 128) / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule, with a defined ttl:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\", ttl = 128) / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\", ttl = 128) / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\", ttl = 128) / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\", ttl = 128) / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its ttl reduced.
> +
> +Action: JUMP
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: jump test
> +------------------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, redirect the packet to
> group 1) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> jump group 1 / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has been added to group 1 on the
> destination device.
> +
> +
> +Action: MARK
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: mark test
> +------------------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, mark the packet with
> an id of 0xABCDEF) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> mark id 0xABCDEF / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has been marked with the correct id.
> +
> +Action: QUEUE
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: queue test
> +------------------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, send the packet to
> queue 1) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> queue index 1 / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has been added to queue 1.
> +
> +Action: PF
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: pf test
> +------------------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, direct the packet to
> the physical function of the device) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> pf / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has been directed to the physical
> function of the device.
> +
> +Action: VF
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: test_original
> +------------------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, direct the packet to
> the original virtual function of the device) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> vf original / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has been directed to the original
> virtual function of the device.
> +
> +Test Case: test_id
> +------------------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, direct the packet to
> the virtual function of id 1) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> vf id 1 / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has been directed to the virtual
> function with the id of 1.
> +
> +
> +Action: PHY_PORT
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: test_original
> +------------------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, direct the packet to
> the original physical port of the device) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> phy_port original / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has been directed to the original
> physical port of the device.
> +
> +Test Case: test_index
> +------------------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, direct the packet to
> the physical port of index 1) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> phy_port index 1 / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has been directed to the physical
> port of index 1.
> +
> +
> +Action: PORT_ID
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: test_original
> +------------------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, direct the packet to
> the original DPDK port ID) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> port_id original / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has been directed to the original
> DPDK port ID of the device.
> +
> +Test Case: test_id
> +------------------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, direct the packet to
> the DPDK port of id 1) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> port_id id 1 / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has been directed to the DPDK port
> of id 1.
> +
> +
> +Action: METER
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: meter test
> +------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, apply a MTR object
> with id 1) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> meter mtr_id 1 / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had MTR object with id 1
> applied to it.
> +
> +Action: SECURITY
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: security test
> +----------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, apply security session
> of id 1) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> security security_session 1 / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had security session 1 applied
> to it.
> +
> +
> +Action: OF_SET_MPLS_TTL
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: of_set_mpls_ttl test
> +---------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, implement MPLS TTL
> with a value of 64) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> of_set_mpls_ttl mpls_ttl 64 / end
> +
> +..
> +
> +3. Send a packet that matches the rule, with an MPLS layer with assigned ttl:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / MPLS(label = 0xab, ttl=128) / UDP() /
> ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule, with MPLS layers with assigned ttl:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / MPLS(label = 0xab, ttl=128) / UDP() /
> ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / MPLS(label = 0xab, ttl=128) / UDP() /
> ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / MPLS(label = 0xab, ttl=128) / UDP() /
> ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / MPLS(label = 0xab, ttl=128) / UDP()
> / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its MPLS ttl defined as 64.
> +
> +Action: OF_DEC_MPLS_TTL
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: of_dec_mpls_ttl test
> +---------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, decrement the MPLS
> ttl value) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> of_dec_mpls_ttl / end
> +
> +..
> +
> +3. Send a packet that matches the rule, with an MPLS layer with assigned ttl:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / MPLS(label = 0xab, ttl=128) / UDP() /
> ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule, with MPLS layers with assigned ttl:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / MPLS(label = 0xab, ttl=128) / UDP() /
> ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / MPLS(label = 0xab, ttl=128) / UDP() /
> ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / MPLS(label = 0xab, ttl=128) / UDP() /
> ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / MPLS(label = 0xab, ttl=128) / UDP()
> / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its MPLS ttl decremented.
> +
> +
> +Action: OF_SET_NW_TTL
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: of_set_nw_ttl test
> +---------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, implement IP TTL
> with a value of 64) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> of_set_nw_ttl nw_ttl 64 / end
> +
> +..
> +
> +3. Send a packet that matches the rule, with a defined TTL in the IP layer:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\", ttl=128)  / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule, with a defined TTL in the IP layer:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\", ttl = 128) / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\", ttl = 128) / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\", ttl = 128) /  UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\", ttl = 128) / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its IP TTL defined as 64.
> +
> +
> +Action: OF_DEC_NW_TTL
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: of_dec_nw_ttl test
> +---------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, decrease the IP TTL) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> of_dec_nw_ttl / end
> +
> +..
> +
> +3. Send a packet that matches the rule, with a defined TTL in the IP layer:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\", ttl=128 )  / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule, with a defined TTL in the IP layer:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\", ttl = 128) / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\", ttl = 128) / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\", ttl = 128) /  UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\", ttl = 128) / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its IP TTL decremented.
> +
> +Action: OF_COPY_TTL_OUT
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: of_copy_ttl_out test
> +---------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, copy the TTL
> outwards) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> of_copy_ttl_out / end
> +
> +..
> +
> +3. Send a packet that matches the rule, with a defined TTL in the IP layer:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\")  / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule, with a defined TTL in the IP layer:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\", ttl = 128) / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\", ttl = 128) / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\", ttl = 128) /  UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\", ttl = 128) / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its TTL copied outwards.
> +
> +Action: OF_COPY_TTL_IN
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: of_copy_ttl_in test
> +---------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, copy the TTL
> inwards) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> of_copy_ttl_in / end
> +
> +..
> +
> +3. Send a packet that matches the rule, with a defined TTL in the IP layer:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\")  / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule, with a defined TTL in the IP layer:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\", ttl = 128) / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\", ttl = 128) / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\", ttl = 128) /  UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\", ttl = 128) / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its TTL copied inwards.
> +
> +Action: OF_POP_VLAN
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: of_pop_vlan test
> +---------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, pop the outer VLAN
> tag) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> of_pop_vlan / end
> +
> +..
> +
> +3. Send a packet that matches the rule, with a defined VLAN layer/tag:
> +
> +::
> +
> +    Pkt0 = Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"192.168.0.1\")  / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule, with defined VLAN layers/tags:
> +
> +::
> +
> +    Pkt1 = Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) / IP(src=\"8.8.8.8\")
> /  UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its outer (only) VLAN tag
> popped.
> +
> +Action: OF_PUSH_VLAN
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: of_push_vlan test
> +---------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, push a new VLAN tag
> with EtherType 0x8100) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> of_push_vlan ethertype 0x8100 / end
> +
> +..
> +
> +3. Send a packet that matches the rule, with a defined VLAN layer/tag:
> +
> +::
> +
> +    Pkt0 = Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"192.168.0.1\")  / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule, with defined VLAN layers/tags:
> +
> +::
> +
> +    Pkt1 = Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) / IP(src=\"8.8.8.8\")
> /  UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had a VLAN tag with EtherType
> 0x8100 pushed onto it.
> +
> +Action: OF_SET_VLAN_VID
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +
> +Test Case: of_set_vlan_vid test
> +---------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, set the VLAN vid to
> 0xbbb):
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> of_set_vlan_vid 0xbbb / end
> +
> +..
> +
> +3. Send a packet that matches the rule, with a defined VLAN layer/tag:
> +
> +::
> +
> +    Pkt0 = Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"192.168.0.1\")  / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule, with defined VLAN layers/tags:
> +
> +::
> +
> +    Pkt1 = Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) / IP(src=\"8.8.8.8\")
> /  UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its VLAN vid set to 0xbbb.
> +
> +Action: OF_SET_VLAN_PCP
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: of_set_vlan_pcp test
> +---------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, set the VLAN pcp to
> 0x7):
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> of_set_vlan_pcp 0x7 / end
> +
> +..
> +
> +3. Send a packet that matches the rule, with a defined VLAN layer/tag:
> +
> +::
> +
> +    Pkt0 = Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"192.168.0.1\")  / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule, with defined VLAN layers/tags:
> +
> +::
> +
> +    Pkt1 = Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) / IP(src=\"8.8.8.8\")
> /  UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) /
> IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its VLAN pcp set to 0x7.
> +
> +Action: OF_POP_MPLS
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: of_pop_mpls test
> +---------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, pop the outer MPLS
> tag) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> of_pop_mpls / end
> +
> +..
> +
> +3. Send a packet that matches the rule, with a defined MPLS layer/tag:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\")  / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule, with defined MPLS layers/tags:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") /  MPLS(label = 0xab, ttl=128) / UDP()
> / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") /  MPLS(label = 0xab, ttl=128) / UDP() /
> ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / MPLS(label = 0xab, ttl=128) / UDP() /
> ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") /  MPLS(label = 0xab, ttl=128) /
> UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its outer (only) MPLS tag
> popped.
> +
> +Action: OF_PUSH_MPLS
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: of_push_mpls test
> +---------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, push a new MPLS tag
> with EtherType 0x0806) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> of_push_mpls ethertype 0x0806 / end
> +
> +..
> +
> +3. Send a packet that matches the rule, with a defined MPLS layer/tag:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\")  / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule, with defined MPLS layers/tags:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") /  MPLS(label = 0xab, ttl=128) / UDP()
> / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") /  MPLS(label = 0xab, ttl=128) / UDP() /
> ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / MPLS(label = 0xab, ttl=128) / UDP() /
> ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") /  MPLS(label = 0xab, ttl=128) /
> UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had an MPLS tag with
> EtherType 0x0806 pushed onto it.
> +
> +
> +Action: VXLAN_ENCAP
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +Test Case: vxlan_encap
> +---------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, encapsulate with a
> VXLAN tag with overlay definition (vni) 0x112233) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> vxlan_encap definition 0x112233 / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\")  / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") /  UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") /  UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") /  UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has been encapsulated with a
> VXLAN tag with vni 0x112233.
> +
> +Action: VXLAN_DECAP
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: vxlan_decap
> +---------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, strip all VXLAN
> headers :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> vxlan_decap / end
> +
> +..
> +
> +3. Send a packet that matches the rule, with a VXLAN header:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\")  / UDP() / VXLAN() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule, with VXLAN headers:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") /  UDP() / VXLAN() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") /  UDP() / VXLAN() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP() / VXLAN() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / UDP() / VXLAN()/  ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its VXLAN header stripped.
> +
> +Action: RAW_ENCAP
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: test_data
> +---------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, encapsulate with a
> VLAN tag with the header value 0x8100aaaa:
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> raw_encap data 0x8100aaaa / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\")  / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has been encapsulated with a VLAN
> tag with the header value 0x8100aaaa.
> +
> +Test Case: test_preserve
> +---------------------------------
> +
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1,
> +encapsulate with a VLAN tag with the header value of 0x8100aaaa and a
> preserve bitmask of 0xffffffff:
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> raw_encap data 0x8100aaaa preserve 0xffffffff / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\")  / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") /  UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has been encapsulated with a VLAN
> tag with the header value 0x8100aaaa
> +and has a preserve bitmask of 0xffffffff.
> +
> +Test Case: test_size
> +---------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1,
> +encapsulate with a VLAN tag with the header value of 0x8100aaaa and a data
> (header) size of 32.
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> raw_encap data 0x8100aaaa size 32/ end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\")  / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") /  UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has been encapsulated with a VLAN
> tag with the header value 0x8100aaaa
> +and has a size of 32.
> +
> +Action: RAW_DECAP
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: test_data
> +---------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, decapsulate a VLAN
> tag with the header value 0x8100aaaa:
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> raw_decap data 0x8100aaaa / end
> +
> +..
> +
> +3. Send a packet that matches the rule, with a matching VLAN header:
> +
> +::
> +
> +    Pkt0 = Ether() /  Dot1Q(prio = 0x5, id = 0x0, vlan = 0xbbb) /
> IP(src=\"192.168.0.1\")  / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule, with matching VLAN headers:
> +
> +::
> +
> +    Pkt1 = Ether() /  Dot1Q(prio = 0x5, id = 0x0, vlan = 0xbbb) /
> IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() /  Dot1Q(prio = 0x5, id = 0x0, vlan = 0xbbb) /
> IP(src=\"10.0.30.99\") /  UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() /  Dot1Q(prio = 0x5, id = 0x0, vlan = 0xbbb) / IP(src=\"8.8.8.8\")
> / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() /  Dot1Q(prio = 0x5, id = 0x0, vlan = 0xbbb) /
> IP(src=\"132.177.0.99\") /  UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its VLAN tag decapsulated.
> +
> +
> +Test Case: test_size
> +---------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, decapsulate a VLAN
> tag with the header value 0x8100aaaa
> +and header size of 32:
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> raw_decap data 0x8100aaaa size 32 / end
> +
> +..
> +
> +3. Send a packet that matches the rule, with a matching VLAN header:
> +
> +::
> +
> +    Pkt0 = Ether() /  Dot1Q(prio = 0x5, id = 0x0, vlan = 0xbbb) /
> IP(src=\"192.168.0.1\")  / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule, with matching VLAN headers:
> +
> +::
> +
> +    Pkt1 = Ether() /  Dot1Q(prio = 0x5, id = 0x0, vlan = 0xbbb) /
> IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() /  Dot1Q(prio = 0x5, id = 0x0, vlan = 0xbbb) /
> IP(src=\"10.0.30.99\") /  UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() /  Dot1Q(prio = 0x5, id = 0x0, vlan = 0xbbb) / IP(src=\"8.8.8.8\")
> / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() /  Dot1Q(prio = 0x5, id = 0x0, vlan = 0xbbb) /
> IP(src=\"132.177.0.99\") /  UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its VLAN tag of size 32
> decapsulated.
> +
> +Action: SET_IPV4_SRC
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: set_ipv4_src test
> +----------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, set the ipv4 src to
> 172.16.0.10) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> set_ipv4_src ipv4_addr 172.16.0.10 / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its IPv4 source address set
> to 172.16.0.10.
> +
> +
> +Action: SET_IPV4_DST
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: set_ipv4_dst test
> +----------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 destination is 192.168.0.1, set the ipv4 dst
> to 172.16.0.10) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 dst is 192.168.0.1 / udp / end actions
> set_ipv4_dst ipv4_addr 172.16.0.10 / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(dst=\"192.168.0.1\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(dst=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(dst=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(dst=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(dst=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its IPv4 destination address
> set to 172.16.0.10.
> +
> +Action: SET_IPV6_SRC
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: set_ipv6_src test
> +----------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv6 source is
> 2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c2,
> +set the ipv6 source to 2001:0000:9d38:6ab8:1c48:9999:aaaa:bbbb) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv6 src is
> 2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c2 / udp /
> +    end actions set_ipv6_src ipv6_addr
> 2001:0000:9d38:6ab8:1c48:9999:aaaa:bbbb / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c2\") /
> UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c3\") /
> UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c4\") /
> UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c5\") /
> UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c6\") /
> UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its IPv6 source address set
> to 2001:0000:9d38:6ab8:1c48:9999:aaaa:bbbb.
> +
> +Action: SET_IPV6_DST
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: set_ipv6_dst test
> +----------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv6 destination is
> 2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c2,
> +set the ipv6 dst to 2001:0000:9d38:6ab8:1c48:9999:aaaa:bbbb) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv6 src is
> 2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c2 / udp /
> +    end actions set_ipv6_dst ipv6_addr
> 2001:0000:9d38:6ab8:1c48:9999:aaaa:bbbb / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IPv6(dst=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c2\") /
> UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IPv6(dst=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c3\") /
> UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IPv6(dst=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c4\") /
> UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IPv6(dst=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c5\") /
> UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IPv6(dst=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c6\") /
> UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its IPv6 destination address
> set to  2001:0000:9d38:6ab8:1c48:9999:aaaa:bbbb.
> +
> +Action: SET_TP_SRC
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: test_udp
> +----------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, set the tcp/udp
> source port to 1998:
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> set_tp_src 1998/ end
> +
> +..
> +
> +3. Send a packet that matches the rule with a defined UDP source port:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / UDP(sport=3838) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule with defined UDP source ports:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / UDP(sport=3838) / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / UDP(sport=3838) / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP(sport=3838) / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / UDP(sport=3838) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its UDP source port set to
> 1998.
> +
> +Test Case: test_tcp
> +----------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, set the tcp/udp
> source port to 1998:
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / tcp / end actions
> set_tp_src 1998 / end
> +
> +..
> +
> +3. Send a packet that matches the rule with a defined TCP source port:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / TCP(sport=3838) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule with defined TCP source ports:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / TCP(sport=3838) / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / TCP(sport=3838) / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / TCP(sport=3838) / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / TCP(sport=3838) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its TCP source port set to
> 1998.
> +
> +Action: SET_TP_DST
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +
> +Test Case: test_udp
> +----------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 destination is 192.168.0.1, set the tcp/udp
> destination port to 1998:
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> set_tp_dst 1998/ end
> +
> +..
> +
> +3. Send a packet that matches the rule with a defined UDP destination port:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / UDP(dport=3838) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule with defined UDP destination ports:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / UDP(dport=3838) / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / UDP(dport=3838) / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP(dport=3838) / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / UDP(dport=3838) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its UDP destination port set
> to 1998.
> +
> +Test Case: test_tcp
> +----------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, set the tcp/udp
> destination port to 1998:
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / tcp / end actions
> set_tp_dst 1998 / end
> +
> +..
> +
> +3. Send a packet that matches the rule with a defined TCP destination port:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / TCP(dport=3838) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule with defined TCP destination ports:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / TCP(dport=3838) / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / TCP(dport=3838) / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / TCP(dport=3838) / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / TCP(dport=3838) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its TCP destination port set
> to 1998.
> +Action: SET_TTL
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: set_ttl test
> +---------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, set TTL to a value of
> 64) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> set_ttl ttl_value 64 / end
> +
> +..
> +
> +3. Send a packet that matches the rule, with a defined TTL in the IP layer:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\", ttl=128)  / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule, with a defined TTL in the IP layer:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\", ttl = 128) / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\", ttl = 128) / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\", ttl = 128) /  UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\", ttl = 128) / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its TTL defined as 64.
> +
> +Action: SET_MAC_SRC
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: set_mac_src test
> +------------------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, set MAC src to
> 10:20:30:40:50:60) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> set_mac_src mac_addr 10:20:30:40:50:60 / end
> +
> +..
> +
> +3. Send a packet that matches the rule, with a defined src MAC address:
> +
> +::
> +
> +    Pkt0 = Ether(src=\"90:61:ae:fd:41:43\") / IP(src=\"192.168.0.1\") / UDP() /
> ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule, with defined src MAC addresses:
> +
> +::
> +
> +    Pkt1 = Ether(src=\"90:61:ae:fd:41:43\") / IP(src=\"192.168.0.2\") / UDP() /
> ('\\x00' * 64)
> +    Pkt2 = Ether(src=\"90:61:ae:fd:41:43\" ) / IP(src=\"10.0.30.99\") / UDP() /
> ('\\x00' * 64)
> +    Pkt3 = Ether(src=\"90:61:ae:fd:41:43\" ) / IP(src=\"8.8.8.8\") / UDP() / ('\\x00'
> * 64)
> +    Pkt4 = Ether(src=\"90:61:ae:fd:41:43\" ) / IP(src=\"132.177.0.99\") / UDP() /
> ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its source MAC address set
> to 10:20:30:40:50:60.
> +
> +Action: SET_MAC_DST
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: set_mac_dst test
> +------------------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, set MAC dst to
> 10:20:30:40:50:60) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> set_mac_dst mac_addr 10:20:30:40:50:60 / end
> +
> +..
> +
> +3. Send a packet that matches the rule, with a defined dst MAC address:
> +
> +::
> +
> +    Pkt0 = Ether(src=\"90:61:ae:fd:41:43\") / IP(dst =\"192.168.0.1\") / UDP() /
> ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule, with defined dst MAC addresses:
> +
> +::
> +
> +    Pkt1 = Ether(dst=\"90:61:ae:fd:41:43\") / IP(src=\"192.168.0.2\") / UDP() /
> ('\\x00' * 64)
> +    Pkt2 = Ether(dst=\"90:61:ae:fd:41:43\" ) / IP(src=\"10.0.30.99\") / UDP() /
> ('\\x00' * 64)
> +    Pkt3 = Ether(dst=\"90:61:ae:fd:41:43\" ) / IP(src=\"8.8.8.8\") / UDP() /
> ('\\x00' * 64)
> +    Pkt4 = Ether(dst=\"90:61:ae:fd:41:43\" ) / IP(src=\"132.177.0.99\") / UDP() /
> ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its destination MAC address
> set to 10:20:30:40:50:60.
> +
> +Action: INC_TCP_SEQ
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: inc_tcp_seq test
> +----------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, increase the TCP seq
> value:
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / tcp / end actions
> inc_tcp_seq / end
> +
> +..
> +
> +3. Send a packet that matches the rule with a defined TCP seq value:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / TCP(seq=2) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule with defined TCP seq values:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / TCP(seq=2) / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / TCP(seq=2) / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / TCP(seq=2) / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / TCP(seq=2) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its TCP seq value increased.
> +
> +Action: DEC_TCP_SEQ
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: dec_tcp_seq test
> +----------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, decrease the TCP seq
> value:
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / tcp / end actions
> dec_tcp_seq / end
> +
> +..
> +
> +3. Send a packet that matches the rule with a defined TCP seq value:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / TCP(seq=2) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule with defined TCP seq values:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / TCP(seq=2) / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / TCP(seq=2) / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / TCP(seq=2) / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / TCP(seq=2) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its TCP seq value decreased.
> +
> +Action: INC_TCP_ACK
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: inc_tcp_ack test
> +----------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, increase the TCP ack
> value:
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / tcp / end actions
> inc_tcp_ack / end
> +
> +..
> +
> +3. Send a packet that matches the rule with a defined TCP ack value:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / TCP(ack=2) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule with defined TCP ack values:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / TCP(ack=2) / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / TCP(ack=2) / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / TCP(ack=2) / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / TCP(ack=2) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its TCP ack value increased.
> +
> +Action: DEC_TCP_ACK
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: dec_tcp_ack test
> +----------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, decrease the TCP ack
> value:
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / tcp / end actions
> dec_tcp_ack / end
> +
> +..
> +
> +3. Send a packet that matches the rule with a defined TCP ack value:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / TCP(ack=2) / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule with defined TCP ack values:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / TCP(ack=2) / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / TCP(ack=2) / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / TCP(ack=2) / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / TCP(ack=2) / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its TCP ack value decreased.
> +
> +Action: SET_TAG
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: test_data
> +------------------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, tag the packet with
> the value 0xabc) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> set_tag data 0xabc / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has been tagged with the correct
> data.
> +
> +Test Case: test_mask
> +------------------------------------------------
> +
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, tag the packet with
> the value 0xabc and mask 0xcba) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> set_tag data 0xabc mask 0xcba / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has been tagged with the correct
> data and mask.
> +
> +
> +Test Case: test_index
> +------------------------------------------------
> +
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, set the packet tag
> index 1 to the value 0xabc) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> set_tag data 0xabc index 1 / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has been tagged with the correct
> data on the correct tag index.
> +
> +
> +Action: SET_META
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: test_data
> +------------------------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, set the packet's meta
> to the value 0xabc) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> set_meta data 0xabc / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had the correct metadata
> assigned to it.
> +
> +Test Case: test_mask
> +------------------------------------------------
> +
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, set the packet's meta
> to the value 0xabc and mask 0xcba):
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> set_meta data 0xabc mask 0xcba / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had the correct metadata and
> mask assigned to it.
> +
> +Action: SET_IPV4_DSCP
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: set_ipv4_dscp test
> +-------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, set the IPv4 dscp (tos)
> to 2) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> set_ipv4_dscp 2 / end
> +
> +..
> +
> +3. Send a packet that matches the rule with a defined dscp (tos) value:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule with defined dscp (tos) values:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its IPv4 dscp (tos) value set
> to 2.
> +
> +
> +Action: SET_IPV6_DSCP
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: set_ipv6_dscp test
> +-------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv6 src is
> 2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c2, set its dscp (tc) value to 0x30):
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv6 src is
> 2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c2 / udp /
> +    end actions set_ipv6_dscp dscp 0x30 / end
> +
> +..
> +
> +3. Send a packet that matches the rule, with a defined dscp (tc) value:
> +
> +::
> +
> +    Pkt0 = Ether() / IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c3\",
> tc=0) / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule, with defined dscp (tc) values:
> +
> +::
> +
> +    Pkt1 = Ether() / IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c3\",
> tc=0) / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c4\",
> tc=0) / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c5\",
> tc=0) / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c6\",
> tc=0) / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its dscp (tc) value set to
> 0x30.
> +
> +Action: AGE
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +Test Case: test_timeout
> +-------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, set the aging timeout
> value to 128) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> age timeout 128 / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its aging timeout value set
> to 128.
> +
> +Test Case: test_reserved
> +-------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, set the aging timeout
> value to 128 and reserved to 0) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> age timeout 128 reserved 0 / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its aging timeout value set
> to 128 and reserved bits set to 0.
> +
> +Test Case: test_context
> +-------------------------------
> +
> +1. Run testpmd in interactive mode with one port bound and available:
> +
> +::
> +
> +    build/testpmd -c 3 -- -i
> +
> +..
> +
> +2. Set the test flow rule (If the IPv4 source is 192.168.0.1, set the aging timeout
> value to 128
> +   and flow context to the rte_flow pointer) :
> +
> +::
> +
> +    flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions
> age timeout 128 context NULL / end
> +
> +..
> +
> +3. Send a packet that matches the rule:
> +
> +::
> +
> +    Pkt0 = Ether() / IP(src=\"192.168.0.1\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +4. Send packets that do not match the rule:
> +
> +::
> +
> +    Pkt1 = Ether() / IP(src=\"192.168.0.2\") / UDP() / ('\\x00' * 64)
> +    Pkt2 = Ether() / IP(src=\"10.0.30.99\") / UDP() / ('\\x00' * 64)
> +    Pkt3 = Ether() / IP(src=\"8.8.8.8\") / UDP() / ('\\x00' * 64)
> +    Pkt4 = Ether() / IP(src=\"132.177.0.99\") / UDP() / ('\\x00' * 64)
> +
> +..
> +
> +5. Check to make sure that the pass packet has had its aging timeout value set
> to 128 and its user flow context
> +set to the rte_flow pointer.
> +
> +
> +
> +
> +
> +
> diff --git a/test_plans/rte_flow_unsupported.rst
> b/test_plans/rte_flow_unsupported.rst
> new file mode 100644
> index 00000000..9df894f3
> --- /dev/null
> +++ b/test_plans/rte_flow_unsupported.rst
> @@ -0,0 +1,130 @@
> +.. # BSD LICENSE
> +    #
> +    # Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
> +    # Copyright © 2018[, 2020] The University of New Hampshire. All rights
> reserved.
> +    # All rights reserved.
> +    #
> +    # Redistribution and use in source and binary forms, with or without
> +    # modification, are permitted provided that the following conditions
> +    # are met:
> +    #
> +    #   * Redistributions of source code must retain the above copyright
> +    #     notice, this list of conditions and the following disclaimer.
> +    #   * Redistributions in binary form must reproduce the above copyright
> +    #     notice, this list of conditions and the following disclaimer in
> +    #     the documentation and/or other materials provided with the
> +    #     distribution.
> +    #   * Neither the name of Intel Corporation nor the names of its
> +    #     contributors may be used to endorse or promote products derived
> +    #     from this software without specific prior written permission.
> +    #
> +    # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> CONTRIBUTORS
> +    # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
> NOT
> +    # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
> FITNESS FOR
> +    # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
> COPYRIGHT
> +    # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> INCIDENTAL,
> +    # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> NOT
> +    # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
> OF USE,
> +    # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
> ON ANY
> +    # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
> TORT
> +    # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
> THE USE
> +    # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> DAMAGE.
> +
> +rte_flow Items and Properties Not Supported by testpmd
> +=======================================================
> +The following rte_flow pattern items and properties are currently unsupported
> by testpmd. As a result, they cannot be tested at this time.
> +
> +These items and properties are intended to be a part of
> **test_plans/flow_pattern_item_test_plan.rst**.
> +
> +Sample test cases for these properties have been written with the other
> rte_flow pattern item/property tests, but are left as comments as they cannot
> be used at this time.
> +
> +
> +Item: ARP
> +~~~~~~~~~
> +ARP is not supported, along with all of its properties:
> +
> +- hdr (hardware type)
> +- pro (protocol type)
> +- hln (hardware address length)
> +- pln (protocol address length)
> +- op (opcode)
> +- sha (sender hardware address)
> +- spa (sender ipv4 address)
> +- tha (target hardware address)
> +- tpa (target ipv4 address)
> +
> +Item: GRE
> +~~~~~~~~~
> +
> +The following property is not supported by testpmd:
> +
> +- c_rsvd0_ver (checksum + reserved0 + version)
> +
> +Item: ICMP
> +~~~~~~~~~~
> +
> +The following properties are not supported by testpmd:
> +
> +- icmp_cksum (checksum)
> +- icmp_ident (identifier)
> +- icmp_seq_nb (sequence number)
> +
> +Item: ICMP6
> +~~~~~~~~~~~
> +ICMP6 is not supported, along with all of its properties:
> +
> +- type
> +- code
> +- checksum
> +
> +Item: IPv4
> +~~~~~~~~~~~
> +The following property is not supported by testpmd:
> +
> +- checksum
> +
> +Item: IPv6
> +~~~~~~~~~~~
> +The following properties are not supported by testpmd:
> +
> +- vtc_flow (version + traffic class + flow)
> +- payload_len (payload length)
> +
> +Item: TCP
> +~~~~~~~~~~~
> +The following properties are not supported by testpmd:
> +
> +- data_off (data offset)
> +- rx_win (window size)
> +- cksum (checksum)
> +
> +
> +Item: UDP
> +~~~~~~~~~~~
> +The following properties are not supported by testpmd:
> +
> +- dgram_len (datagram length)
> +- dgram_cksum (datagram checksum)
> +
> +Item: VXLAN
> +~~~~~~~~~~~
> +The following properties are not supported by testpmd:
> +
> +- rsvd0
> +- rsvd1
> +- flags
> +
> +Item: VXLAN_GPE
> +~~~~~~~~~~~~~~~
> +VXLAN_GPE is not supported, along with all of its properties:
> +
> +
> +- rsvd0
> +- rsvd1
> +- flags
> +- vni
> +- protocol
> +
> +
> +
> +
> diff --git a/tests/TestSuite_rte_flow.py b/tests/TestSuite_rte_flow.py
> new file mode 100644
> index 00000000..56277a18
> --- /dev/null
> +++ b/tests/TestSuite_rte_flow.py
> @@ -0,0 +1,232 @@
> +# BSD LICENSE
> +#
> +# Copyright(c) 2020 Intel Corporation. All rights reserved.
> +# Copyright © 2018[, 2019] The University of New Hampshire. All rights
> reserved.
> +# All rights reserved.
> +#
> +# Redistribution and use in source and binary forms, with or without
> +# modification, are permitted provided that the following conditions
> +# are met:
> +#
> +#   * Redistributions of source code must retain the above copyright
> +#     notice, this list of conditions and the following disclaimer.
> +#   * Redistributions in binary form must reproduce the above copyright
> +#     notice, this list of conditions and the following disclaimer in
> +#     the documentation and/or other materials provided with the
> +#     distribution.
> +#   * Neither the name of Intel Corporation nor the names of its
> +#     contributors may be used to endorse or promote products derived
> +#     from this software without specific prior written permission.
> +#
> +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> CONTRIBUTORS
> +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
> FOR
> +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
> COPYRIGHT
> +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> INCIDENTAL,
> +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
> NOT
> +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> USE,
> +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
> ON ANY
> +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
> THE USE
> +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> +
> +"""
> +DPDK Test suite.
> +MTU Checks example.
> +"""
> +import time
> +import ipaddress
> +from typing import Callable
> +
> +import utils
> +from pmd_output import PmdOutput
> +from test_case import TestCase
> +
> +from test_case import TestCase
> +
> +from framework.flow import generator
> +
> +
> +class RteFlow(TestCase):
> +    #
> +    #
> +    # Helper methods and setup methods.
> +    #
> +    # Some of these methods may not be used because they were inlined from a
> child
> +    # of TestCase. This was done because the current test system doesn't
> support
> +    # inheritance.
> +    #
> +    def exec(self, command: str) -> str:
> +        """
> +        An abstraction to remove repeated code throughout the subclasses of this
> class
> +        """
> +        return self.dut.send_expect(command, "testpmd>")
> +
> +    def get_mac_address_for_port(self, port_id: int) -> str:
> +        return self.dut.get_mac_address(port_id)
> +
> +    def send_scapy_packet(self, port_id: int, packet: str):
> +        itf = self.tester.get_interface(port_id)
> +        return self.tester.send_expect(f'sendp({packet}, iface="{itf}")', ">>>",
> timeout=30)
> +
> +    def set_up_all(self):
> +        """
> +        Prerequisite steps for each test suit.
> +        """
> +        self.dut_ports = self.dut.get_ports()
> +        self.verify(len(self.dut_ports) >= 2, "Insufficient ports")
> +        self.rx_port = self.dut_ports[0]
> +        self.tx_port = self.dut_ports[1]
> +
> +        self.pmdout = PmdOutput(self.dut)
> +        self.pmdout.start_testpmd("default", "--rxq 2 --txq 2")
> +        self.exec("set verbose 3")
> +        self.exec("set fwd rxonly")
> +        self.tester.send_expect("scapy", ">>>")
> +
> +    def initialize_flow_rule(self, rule: str):
> +        output: str = self.exec(f"flow validate {self.dut_ports[0]} {rule}")
> +        if "Unsupported pattern" in output:
> +            return False
> +
> +        output = self.exec(f"flow create {self.dut_ports[0]} {rule}")
> +        self.verify("created" in output or "Flow rule validated" in output, "Flow rule
> was not created: " + output)
> +        return True
> +
> +    def send_packets(self, packets, pass_fail_function: Callable[[str], bool],
> error_message: str):
> +        for packet in packets:
> +            output = self.send_scapy_packet(0, packet)
> +            time.sleep(5)  # Allow the packet to be processed
> +            self.verify("Sent" in output, "Broken scapy packet definiton: " + packet)
> +            output = self.pmdout.get_output()
> +            self.verify(pass_fail_function(output),
> +                        error_message + "\r\n" + output)
> +
> +    def do_test_with_callable_tests_for_pass_fail(self, rule: str, pass_packets:
> frozenset, fail_packets: frozenset,
> +                                                  pass_check_function: Callable[[str], bool],
> +                                                  fail_check_function: Callable[[str], bool],
> +                                                  error_message: str):
> +        was_valid: bool = self.initialize_flow_rule(rule)
> +        if not was_valid:  # If a PMD rejects a test case, we let it pass
> +            return None
> +
> +        self.exec("start")
> +        self.send_packets(pass_packets, pass_check_function, error_message)
> +        self.send_packets(fail_packets, fail_check_function, error_message)
> +
> +    def do_test_with_expected_strings_for_pass_fail(self, rule: str,
> pass_packets: frozenset,
> +                                                    fail_packets: frozenset,
> +                                                    pass_expect: str, fail_expect: str, error_message:
> str):
> +        self.do_test_with_callable_tests_for_pass_fail(rule, pass_packets,
> fail_packets,
> +                                                       lambda output: pass_expect in output,
> +                                                       lambda output: fail_expect in output,
> +                                                       error_message)
> +
> +    def do_test_with_queue_action(self, rule: str, pass_packets: frozenset,
> fail_packets: frozenset):
> +        self.do_test_with_expected_strings_for_pass_fail(rule, pass_packets,
> fail_packets,
> +                                                         f"port {self.dut_ports[0]}/queue 1",
> +                                                         f"port {self.dut_ports[0]}/queue 0",
> +                                                         "Error: packet went to the wrong queue")
> +
> +    def set_up(self):
> +        """
> +        This is to clear up environment before the case run.
> +        """
> +
> +    def tear_down(self):
> +        """
> +        Run after each test case.
> +        """
> +        self.exec(f"flow flush {self.dut_ports[0]}")
> +        self.exec("stop")
> +
> +    def tear_down_all(self):
> +        """
> +        When the case of this test suite finished, the environment should
> +        clear up.
> +        """
> +        self.tester.send_expect("exit()", "#")
> +        self.dut.kill_all()
> +        self.tester.kill_all()
> +
> +    """
> +    Edge Cases
> +
> +    These are tests which are designed to deal with edge cases.
> +    """
> +
> +    def test_excessive_voids(self):
> +        """
> +        This test puts far, far too many void tokens in an otherwise valid
> +        pattern. This may cause a crash or other issue, due to buffer size
> +        constraints or other limits inside of either the parser or the nic.
> +        """
> +        self.do_test_with_queue_action(
> +            "ingress pattern eth / ipv4 / " + (
> +                    "void / " * 200) + "udp / end actions queue index 1 / end",
> +            frozenset({'Ether() / IP() / UDP() / (\'\\x00\' * 64)'}),
> +            frozenset({
> +                'Ether() / IP() / TCP() / (\'\\x00\' * 64)',
> +                'Ether() / IP() / SCTP() / (\'\\x00\' * 64)',
> +                'Ether() / IPv6() / UDP() / (\'\\x00\' * 64)',
> +            })
> +        )
> +
> +    def test_excessive_tunneling(self):
> +        self.do_test_with_queue_action(
> +            "ingress pattern " + ("eth / gre / " * 20) + "eth / ipv4 / udp / end actions
> queue index 1 / end",
> +            frozenset({'Ether() / IP() / UDP() / (\'\\x00\' * 64)'}),
> +            frozenset({
> +                'Ether() / IP() / TCP() / (\'\\x00\' * 64)',
> +                'Ether() / IP() / SCTP() / (\'\\x00\' * 64)',
> +                'Ether() / IPv6() / UDP() / (\'\\x00\' * 64)',
> +            })
> +        )
> +
> +    """
> +    Action Test Cases
> +
> +    These are test cases built for testing various actions
> +    """
> +
> +    def test_drop_case1(self):
> +        self.do_test_with_callable_tests_for_pass_fail(
> +            "ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions drop /
> end",
> +            frozenset({'Ether() / IP(src="192.168.0.1") / UDP() / (\'\\x00\' * 64)'}),
> +            frozenset({'Ether() / IP(src="10.0.30.99") / UDP() / (\'\\x00\' * 64)',
> +                       'Ether() / IP(src="132.177.0.99") / UDP() / (\'\\x00\' * 64)',
> +                       'Ether() / IP(src="192.168.0.2") / UDP() / (\'\\x00\' * 64)',
> +                       'Ether() / IP(src="8.8.8.8") / UDP() / (\'\\x00\' * 64)'}),
> +            lambda output: "port" not in output,
> +            lambda output: "port" in output,
> +            "Drop function was not correctly applied")
> +
> +    def test_queue_case1(self):
> +        self.do_test_with_queue_action(
> +            "ingress pattern eth / ipv4 src is 192.168.0.1 / udp / end actions queue
> index 1 / end",
> +            frozenset({'Ether() / IP(src="192.168.0.1") / UDP() / (\'\\x00\' * 64)'}),
> frozenset(
> +                {'Ether() / IP(src="10.0.30.99") / UDP() / (\'\\x00\' * 64)',
> +                 'Ether() / IP(src="132.177.0.99") / UDP() / (\'\\x00\' * 64)',
> +                 'Ether() / IP(src="192.168.0.2") / UDP() / (\'\\x00\' * 64)',
> +                 'Ether() / IP(src="8.8.8.8") / UDP() / (\'\\x00\' * 64)'}))
> +
> +
> +def do_runtime_test_generation():
> +    """
> +    There are enough tests for this suite that it presents a maintainability
> +    issue to keep using the generator manually, so this approach is designed
> +    """
> +    print("Generating test cases for RTE Flow test suite.")
> +    pattern_functions =
> generator.create_test_function_strings(generator.get_patterns_with_propertie
> s())
> +
> +    pattern_function_string = "\n".join(pattern_functions)
> +    exec(pattern_function_string)
> +
> +    # Copy it because a for loop creates local variables, which changes the dict
> at runtime.
> +    locals_copy = filter(lambda name_function_tuple:
> name_function_tuple[0].startswith("test_"), locals().items())
> +
> +    for name, function in locals_copy:
> +        setattr(RteFlow, name, function)
> +
> +
> +do_runtime_test_generation()
> --
> 2.25.1


  parent reply	other threads:[~2020-10-22  8:53 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-10-14 20:50 Owen Hilyard
2020-10-14 21:02 ` [dts] [PATCH] rte flow: fixing checkpatch issues Owen Hilyard
2020-10-22  8:53 ` Tu, Lijuan [this message]
2020-10-23 18:18   ` [dts] [PATCH] rte flow: added test suite and framework Owen Hilyard
2020-10-23 23:28     ` [dts] [PATCH v2 1/7] rte flow: add test plan and test suite Owen Hilyard
2020-10-23 23:28       ` [dts] [PATCH v2 2/7] rte flow: add supporting data structures Owen Hilyard
2020-10-23 23:28         ` [dts] [PATCH v2 3/7] rte flow: Add base flow type Owen Hilyard
2020-10-23 23:28           ` [dts] [PATCH v2 4/7] rte flow: add more specifc data structures Owen Hilyard
2020-10-23 23:29             ` [dts] [PATCH v2 5/7] rte flow: add action items Owen Hilyard
2020-10-23 23:29               ` [dts] [PATCH v2 6/7] rte flow: add pattern items Owen Hilyard
2020-10-23 23:29                 ` [dts] [PATCH v2 7/7] rte flow: add flow test generator Owen Hilyard
2020-10-23 23:29                   ` [dts] [PATCH v2] " Owen Hilyard
2020-10-23 23:30                     ` Owen Hilyard
2020-10-27  5:07       ` [dts] [PATCH v2 1/7] rte flow: add test plan and test suite Tu, Lijuan

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=f010c65a87f64ff2821a7df093ed7d46@intel.com \
    --to=lijuan.tu@intel.com \
    --cc=dts@dpdk.org \
    --cc=lihongx.ma@intel.com \
    --cc=lylavoie@iol.unh.edu \
    --cc=ohilyard@iol.unh.edu \
    --cc=shall@iol.unh.edu \
    --cc=yuan.peng@intel.com \
    --cc=zhaoyan.chen@intel.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

test suite reviews and discussions

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://inbox.dpdk.org/dts/0 dts/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 dts dts/ https://inbox.dpdk.org/dts \
		dts@dpdk.org
	public-inbox-index dts

Example config snippet for mirrors.
Newsgroup available over NNTP:
	nntp://inbox.dpdk.org/inbox.dpdk.dts


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git