diff mbox series

[ovs-dev,v4,06/17] python: add flow base class

Message ID 20220616063247.517147-7-amorenoz@redhat.com
State Changes Requested
Headers show
Series python: add flow parsing library | expand

Checks

Context Check Description
ovsrobot/apply-robot success apply and check: success
ovsrobot/github-robot-_Build_and_Test success github build: passed
ovsrobot/intel-ovs-compilation success test: success

Commit Message

Adrian Moreno June 16, 2022, 6:32 a.m. UTC
It simplifies the implementation of different types of flows by creating
the concept of Section (e.g: match, action) and automatic accessors for
all the provided Sections

Acked-by: Eelco Chaudron <echaudro@redhat.com>
Signed-off-by: Adrian Moreno <amorenoz@redhat.com>
---
 python/automake.mk      |   1 +
 python/ovs/flow/flow.py | 125 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 126 insertions(+)
 create mode 100644 python/ovs/flow/flow.py
diff mbox series

Patch

diff --git a/python/automake.mk b/python/automake.mk
index c9a1e7c67..b34a5324b 100644
--- a/python/automake.mk
+++ b/python/automake.mk
@@ -28,6 +28,7 @@  ovs_pyfiles = \
 	python/ovs/fcntl_win.py \
 	python/ovs/flow/__init__.py \
 	python/ovs/flow/decoders.py \
+	python/ovs/flow/flow.py \
 	python/ovs/flow/kv.py \
 	python/ovs/flow/list.py \
 	python/ovs/json.py \
diff --git a/python/ovs/flow/flow.py b/python/ovs/flow/flow.py
new file mode 100644
index 000000000..2f053e77d
--- /dev/null
+++ b/python/ovs/flow/flow.py
@@ -0,0 +1,125 @@ 
+""" Defines the Flow class.
+"""
+
+
+class Section(object):
+    """A flow can be seen as composed of different sections, e.g:
+
+     [info] [match] actions=[actions]
+
+    This class represents each of those sections.
+
+    A section is basically a set of Key-Value pairs. Typically, they can be
+    expressed as a dictionary, for instance the "match" part of a flow can be
+    expressed as:
+        {
+            "nw_src": "192.168.1.1",
+            "nw_dst": "192.168.1.2",
+        }
+    However, some of them must be expressed as a list which allows for
+    duplicated keys. For instance, the "actions" section could be:
+        [
+            {
+                "output": 32
+            },
+            {
+                "output": 33
+            }
+        ]
+
+    The is_list flag is used to discriminate this.
+
+    Attributes:
+        name (str): Name of the section.
+        pos (int): Position within the overall flow string.
+        string (str): Section string.
+        data (list[KeyValue]): Parsed data of the section.
+        is_list (bool): Whether the key-values shall be expressed as a list
+        (i.e: it allows repeated keys).
+    """
+
+    def __init__(self, name, pos, string, data, is_list=False):
+        self.name = name
+        self.pos = pos
+        self.string = string
+        self.data = data
+        self.is_list = is_list
+
+    def __str__(self):
+        return "{} (at {}): {}".format(self.name, self.pos, self.string)
+
+    def __repr__(self):
+        return "%s('%s')" % (self.__class__.__name__, self)
+
+    def dict(self):
+        return {self.name: self.format_data()}
+
+    def format_data(self):
+        """Returns the section's key-values formatted in a dictionary or list
+        depending on the value of is_list flag.
+        """
+        if self.is_list:
+            return [{item.key: item.value} for item in self.data]
+        else:
+            return {item.key: item.value for item in self.data}
+
+
+class Flow(object):
+    """The Flow class is a base class for other types of concrete flows
+    (such as OFproto Flows or DPIF Flows).
+
+    A flow is basically comprised of a number of sections.
+    For each section named {section_name}, the flow object will have the
+    following attributes:
+     - {section_name} will return the sections data in a formatted way.
+     - {section_name}_kv will return the sections data as a list of KeyValues.
+
+    Args:
+        sections (list[Section]): List of sections that comprise the flow
+        orig (str): Original flow string.
+        id (Any): Optional; identifier that clients can use to uniquely
+            identify this flow.
+    """
+
+    def __init__(self, sections, orig="", id=None):
+        self._sections = sections
+        self._orig = orig
+        self._id = id
+        for section in sections:
+            setattr(
+                self, section.name, self.section(section.name).format_data()
+            )
+            setattr(
+                self,
+                "{}_kv".format(section.name),
+                self.section(section.name).data,
+            )
+
+    def section(self, name):
+        """Return the section by name."""
+        return next(
+            (sect for sect in self._sections if sect.name == name), None
+        )
+
+    @property
+    def id(self):
+        """Return the Flow ID."""
+        return self._id
+
+    @property
+    def sections(self):
+        """Return the all the sections in a list."""
+        return self._sections
+
+    @property
+    def orig(self):
+        """Return the original flow string."""
+        return self._orig
+
+    def dict(self):
+        """Returns the Flow information in a dictionary."""
+        flow_dict = {"orig": self.orig}
+        for section in self.sections:
+            flow_dict.update(section.dict())
+
+        return flow_dict