From patchwork Wed Apr 6 15:19:01 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Juraj_Linke=C5=A1?= X-Patchwork-Id: 109321 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 0A61FA0509; Wed, 6 Apr 2022 17:21:51 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 62EA842986; Wed, 6 Apr 2022 17:19:33 +0200 (CEST) Received: from lb.pantheon.sk (lb.pantheon.sk [46.229.239.20]) by mails.dpdk.org (Postfix) with ESMTP id 9CDF64296F for ; Wed, 6 Apr 2022 17:19:30 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by lb.pantheon.sk (Postfix) with ESMTP id DFA17129C28; Wed, 6 Apr 2022 17:19:29 +0200 (CEST) X-Virus-Scanned: amavisd-new at siecit.sk Received: from lb.pantheon.sk ([127.0.0.1]) by localhost (lb.pantheon.sk [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id YVfQ1xsocuRG; Wed, 6 Apr 2022 17:19:27 +0200 (CEST) Received: from entguard.lab.pantheon.local (unknown [46.229.239.141]) by lb.pantheon.sk (Postfix) with ESMTP id 140C1184FE9; Wed, 6 Apr 2022 17:19:17 +0200 (CEST) From: =?utf-8?q?Juraj_Linke=C5=A1?= To: thomas@monjalon.net, david.marchand@redhat.com, Honnappa.Nagarahalli@arm.com, ohilyard@iol.unh.edu, lijuan.tu@intel.com Cc: dev@dpdk.org, =?utf-8?q?Juraj_Linke=C5=A1?= Subject: [RFC PATCH v1 21/23] dts: merge DTS framework/flow/flow_pattern_items.py to DPDK Date: Wed, 6 Apr 2022 15:19:01 +0000 Message-Id: <20220406151903.2916254-22-juraj.linkes@pantheon.tech> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220406151903.2916254-1-juraj.linkes@pantheon.tech> References: <20220406151903.2916254-1-juraj.linkes@pantheon.tech> MIME-Version: 1.0 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org --- dts/framework/flow/flow_pattern_items.py | 1219 ++++++++++++++++++++++ 1 file changed, 1219 insertions(+) create mode 100644 dts/framework/flow/flow_pattern_items.py diff --git a/dts/framework/flow/flow_pattern_items.py b/dts/framework/flow/flow_pattern_items.py new file mode 100644 index 0000000000..ccb019e765 --- /dev/null +++ b/dts/framework/flow/flow_pattern_items.py @@ -0,0 +1,1219 @@ +# 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 Dict, FrozenSet, Iterable, List, Tuple + +from scapy.layers.inet import ICMP, IP, TCP, UDP +from scapy.layers.inet6 import IPv6 +from scapy.layers.l2 import ARP, GRE, Dot1Q, Ether +from scapy.layers.sctp import SCTP +from scapy.layers.vxlan import VXLAN +from scapy.packet import Packet + +from .enums import FlowItemType +from .exceptions import InvalidFlowItemException +from .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 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 = { + # THE FOLLOWING PROPERTIES ARE UNSUPPORTED BY TESTPMD AT THE TIME OF WRITING. + # THEY CAN BE ENABLED ONCE TESTPMD SUPPORTS THEM + # 'hdr': + # ('arp_eth_ipv4 hdr is 1', + # frozenset({"Ether() / ARP(hwtype=1) / Raw('\\x00' * 64)"}), + # + # frozenset({"Ether() / ARP(hwtype=2) / Raw('\\x00' * 64)", + # "Ether() / ARP(hwtype=3) / Raw('\\x00' * 64)", + # "Ether() / ARP(hwtype=6) / Raw('\\x00' * 64)", + # "Ether() / ARP(hwtype-15) / Raw('\\x00' * 64)" + # })), + # 'pro': + # ('arp_eth_ipv4 pro is 0x0800', + # frozenset({"Ether() / ARP(ptype=0x0800) / Raw('\\x00' * 64)"}), + # + # frozenset({"Ether() / ARP(ptype=0x0800) / Raw('\\x00' * 64)", + # "Ether() / ARP(ptype=0x0842) / Raw('\\x00' * 64)", + # "Ether() / ARP(ptype=0x6004) / Raw('\\x00' * 64)", + # "Ether() / ARP(ptype=0x809b) / Raw('\\x00' * 64)" + # })), + # + # 'hln': + # ('arp_eth_ipv4 hln is 6', + # frozenset({"Ether() / ARP(hwlen=6) / Raw('\\x00' * 64)"}), + # + # frozenset({"Ether() / ARP(hwlen=12) / Raw('\\x00' * 64)", + # "Ether() / ARP(hwlen=2) / Raw('\\x00' * 64)", + # "Ether() / ARP(hwlen=8) / Raw('\\x00' * 64)", + # "Ether() / ARP(hwlen=4) / Raw('\\x00' * 64)" + # })), + # + # 'pln': + # ('arp_eth_ipv4 pln is 4', + # frozenset({"Ether() / ARP(plen=4) / Raw('\\x00' * 64)"}), + # + # frozenset({"Ether() / ARP(plen=6) / Raw('\\x00' * 64)", + # "Ether() / ARP(plen=2) / Raw('\\x00' * 64)", + # "Ether() / ARP(plen=8) / Raw('\\x00' * 64)", + # "Ether() / ARP(plen=12) / Raw('\\x00' * 64)" + # })), + # + # 'op': + # ('arp_eth_ipv4 op is 1', + # frozenset({"Ether() / ARP(op=1) / Raw('\\x00' * 64)"}), + # + # frozenset({"Ether() / ARP(op=2) / Raw('\\x00' * 64)", + # "Ether() / ARP(op=3) / Raw('\\x00' * 64)", + # "Ether() / ARP(op=4) / Raw('\\x00' * 64)", + # "Ether() / ARP(op=5) / Raw('\\x00' * 64)" + # })), + # END UNSUPPORTED PROPERTIES + "sha": ( + "arp_eth_ipv4 sha is 90:61:ae:fd:41:43", + frozenset( + {"Ether() / ARP(hwsrc=\"90:61:ae:fd:41:43\") / Raw('\\x00' * 64)"} + ), + frozenset( + { + "Ether() / ARP(hwsrc=\"90:61:ae:fd:41:44\") / Raw('\\x00' * 64)", + "Ether() / ARP(hwsrc=\"90:61:ae:fd:41:45\") / Raw('\\x00' * 64)", + "Ether() / ARP(hwsrc=\"90:61:ae:fd:41:46\") / Raw('\\x00' * 64)", + "Ether() / ARP(hwsrc=\"90:61:ae:fd:41:47\") / Raw('\\x00' * 64)", + } + ), + ), + "spa": ( + "arp_eth_ipv4 spa is 192.168.0.80", + frozenset({"Ether() / ARP(psrc=\"192.168.0.80\") / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether() / ARP(psrc=\"10.0.30.10\") / Raw('\\x00' * 64)", + "Ether() / ARP(psrc=\"8.8.8.8\") / Raw('\\x00' * 64)", + "Ether() / ARP(psrc=\"132.177.0.5\") / Raw('\\x00' * 64)", + "Ether() / ARP(psrc=\"123.4.5.6\") / Raw('\\x00' * 64)", + } + ), + ), + "tha": ( + "arp_eth_ipv4 tha is 00:00:00:00:00:00", + frozenset({"Ether() / ARP(hwdst=00:00:00:00:00:00) / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether() / ARP(hwdst=90:61:ae:fd:41:45) / Raw('\\x00' * 64)", + "Ether() / ARP(hwdst=90:61:ae:fd:41:46) / Raw('\\x00' * 64)", + "Ether() / ARP(hwdst=90:61:ae:fd:41:47) / Raw('\\x00' * 64)", + "Ether() / ARP(hwdst=90:61:ae:fd:41:48) / Raw('\\x00' * 64)", + } + ), + ), + "tpa": ( + "arp_eth_ipv4 tpa is 192.168.0.1", + frozenset({"Ether() / ARP(pdst=192.168.0.1) / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether() / ARP(pdst=10.0.30.10) / Raw('\\x00' * 64)", + "Ether() / ARP(pdst=8.8.8.8) / Raw('\\x00' * 64)", + "Ether() / ARP(pdst=132.177.0.5) / Raw('\\x00' * 64)", + "Ether() / ARP(pdst=123.4.5.6) / Raw('\\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\") / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether(dst=\"90:61:ae:fd:41:44\") / Raw('\\x00' * 64)", + "Ether(dst=\"90:61:ae:fd:41:45\") / Raw('\\x00' * 64)", + "Ether(dst=\"90:61:ae:fd:41:46\") / Raw('\\x00' * 64)", + "Ether(dst=\"91:61:ae:fd:41:43\") / Raw('\\x00' * 64)", + } + ), + ), + "src": ( + "eth src is 90:61:ae:fd:41:43", + frozenset({"Ether(src=\"90:61:ae:fd:41:43\") / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether(src=\"90:61:ae:fd:41:44\") / Raw('\\x00' * 64)", + "Ether(src=\"90:61:ae:fd:41:45\") / Raw('\\x00' * 64)", + "Ether(src=\"90:61:ae:fd:41:46\") / Raw('\\x00' * 64)", + "Ether(src=\"91:61:ae:fd:41:43\") / Raw('\\x00' * 64)", + } + ), + ), + "type": ( + "eth type is 0x0800", # IPv4 EtherType + frozenset({"Ether(type=0x0800) / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether(type=0x0842) / Raw('\\x00' * 64)", + "Ether(type=0x8100) / Raw('\\x00' * 64)", # Possibly a special case? TPID/VLAN + "Ether(type=0x9100) / Raw('\\x00' * 64)", # Possibly special, VLAN double tagging + "Ether(type=0x8863) / Raw('\\x00' * 64)", + "Ether(type=0x9000) / Raw('\\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) / Raw('\\x00' * 64)"} + ), + frozenset( + { + "Ether() / GRE(chksum_present=1, version=0)) / Raw('\\x00' * 64)", + # this is the only other option + } + ), + ), + "protocol": ( + "gre protocol is 0x0800", + frozenset({"Ether() / GRE(proto=0x0800) / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether() / GRE(proto=0x0842) / Raw('\\x00' * 64)", + "Ether() / GRE(proto=0x8100) / Raw('\\x00' * 64)", + "Ether() / GRE(proto=0x0806) / Raw('\\x00' * 64)", + "Ether() / GRE(proto=0x809B) / Raw('\\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 = { + # THE FOLLOWING PROPERTIES ARE UNSUPPORTED BY TESTPMD AT THE TIME OF WRITING. + # THEY CAN BE ENABLED ONCE TESTPMD SUPPORTS THEM + # 'icmp_cksum': + # ('icmp cksum is 0x0800', + # frozenset({"Ether() / ICMP() / UDP() / Raw('\x00' * 64)"}), + # + # frozenset({"Ether() / ICMP() / UDP() / Raw('\x00' * 64)", + # "Ether() / ICMP() / UDP() / Raw('\x00' * 64)", + # "Ether() / ICMP() / UDP() / Raw('\x00' * 64)", + # "Ether() / ICMP() / UDP() / Raw('\x00' * 64)" + # })), + # END UNSUPPORTED PROPERTIES + "icmp_type": ( + "icmp type is 3", + frozenset({"Ether() / ICMP(type=3) / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether() / ICMP(type=3) / Raw('\\x00' * 64)", + "Ether() / ICMP(type=11) / Raw('\\x00' * 64)", + "Ether() / ICMP(type=13) / Raw('\\x00' * 64)", + "Ether() / ICMP(type=0) / Raw('\\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) / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether() / ICMP(type=3, code=0) / Raw('\\x00' * 64)", + "Ether() / ICMP(type=3, code=2) / Raw('\\x00' * 64)", + "Ether() / ICMP(type=11, code=1) / Raw('\\x00' * 64)", + "Ether() / ICMP(type=12, code=2) / Raw('\\x00' * 64)", + } + ), + ), + "icmp_ident": ( + "icmp ident is 0x0800", + frozenset({"Ether() / ICMP() / UDP() / Raw('\x00' * 64)"}), + frozenset( + { + "Ether() / ICMP() / UDP() / Raw('\x00' * 64)", + "Ether() / ICMP() / UDP() / Raw('\x00' * 64)", + "Ether() / ICMP() / UDP() / Raw('\x00' * 64)", + "Ether() / ICMP() / UDP() / Raw('\x00' * 64)", + } + ), + ), + "icmp_seq": ( + "icmp seq is 0x0800", + frozenset({"Ether() / ICMP(proto=0x0800) / UDP() / Raw('\x00' * 64)"}), + frozenset( + { + "Ether() / ICMP() / UDP() / Raw('\x00' * 64)", + "Ether() / ICMP() / UDP() / Raw('\x00' * 64)", + "Ether() / ICMP() / UDP() / Raw('\x00' * 64)", + "Ether() / ICMP() / UDP() / Raw('\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``. + """ + possible_properties = { + # THE FOLLOWING PROPERTIES ARE UNSUPPORTED BY TESTPMD AT THE TIME OF WRITING. + # THEY CAN BE ENABLED ONCE TESTPMD SUPPORTS THEM + # 'checksum': + # ('icmp6 cksum is 0x1234', + # frozenset({"Ether() / ICMPv6DestUnreach(cksum=0x1234) / Raw('\\x00' * 64)"}), + # + # frozenset({"Ether() / ICMPv6DestUnreach(cksum=0x4321) / Raw('\\x00' * 64)", + # "Ether() / ICMPv6DestUnreach(cksum=0xffff) / Raw('\\x00' * 64)", + # "Ether() / ICMPv6DestUnreach(cksum=0x1233) / Raw('\\x00' * 64)", + # "Ether() / ICMPv6DestUnreach(cksum=0x1010) / Raw('\\x00' * 64)" + # })), + # END UNSUPPORTED PROPERTIES + "type": ( + "icmp6 type is 1", # Destination Unreachable + frozenset({"Ether() / ICMPv6DestUnreach(type=1) / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether() / ICMPv6DestUnreach(type=128) / Raw('\\x00' * 64)", + "Ether() / ICMPv6DestUnreach(type=129) / Raw('\\x00' * 64)", + "Ether() / ICMPv6DestUnreach(type=3) / Raw('\\x00' * 64)", + "Ether() / ICMPv6DestUnreach(type=135) / Raw('\\x00' * 64)", + } + ), + ), + "code": ( # ICMP code is dependent on type; these are possible Destination Unreachable codes + "icmp6 code is 0", + frozenset({"Ether() / ICMPv6DestUnreach(code=0) / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether() / ICMPv6DestUnreach(code=1) / Raw('\\x00' * 64)", + "Ether() / ICMPv6DestUnreach(code=2) / Raw('\\x00' * 64)", + "Ether() / ICMPv6DestUnreach(code=3) / Raw('\\x00' * 64)", + "Ether() / ICMPv6DestUnreach(code=4) / Raw('\\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) / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether() / IP(tos=2) / Raw('\\x00' * 64)", + "Ether() / IP(tos=4) / Raw('\\x00' * 64)", + "Ether() / IP(tos=8) / Raw('\\x00' * 64)", + "Ether() / IP(tos=16) / Raw('\\x00' * 64)", + } + ), + ), + "ttl": ( + "ipv4 ttl is 64", + frozenset({"Ether() / IP(ttl=64) / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether() / IP(ttl=128) / Raw('\\x00' * 64)", + "Ether() / IP(ttl=255) / Raw('\\x00' * 64)", + "Ether() / IP(ttl=32) / Raw('\\x00' * 64)", + "Ether() / IP(ttl=100) / Raw('\\x00' * 64)", + } + ), + ), + "proto": ( + "ipv4 proto is 0x06", # TCP + frozenset({"Ether() / IP(proto=0x06) / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether() / IP(proto=0x01) / Raw('\\x00' * 64)", + "Ether() / IP(proto=0x11) / Raw('\\x00' * 64)", + "Ether() / IP(proto=0x12) / Raw('\\x00' * 64)", + "Ether() / IP(proto=0x58) / Raw('\\x00' * 64)", + } + ), + ), + "src": ( + "ipv4 src is 192.168.0.5", + frozenset({"Ether() / IP(src=\"192.168.0.5\") / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether() / IP(src=\"10.10.10.10\") / Raw('\\x00' * 64)", + "Ether() / IP(src=\"132.177.127.6\") / Raw('\\x00' * 64)", + "Ether() / IP(src=\"192.168.0.4\") / Raw('\\x00' * 64)", + "Ether() / IP(src=\"192.168.0.250\") / Raw('\\x00' * 64)", + } + ), + ), + "dst": ( + "ipv4 dst is 192.168.0.5", + frozenset({"Ether() / IP(dst=\"192.168.0.5\") / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether() / IP(dst=\"10.10.10.10\") / Raw('\\x00' * 64)", + "Ether() / IP(dst=\"132.177.127.6\") / Raw('\\x00' * 64)", + "Ether() / IP(dst=\"192.168.0.4\") / Raw('\\x00' * 64)", + "Ether() / IP(dst=\"192.168.0.250\") / Raw('\\x00' * 64)", + } + ), + ), + # CHECKSUM PROPERTY NOT SUPPORTED BY TESTPMD; DO NOT UNCOMMENT UNTIL SUPPORTED + # 'checksum': + # ('ipv4 chksum is 0x1234', + # frozenset({"Ether() / ICMPv6DestUnreach(cksum=0x1234) / Raw('\\x00' * 64)"}), + # frozenset({"Ether() / ICMPv6DestUnreach(cksum=0x4321) / Raw('\\x00' * 64)", + # "Ether() / ICMPv6DestUnreach(cksum=0xffff) / Raw('\\x00' * 64)", + # "Ether() / ICMPv6DestUnreach(cksum=0x1233) / Raw('\\x00' * 64)", + # "Ether() / ICMPv6DestUnreach(cksum=0x1010) / Raw('\\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 CAN BE ENABLED ONCE TESTPMD SUPPORTS THEM + # 'vtc_flow': + # ('ipv6 vtc_flow is 0x0', + # frozenset({"Ether() / IPv6(tc=0, fl=0, version=0) / Raw('\\x00' * 64)"}), + # frozenset({"Ether() / IPv6(tc=1, fl=0, version=0) / Raw('\\x00' * 64)", + # "Ether() / IPv6(tc=0, fl=0xABCD, version=0) / Raw('\\x00' * 64)", + # "Ether() / IPv6(tc=0, fl=0, version=1) / Raw('\\x00' * 64)", + # "Ether() / IPv6(tc=6, fl=0x9999, version=1) / Raw('\\x00' * 64)" + # })), + # 'payload_len': + # ('ipv6 payload_len is 64', + # frozenset({"Ether() / IPv6(plen=64) / Raw('\\x00' * 64)"}), + # frozenset({"Ether() / IPv6(plen=32) / Raw('\\x00' * 64)", + # "Ether() / IPv6(plen=128) / Raw('\\x00' * 64)", + # "Ether() / IPv6(plen=5000) / Raw('\\x00' * 64)", + # "Ether() / IPv6(plen=4) / Raw('\\x00' * 64)" + # })), + # END UNSUPPORTED PROPERTIES + "tc": ( + "ipv6 tc is 0", + frozenset({"Ether() / IPv6(tc=0) / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether() / IPv6(tc=1) / Raw('\\x00' * 64)", + "Ether() / IPv6(tc=2) / Raw('\\x00' * 64)", + "Ether() / IPv6(tc=4) / Raw('\\x00' * 64)", + "Ether() / IPv6(tc=6) / Raw('\\x00' * 64)", + } + ), + ), + "flow": ( + "ipv6 flow is 0xABCD", + frozenset({"Ether() / IPv6(fl=0xABCD) / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether() / IPv6(fl=0xABCE) / Raw('\\x00' * 64)", + "Ether() / IPv6(fl=0x0001) / Raw('\\x00' * 64)", + "Ether() / IPv6(fl=0xFFFF) / Raw('\\x00' * 64)", + "Ether() / IPv6(fl=0x1234) / Raw('\\x00' * 64)", + } + ), + ), + "proto": ( # next header (nh) + "ipv6 proto is 6", # TCP + frozenset({"Ether() / IPv6(nh=6) / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether() / IPv6(nh=17) / Raw('\\x00' * 64)", + "Ether() / IPv6(nh=41) / Raw('\\x00' * 64)", + "Ether() / IPv6(nh=0) / Raw('\\x00' * 64)", + "Ether() / IPv6(nh=60) / Raw('\\x00' * 64)", + } + ), + ), + "hop": ( # hop limit + "ipv6 hop is 64", + frozenset({"Ether() / IPv6(hlim=64) / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether() / IPv6(hlim=128) / Raw('\\x00' * 64)", + "Ether() / IPv6(hlim=32) / Raw('\\x00' * 64)", + "Ether() / IPv6(hlim=255) / Raw('\\x00' * 64)", + "Ether() / IPv6(hlim=100) / Raw('\\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\") / Raw('\\x00' * 64)" + } + ), + frozenset( + { + "Ether() / IPv6(dst=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c3\") / Raw('\\x00' * 64)", + "Ether() / IPv6(dst=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c4\") / Raw('\\x00' * 64)", + "Ether() / IPv6(dst=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c5\") / Raw('\\x00' * 64)", + "Ether() / IPv6(dst=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c6\") / Raw('\\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\") / Raw('\\x00' * 64)" + } + ), + frozenset( + { + "Ether() / IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c3\") / Raw('\\x00' * 64)", + "Ether() / IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c4\") / Raw('\\x00' * 64)", + "Ether() / IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c5\") / Raw('\\x00' * 64)", + "Ether() / IPv6(src=\"2001:0000:9d38:6ab8:1c48:3a1c:a95a:b1c6\") / Raw('\\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) / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether() / IP() / SCTP(sport=3939) / Raw('\\x00' * 64)", + "Ether() / IP() / SCTP(sport=5000) / Raw('\\x00' * 64)", + "Ether() / IP() / SCTP(sport=1998) / Raw('\\x00' * 64)", + "Ether() / IP() / SCTP(sport=1028) / Raw('\\x00' * 64)", + } + ), + ), + "dst": ( + "sctp dst is 3838", + frozenset({"Ether() / IP() / SCTP(dport=3838) / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether() / IP() / SCTP(dport=3939) / Raw('\\x00' * 64)", + "Ether() / IP() / SCTP(dport=5000) / Raw('\\x00' * 64)", + "Ether() / IP() / SCTP(dport=1998) / Raw('\\x00' * 64)", + "Ether() / IP() / SCTP(dport=1028) / Raw('\\x00' * 64)", + } + ), + ), + "tag": ( + "sctp tag is 12345", + frozenset({"Ether() / IP() / SCTP(tag=12345) / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether() / IP() / SCTP(tag=12346) / Raw('\\x00' * 64)", + "Ether() / IP() / SCTP(tag=12) / Raw('\\x00' * 64)", + "Ether() / IP() / SCTP(tag=9999) / Raw('\\x00' * 64)", + "Ether() / IP() / SCTP(tag=42) / Raw('\\x00' * 64)", + } + ), + ), + "cksum": ( + "sctp cksum is 0x01535b67", + frozenset({"Ether() / IP() / SCTP(chksum=0x01535b67) / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether() / IP() / SCTP(chksum=0x01535b68) / Raw('\\x00' * 64)", + "Ether() / IP() / SCTP(chksum=0xdeadbeef) / Raw('\\x00' * 64)", + "Ether() / IP() / SCTP(chksum=0x12345678) / Raw('\\x00' * 64)", + "Ether() / IP() / SCTP(chksum=0x385030fe) / Raw('\\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 CAN BE ENABLED ONCE TESTPMD SUPPORTS THEM + # 'data_off': + # ('tcp data_off is 0', + # frozenset({"Ether() / IP() / TCP(dataofs=0) / Raw('\\x00' * 64)"}), + # frozenset({"Ether() / IP() / TCP(dataofs=1) / Raw('\\x00' * 64)", + # "Ether() / IP() / TCP(dataofs=2) / Raw('\\x00' * 64)", + # "Ether() / IP() / TCP(dataofs=3) / Raw('\\x00' * 64)", + # "Ether() / IP() / TCP(dataofs=4) / Raw('\\x00' * 64)" + # })), + # 'rx_win': + # ('tcp rx_win is 64', + # frozenset({"Ether() / IP() / TCP(window=64)/ Raw('\\x00' * 64)"}), + # frozenset({"Ether() / IP() / TCP(window=16)/ Raw('\\x00' * 64)", + # "Ether() / IP() / TCP(window=128) / Raw('\\x00' * 64)", + # "Ether() / IP() / TCP(window=32) / Raw('\\x00' * 64)", + # "Ether() / IP() / TCP(window=255) / Raw('\\x00' * 64)" + # })), + # 'cksum': + # ('tcp cksum is 0x1234', + # frozenset({"Ether() / IP() / TCP(chksum=0x1234) / Raw('\\x00' * 64)"}), + # frozenset({"Ether() / IP() / TCP(chksum=0x4321) / Raw('\\x00' * 64)", + # "Ether() / IP() / TCP(chksum=0xffff) / Raw('\\x00' * 64)", + # "Ether() / IP() / TCP(chksum=0x9999) / Raw('\\x00' * 64)", + # "Ether() / IP() / TCP(chksum=0x1233) / Raw('\\x00' * 64)" + # })), + # END UNSUPPORTED PROPERTIES + "src": ( + "tcp src is 3838", + frozenset({"Ether() / IP() / TCP(sport=3838) / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether() / IP() / TCP(sport=3939) / Raw('\\x00' * 64)", + "Ether() / IP() / TCP(sport=5000) / Raw('\\x00' * 64)", + "Ether() / IP() / TCP(sport=1998) / Raw('\\x00' * 64)", + "Ether() / IP() / TCP(sport=1028) / Raw('\\x00' * 64)", + } + ), + ), + "dst": ( + "tcp dst is 3838", + frozenset({"Ether() / IP() / TCP(dport=3838) / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether() / IP() / TCP(dport=3939) / Raw('\\x00' * 64)", + "Ether() / IP() / TCP(dport=5000) / Raw('\\x00' * 64)", + "Ether() / IP() / TCP(dport=1998) / Raw('\\x00' * 64)", + "Ether() / IP() / TCP(dport=1028) / Raw('\\x00' * 64)", + } + ), + ), + "flags": ( + "tcp flags is 0x02", + frozenset({"Ether() / IP() / TCP(flags=0x02) / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether() / IP() / TCP(flags=0x01) / Raw('\\x00' * 64)", + "Ether() / IP() / TCP(flags=0x04) / Raw('\\x00' * 64)", + "Ether() / IP() / TCP(flags=0x08) / Raw('\\x00' * 64)", + "Ether() / IP() / TCP(flags=0x10) / Raw('\\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 MAY BE RE-ENABLED ONCE TESTPMD SUPPORTS THEIR USE + # 'dgram_len': + # ('udp dgram_len is 64', + # frozenset({"Ether() / IP() / UDP(len=64) / Raw('\\x00' * 64)"}), + # + # frozenset({"Ether() / IP() / UDP(len=128) / Raw('\\x00' * 64)", + # "Ether() / IP() / UDP(len=32) / Raw('\\x00' * 64)", + # "Ether() / IP() / UDP(len=16) / Raw('\\x00' * 64)", + # "Ether() / IP() / UDP(len=255) / Raw('\\x00' * 64)" + # })), + # 'dgram_cksum': + # ('udp dgram_cksum is 0x1234', + # frozenset({"Ether() / IP() / UDP(chksum=0x1234) / Raw('\\x00' * 64)"}), + # + # frozenset({"Ether() / IP() / UDP(chksum=0x4321) / Raw('\\x00' * 64)", + # "Ether() / IP() / UDP(chksum=0xffff) / Raw('\\x00' * 64)", + # "Ether() / IP() / UDP(chksum=0x9999) / Raw('\\x00' * 64)", + # "Ether() / IP() / UDP(chksum=0x1233) / Raw('\\x00' * 64)" + # })), + # END UNSUPPORTED PROPERTIES + "src": ( + "udp src is 3838", + frozenset({"Ether() / IP() / UDP(sport=3838) / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether() / IP() / UDP(sport=3939) / Raw('\\x00' * 64)", + "Ether() / IP() / UDP(sport=5000) / Raw('\\x00' * 64)", + "Ether() / IP() / UDP(sport=1998) / Raw('\\x00' * 64)", + "Ether() / IP() / UDP(sport=1028) / Raw('\\x00' * 64)", + } + ), + ), + "dst": ( + "udp dst is 3838", + frozenset({"Ether() / IP() / UDP(dport=3838) / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether() / IP() / UDP(dport=3939) / Raw('\\x00' * 64)", + "Ether() / IP() / UDP(dport=5000) / Raw('\\x00' * 64)", + "Ether() / IP() / UDP(dport=1998) / Raw('\\x00' * 64)", + "Ether() / IP() / UDP(dport=1028) / Raw('\\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 = { + # THE FOLLOWING PROPERTIES ARE UNSUPPORTED BY TESTPMD AT THE TIME OF WRITING. + # THEY MAY BE RE-ENABLED ONCE TESTPMD SUPPORTS THEIR USE + # 'tpid': + # ('vlan tpid is 0x8100', # standard value + # frozenset({"Ether() / Dot1Q(type=0x8100) / Raw('\\x00' * 64)"}), + # + # frozenset({"Ether() / Dot1Q(type=0x0800) / Raw('\\x00' * 64)", + # "Ether() / Dot1Q(type=0x0842) / Raw('\\x00' * 64)", + # "Ether() / Dot1Q(type=0x809b) / Raw('\\x00' * 64)", + # "Ether() / Dot1Q(type=0x86dd) / Raw('\\x00' * 64)" + # })), + # END UNSUPPORTED PROPERTIES + "tci": ( + "vlan tci is 0xaaaa", + frozenset( + { + "Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xaaa) / Raw('\\x00' * 64)" + } + ), + frozenset( + { + "Ether() / Dot1Q(prio = 0x0, id = 0x1, vlan = 0xbbb) / Raw('\\x00' * 64)", + "Ether() / Dot1Q(prio = 0x5, id = 0x0, vlan = 0xccc) / Raw('\\x00' * 64)", + "Ether() / Dot1Q(prio = 0x5, id = 0x1, vlan = 0xaaa) / Raw('\\x00' * 64)", + "Ether() / Dot1Q(prio = 0x4, id = 0x0, vlan = 0xaaa) / Raw('\\x00' * 64)", + } + ), + ), + "pcp": ( + "vlan pcp is 0x0", + frozenset({"Ether() / Dot1Q(prio=0x0) / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether() / Dot1Q(prio=0x1) / Raw('\\x00' * 64)", + "Ether() / Dot1Q(prio=0x2) / Raw('\\x00' * 64)", + "Ether() / Dot1Q(prio=0x3) / Raw('\\x00' * 64)", + "Ether() / Dot1Q(prio=0x7) / Raw('\\x00' * 64)", + } + ), + ), + "dei": ( + "vlan dei is 0", + frozenset({"Ether() / Dot1Q(id=0) / Raw('\\x00' * 64)"}), + frozenset({"Ether() / Dot1Q(id=1) / Raw('\\x00' * 64)"}), + ), + "vid": ( + "vlan vid is 0xabc", + frozenset({"Ether() / Dot1Q(vlan=0xabc) / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether() / Dot1Q(vlan=0xaaa) / Raw('\\x00' * 64)", + "Ether() / Dot1Q(vlan=0x123) / Raw('\\x00' * 64)", + "Ether() / Dot1Q(vlan=0x1f5) / Raw('\\x00' * 64)", + "Ether() / Dot1Q(vlan=0x999) / Raw('\\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 CAN BE ENABLED ONCE TESTPMD SUPPORTS THEM + # 'rsvd0': + # ('vxlan rsvd0 is 0x000000', + # frozenset({"Ether() / IP() / VXLAN(reserved0=0) / Raw('\\x00' * 64)"}), + # + # frozenset({"Ether() / IP() / VXLAN(reserved0=1) / Raw('\\x00' * 64)", + # "Ether() / IP() / VXLAN(reserved0=2) / Raw('\\x00' * 64)", + # "Ether() / IP() / VXLAN(reserved0=3) / Raw('\\x00' * 64)", + # "Ether() / IP() / VXLAN(reserved0=4) / Raw('\\x00' * 64)" + # })), + # 'rsvd1': + # ('vxlan rsvd1 is 0x00', + # frozenset({"Ether() / IP() / VXLAN(reserved0=0) / Raw('\\x00' * 64)"}), + # + # frozenset({"Ether() / IP() / VXLAN(reserved0=1) / Raw('\\x00' * 64)", + # "Ether() / IP() / VXLAN(reserved0=2) / Raw('\\x00' * 64)", + # "Ether() / IP() / VXLAN(reserved0=3) / Raw('\\x00' * 64)", + # "Ether() / IP() / VXLAN(reserved0=4) / Raw('\\x00' * 64)" + # })), + # 'flags': + # ('vxlan flags is 0x08', + # frozenset({"Ether() / IP() / VXLAN(flags=0x08) / Raw('\\x00' * 64)"}), + # + # frozenset({"Ether() / IP() / VXLAN(flags=0x80) / Raw('\\x00' * 64)", + # "Ether() / IP() / VXLAN(flags=0x00) / Raw('\\x00' * 64)", + # "Ether() / IP() / VXLAN(flags=0x99) / Raw('\\x00' * 64)", + # "Ether() / IP() / VXLAN(flags=0x01) / Raw('\\x00' * 64)" + # })), + # END UNSUPPORTED PROPERTIES + "vni": ( # a 3-byte value + "vxlan vni is 0x112233", + frozenset({"Ether() / IP() / VXLAN(vni=0x112233) / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether() / IP() / VXLAN(vni=0x112234) / Raw('\\x00' * 64)", + "Ether() / IP() / VXLAN(vni=0x123456) / Raw('\\x00' * 64)", + "Ether() / IP() / VXLAN(vni=0xaabbcc) / Raw('\\x00' * 64)", + "Ether() / IP() / VXLAN(vni=0x999999) / Raw('\\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. + """ + + possible_properties = { + # THE FOLLOWING PROPERTIES ARE UNSUPPORTED BY TESTPMD AT THE TIME OF WRITING. + # THEY CAN BE ENABLED ONCE TESTPMD SUPPORTS THEM + # 'rsvd0': + # ('vxlan rsvd0 is 0x000000', + # frozenset({"Ether() / IP() / VXLAN(reserved0=0) / Raw('\\x00' * 64)"}), + # + # frozenset({"Ether() / IP() / VXLAN(reserved0=1) / Raw('\\x00' * 64)", + # "Ether() / IP() / VXLAN(reserved0=2) / Raw('\\x00' * 64)", + # "Ether() / IP() / VXLAN(reserved0=3) / Raw('\\x00' * 64)", + # "Ether() / IP() / VXLAN(reserved0=4) / Raw('\\x00' * 64)" + # })), + # 'rsvd1': + # ('vxlan rsvd1 is 0x00', + # frozenset({"Ether() / IP() / VXLAN(reserved0=0) / Raw('\\x00' * 64)"}), + # + # frozenset({"Ether() / IP() / VXLAN(reserved0=1) / Raw('\\x00' * 64)", + # "Ether() / IP() / VXLAN(reserved0=2) / Raw('\\x00' * 64)", + # "Ether() / IP() / VXLAN(reserved0=3) / Raw('\\x00' * 64)", + # "Ether() / IP() / VXLAN(reserved0=4) / Raw('\\x00' * 64)" + # })), + # 'flags': + # ('vxlan flags is 0x08', + # frozenset({"Ether() / IP() / VXLAN(flags=0x08) / Raw('\\x00' * 64)"}), + # + # frozenset({"Ether() / IP() / VXLAN(flags=0x80) / Raw('\\x00' * 64)", + # "Ether() / IP() / VXLAN(flags=0x00) / Raw('\\x00' * 64)", + # "Ether() / IP() / VXLAN(flags=0x99) / Raw('\\x00' * 64)", + # "Ether() / IP() / VXLAN(flags=0x01) / Raw('\\x00' * 64)" + # })), + # 'protocol': + # ('vxlan protocol is 0x01', + # frozenset({"Ether() / IP() / VXLAN(NextProtocol=0x01) / Raw('\\x00' * 64)"}), + # + # frozenset({"Ether() / IP() / VXLAN(NextProtocol=0x01) / Raw('\\x00' * 64)", + # "Ether() / IP() / VXLAN(NextProtocol=0x11) / Raw('\\x00' * 64)", + # "Ether() / IP() / VXLAN(NextProtocol=0x22) / Raw('\\x00' * 64)", + # "Ether() / IP() / VXLAN(NextProtocol=0x33) / Raw('\\x00' * 64)" + # })), + # END UNSUPPORTED PROPERTIES + "vni": ( # a 3-byte value + "vxlan vni is 0x112233", + frozenset({"Ether() / IP() / VXLAN(vni=0x112233) / Raw('\\x00' * 64)"}), + frozenset( + { + "Ether() / IP() / VXLAN(vni=0x112234) / Raw('\\x00' * 64)", + "Ether() / IP() / VXLAN(vni=0x123456) / Raw('\\x00' * 64)", + "Ether() / IP() / VXLAN(vni=0xaabbcc) / Raw('\\x00' * 64)", + "Ether() / IP() / VXLAN(vni=0x999999) / Raw('\\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, +}