[ovs-dev] [RFC PATCH 01/10] python: introduce scheleton of ovs_ofparse utility

Adrian Moreno amorenoz at redhat.com
Mon Nov 22 15:01:48 UTC 2021


ovs-ofparse is a python program that uses ovs.flows library to provide
rich formatting of openflow and datapath flows.

It uses 'click' as the command line argument framework and has the
following syntax:

ovs-ofparse [OPTIONS] [openflow | datapath] FORMAT [FORMAT OPTIONS]

OPTIONS: describe general options that apply to any protocol or format
[openflow | datapath] defines the flow protocol to parse
FORMAT: specifies the format to print the output in
[FORMAT OPTIONS] are optional format-specific options

A generic configuration file called ovs-ofparse.conf is supported

Signed-off-by: Adrian Moreno <amorenoz at redhat.com>
---
 python/automake.mk                 |  8 ++-
 python/ovs/ovs_ofparse/__init__.py |  2 +
 python/ovs/ovs_ofparse/datapath.py | 10 ++++
 python/ovs/ovs_ofparse/main.py     | 89 ++++++++++++++++++++++++++++++
 python/ovs/ovs_ofparse/openflow.py | 11 ++++
 python/ovs/ovs_ofparse/ovs-ofparse |  6 ++
 python/setup.py                    |  8 ++-
 7 files changed, 131 insertions(+), 3 deletions(-)
 create mode 100644 python/ovs/ovs_ofparse/__init__.py
 create mode 100644 python/ovs/ovs_ofparse/datapath.py
 create mode 100644 python/ovs/ovs_ofparse/main.py
 create mode 100644 python/ovs/ovs_ofparse/openflow.py
 create mode 100755 python/ovs/ovs_ofparse/ovs-ofparse

diff --git a/python/automake.mk b/python/automake.mk
index 56cd9b7dc..cfe91c17b 100644
--- a/python/automake.mk
+++ b/python/automake.mk
@@ -51,7 +51,13 @@ ovs_pyfiles = \
 	python/ovs/flows/ofp_act.py \
 	python/ovs/flows/odp.py \
 	python/ovs/flows/filter.py \
-	python/ovs/flows/deps.py
+	python/ovs/flows/deps.py \
+	python/ovs/ovs_ofparse/__init__.py \
+	python/ovs/ovs_ofparse/main.py \
+	python/ovs/ovs_ofparse/datapath.py \
+	python/ovs/ovs_ofparse/openflow.py \
+	python/ovs/ovs_ofparse/ovs-ofparse
+
 
 ovs_tests = \
 	python/ovs/tests/test_kv.py \
