DPDK patches and discussions
 help / color / mirror / Atom feed
From: "Juraj Linkeš" <juraj.linkes@pantheon.tech>
To: thomas@monjalon.net, david.marchand@redhat.com,
	Honnappa.Nagarahalli@arm.com, ohilyard@iol.unh.edu,
	lijuan.tu@intel.com
Cc: dev@dpdk.org, "Juraj Linkeš" <juraj.linkes@pantheon.tech>
Subject: [RFC PATCH v1 18/23] dts: merge DTS framework/flow/flow.py to DPDK
Date: Wed,  6 Apr 2022 15:18:58 +0000	[thread overview]
Message-ID: <20220406151903.2916254-19-juraj.linkes@pantheon.tech> (raw)
In-Reply-To: <20220406151903.2916254-1-juraj.linkes@pantheon.tech>

---
 dts/framework/flow/flow.py | 223 +++++++++++++++++++++++++++++++++++++
 1 file changed, 223 insertions(+)
 create mode 100644 dts/framework/flow/flow.py

diff --git a/dts/framework/flow/flow.py b/dts/framework/flow/flow.py
new file mode 100644
index 0000000000..e80e69a991
--- /dev/null
+++ b/dts/framework/flow/flow.py
@@ -0,0 +1,223 @@
+# 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.
+
+from __future__ import annotations
+
+import copy
+import itertools
+import operator
+from functools import reduce
+from typing import FrozenSet, Iterable, List, Tuple, Union
+
+from scapy.layers.l2 import Ether
+from scapy.packet import Raw
+
+from .enums import FlowActionType, FlowItemType
+from .exceptions import InvalidFlowItemException
+from .flow_action_items import ActionFlowItem
+from .flow_items import FlowItem
+from .flow_pattern_items import TUNNELING_PROTOCOLS, PatternFlowItem
+
+# Get reserved mac addresses
+NEVER_MATCH_PACKET = Ether(src="", dst="") / Raw("\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:]
-- 
2.20.1


  parent reply	other threads:[~2022-04-06 15:21 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-04-06 15:18 [RFC PATCH v1 00/23] merge DTS test resource files " Juraj Linkeš
2022-04-06 15:18 ` [RFC PATCH v1 01/23] dts: merge DTS framework/plotgraph.py " Juraj Linkeš
2022-04-06 15:18 ` [RFC PATCH v1 02/23] dts: merge DTS framework/plotting.py " Juraj Linkeš
2022-04-06 15:18 ` [RFC PATCH v1 03/23] dts: merge DTS framework/pmd_output.py " Juraj Linkeš
2022-04-06 15:18 ` [RFC PATCH v1 04/23] dts: merge DTS framework/qemu_kvm.py " Juraj Linkeš
2022-04-06 15:18 ` [RFC PATCH v1 05/23] dts: merge DTS framework/qemu_libvirt.py " Juraj Linkeš
2022-04-06 15:18 ` [RFC PATCH v1 06/23] dts: merge DTS framework/test_capabilities.py " Juraj Linkeš
2022-04-06 15:18 ` [RFC PATCH v1 07/23] dts: merge DTS framework/test_case.py " Juraj Linkeš
2022-04-06 15:18 ` [RFC PATCH v1 08/23] dts: merge DTS framework/virt_base.py " Juraj Linkeš
2022-04-06 15:18 ` [RFC PATCH v1 09/23] dts: merge DTS framework/virt_common.py " Juraj Linkeš
2022-04-06 15:18 ` [RFC PATCH v1 10/23] dts: merge DTS framework/virt_dut.py " Juraj Linkeš
2022-04-06 15:18 ` [RFC PATCH v1 11/23] dts: merge DTS framework/virt_resource.py " Juraj Linkeš
2022-04-06 15:18 ` [RFC PATCH v1 12/23] dts: merge DTS framework/virt_scene.py " Juraj Linkeš
2022-04-06 15:18 ` [RFC PATCH v1 13/23] dts: merge DTS nics/__init__.py " Juraj Linkeš
2022-04-06 15:18 ` [RFC PATCH v1 14/23] dts: merge DTS nics/system_info.py " Juraj Linkeš
2022-04-06 15:18 ` [RFC PATCH v1 15/23] dts: merge DTS framework/flow/__init__.py " Juraj Linkeš
2022-04-06 15:18 ` [RFC PATCH v1 16/23] dts: merge DTS framework/flow/enums.py " Juraj Linkeš
2022-04-06 15:18 ` [RFC PATCH v1 17/23] dts: merge DTS framework/flow/exceptions.py " Juraj Linkeš
2022-04-06 15:18 ` Juraj Linkeš [this message]
2022-04-06 15:18 ` [RFC PATCH v1 19/23] dts: merge DTS framework/flow/flow_action_items.py " Juraj Linkeš
2022-04-06 15:19 ` [RFC PATCH v1 20/23] dts: merge DTS framework/flow/flow_items.py " Juraj Linkeš
2022-04-06 15:19 ` [RFC PATCH v1 21/23] dts: merge DTS framework/flow/flow_pattern_items.py " Juraj Linkeš
2022-04-06 15:19 ` [RFC PATCH v1 22/23] dts: merge DTS framework/flow/flow_rule.py " Juraj Linkeš
2022-04-06 15:19 ` [RFC PATCH v1 23/23] dts: merge DTS framework/flow/generator.py " Juraj Linkeš

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=20220406151903.2916254-19-juraj.linkes@pantheon.tech \
    --to=juraj.linkes@pantheon.tech \
    --cc=Honnappa.Nagarahalli@arm.com \
    --cc=david.marchand@redhat.com \
    --cc=dev@dpdk.org \
    --cc=lijuan.tu@intel.com \
    --cc=ohilyard@iol.unh.edu \
    --cc=thomas@monjalon.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).