From patchwork Fri Oct 23 23:29:01 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Owen Hilyard X-Patchwork-Id: 82029 Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 37DFDA04B0; Sat, 24 Oct 2020 01:29:27 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 2958F68F0; Sat, 24 Oct 2020 01:29:26 +0200 (CEST) Received: from mail-qt1-f174.google.com (mail-qt1-f174.google.com [209.85.160.174]) by dpdk.org (Postfix) with ESMTP id 759A768C3 for ; Sat, 24 Oct 2020 01:29:24 +0200 (CEST) Received: by mail-qt1-f174.google.com with SMTP id c15so2577120qtc.2 for ; Fri, 23 Oct 2020 16:29:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iol.unh.edu; s=unh-iol; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=+Zcz5JQ1sblTVTdk0BnOPDxicxSDjxw5YzKWfhjBAhE=; b=JMvs5MUPlrSApCUgUoJiFp6SCiDVJAeSqDD+MrzCJ+3fQqno0hRLYT18b6VRqzr7K/ yVW1XWFnQ7Mi29ayy767Secol7uvPh+xKHc1Fhs4TrpDUoSwiQ4NrNmNvAxvjQlxhbyS U3/3s7ezEd938bYsGWL7WguD1XAGIwv8WVBNE= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=+Zcz5JQ1sblTVTdk0BnOPDxicxSDjxw5YzKWfhjBAhE=; b=MFjabzX3flWE6vFwtF5G5D8whhd/aekpntozZ25mxZDLu4m8uznEhW4M0lDrk9RBak 4tjZq2LGiSntO7IHxXQp6XYcOxkONUUh6oK/7IeoDm1j6qQyZBI/haRGb3v09jsPn05s 7dzF+10912/QJvigLuREhIacD9qZg1p5a/NZ8HCuj7hidRYkimkO8eU/cA41c/l2rxzg MdGnU5LUXi8iX1BXG/8CaGf2/onyOzZ1xCifOQZLwJVQDycpRrBMOVBLofDG2bzBdsRV Wt8p8b94AqZkfF8cFvVy+YhFyWWSN5T/QySCXO86vJbK8hg1qbclmI2JkDf6tB4xMC2i 4aCQ== X-Gm-Message-State: AOAM531casa42DDafH+fCo4UQQsR849ltosBbNK+BE8ci/DZRN4sRnu6 iN3RyE/QzIP0K5ffhXDLv6HAug== X-Google-Smtp-Source: ABdhPJyQjMQsEUYw1mwK5MuIKOSlZUcIL2iQ8Va2NaF97QyIsqlfyRI3Xpbpoxlxu2AAx25/aV+DaQ== X-Received: by 2002:ac8:24c3:: with SMTP id t3mr4567081qtt.46.1603495762548; Fri, 23 Oct 2020 16:29:22 -0700 (PDT) Received: from ohilyard-Alienware-m17.iol.unh.edu (nt-238-66.w4.unh.edu. [132.177.238.66]) by smtp.googlemail.com with ESMTPSA id j16sm1851673qkg.26.2020.10.23.16.29.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 23 Oct 2020 16:29:22 -0700 (PDT) From: Owen Hilyard To: ohilyard@iol.unh.edu, dts@dpdk.org, lijuan.tu@intel.com Cc: shall@iol.unh.edu, lihongx.ma@intel.com, lylavoie@iol.unh.edu, zhaoyan.chen@intel.com, yuan.peng@intel.com Date: Fri, 23 Oct 2020 19:29:01 -0400 Message-Id: <20201023232903.37387-6-ohilyard@iol.unh.edu> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201023232903.37387-5-ohilyard@iol.unh.edu> References: <20201023232903.37387-1-ohilyard@iol.unh.edu> <20201023232903.37387-2-ohilyard@iol.unh.edu> <20201023232903.37387-3-ohilyard@iol.unh.edu> <20201023232903.37387-4-ohilyard@iol.unh.edu> <20201023232903.37387-5-ohilyard@iol.unh.edu> MIME-Version: 1.0 Subject: [dts] [PATCH v2 6/7] rte flow: add pattern items X-BeenThere: dts@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: test suite reviews and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dts-bounces@dpdk.org Sender: "dts" This file contains the pattern flow item definitions and supporting information. Signed-off-by: Owen Hilyard --- framework/flow/flow_pattern_items.py | 1102 ++++++++++++++++++++++++++ 1 file changed, 1102 insertions(+) create mode 100644 framework/flow/flow_pattern_items.py diff --git a/framework/flow/flow_pattern_items.py b/framework/flow/flow_pattern_items.py new file mode 100644 index 0000000..bb14306 --- /dev/null +++ b/framework/flow/flow_pattern_items.py @@ -0,0 +1,1102 @@ +# 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. + +# 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 flow.enums import FlowItemType +from flow.exceptions import InvalidFlowItemException +from 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 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, +}