diff --git a/python/ovs/ovs_ofparse/__init__.py b/python/ovs/ovs_ofparse/__init__.py
new file mode 100644
index 000000000..ba3a4e7e8
--- /dev/null
+++ b/python/ovs/ovs_ofparse/__init__.py
@@ -0,0 +1,2 @@
+import ovs.ovs_ofparse.openflow  # noqa: F401
+import ovs.ovs_ofparse.datapath  # noqa: F401
diff --git a/python/ovs/ovs_ofparse/datapath.py b/python/ovs/ovs_ofparse/datapath.py
new file mode 100644
index 000000000..c5bb43fa9
--- /dev/null
+++ b/python/ovs/ovs_ofparse/datapath.py
@@ -0,0 +1,10 @@
+import click
+
+from ovs.ovs_ofparse.main import maincli
+
+
+ at maincli.group(subcommand_metavar="FORMAT")
+ at click.pass_obj
+def datapath(opts):
+    """Process DPIF Flows"""
+    pass
diff --git a/python/ovs/ovs_ofparse/main.py b/python/ovs/ovs_ofparse/main.py
new file mode 100644
index 000000000..09fb08460
--- /dev/null
+++ b/python/ovs/ovs_ofparse/main.py
@@ -0,0 +1,89 @@
+import click
+import os.path
+import configparser
+
+from pkg_resources import resource_filename
+
+_default_config_file = "ovs-ofparse.conf"
+_default_config_path = os.path.abspath(
+    os.path.join(resource_filename(__name__, ""), "etc", _default_config_file)
+)
+
+
+class Options(dict):
+    """Options dictionary"""
+
+    pass
+
+
+def validate_input(ctx, param, value):
+    """Validate the "-i" option"""
+    result = list()
+    for input_str in value:
+        parts = input_str.strip().split(",")
+        if len(parts) == 2:
+            parts = tuple(parts)
+        elif len(parts) == 1:
+            parts = tuple(["Filename: " + parts[0], parts[0]])
+        else:
+            raise click.BadParameter(
+                "input filename should have the following format: "
+                "[alias,]FILENAME"
+            )
+
+        if not os.path.isfile(parts[1]):
+            raise click.BadParameter(
+                "input filename %s does not exist" % parts[1]
+            )
+        result.append(parts)
+    return result
+
+
+ at click.group(
+    subcommand_metavar="TYPE",
+    context_settings=dict(help_option_names=["-h", "--help"]),
+)
+ at click.option(
+    "-c",
+    "--config",
+    help="Use config file",
+    type=click.Path(),
+    default=_default_config_path,
+    show_default=True,
+)
+ at click.option(
+    "-i",
+    "--input",
+    "filename",
+    help="Read flows from specified filepath. If not provided, flows will be"
+    " read from stdin. This option can be specified multiple times."
+    " Format [alias,]FILENAME. Where alias is a name that shall be used to"
+    " refer to this FILENAME",
+    multiple=True,
+    type=click.Path(),
+    callback=validate_input,
+)
+ at click.pass_context
+def maincli(ctx, config, filename):
+    """
+    OpenFlow Parse utility.
+
+    It parses openflow and datapath flows
+    (such as the output of ovs-ofctl dump-flows or ovs-appctl dpctl/dump-flows)
+    and prints them in different formats.
+
+    """
+    ctx.obj = Options()
+    ctx.obj["filename"] = filename or None
+
+    config_file = config or _default_config_path
+    parser = configparser.ConfigParser()
+    parser.read(config_file)
+
+    ctx.obj["config"] = parser
+
+def main():
+    """
+    Main Function
+    """
+    maincli()
diff --git a/python/ovs/ovs_ofparse/openflow.py b/python/ovs/ovs_ofparse/openflow.py
new file mode 100644
index 000000000..0035c8118
--- /dev/null
+++ b/python/ovs/ovs_ofparse/openflow.py
@@ -0,0 +1,11 @@
+import click
+
+
+from ovs.ovs_ofparse.main import maincli
+
+
+ at maincli.group(subcommand_metavar="FORMAT")
+ at click.pass_obj
+def openflow(opts):
+    """Process OpenFlow Flows"""
+    pass
diff --git a/python/ovs/ovs_ofparse/ovs-ofparse b/python/ovs/ovs_ofparse/ovs-ofparse
new file mode 100755
index 000000000..32c503e9d
--- /dev/null
+++ b/python/ovs/ovs_ofparse/ovs-ofparse
@@ -0,0 +1,6 @@
+#!/usr/bin/env python3
+
+from ovs.ovs_ofparse import main
+
+if __name__ == '__main__':
+    main.main()
diff --git a/python/setup.py b/python/setup.py
index 4e8a9761a..6643f59cd 100644
--- a/python/setup.py
+++ b/python/setup.py
@@ -71,7 +71,7 @@ setup_args = dict(
     author='Open vSwitch',
     author_email='dev at openvswitch.org',
     packages=['ovs', 'ovs.compat', 'ovs.compat.sortedcontainers',
-              'ovs.db', 'ovs.unixctl', 'ovs.flows'],
+              'ovs.db', 'ovs.unixctl', 'ovs.flows', 'ovs.ovs_ofparse'],
     keywords=['openvswitch', 'ovs', 'OVSDB'],
     license='Apache 2.0',
     classifiers=[
@@ -87,7 +87,11 @@ setup_args = dict(
     ext_modules=[setuptools.Extension("ovs._json", sources=["ovs/_json.c"],
                                       libraries=['openvswitch'])],
     cmdclass={'build_ext': try_build_ext},
-    install_requires=['sortedcontainers', 'netaddr', 'pyparsing'],
+    install_requires=['sortedcontainers',
+                      'netaddr',
+                      'pyparsing',
+                      'click'],
+    scripts=['ovs/ovs_ofparse/ovs-ofparse'],
     extras_require={':sys_platform == "win32"': ['pywin32 >= 1.0']},
 )
 
-- 
2.31.1



More information about the dev mailing list