On 10 Jul 2024, at 19:04, Adrian Moreno wrote:
> When anaylizing OVN issues, it might be useful to see what OpenFlow
anaylizing -> analyzing
> flows were generated from each logical flow. In order to make it simpler
> to visualize this, add a cookie format that simply sorts the flows first
> by cookie, then by table.
>
> Example:
> $ export OVN_NB_DB=...
> $ export OVN_SB_DB=...
> $ ovs-vsctl dump-flows br-int | ovs-flowviz openflow cookie
> --ovn-filter="acl.*icmp4"
> $ ovs-vsctl dump-flows br-int | ovs-flowviz openflow cookie
> --ovn-detrace
>
> Acked-by: Eelco Chaudron <[email protected]>
> Signed-off-by: Adrian Moreno <[email protected]>
> ---
Thanks for sending the v5, the changes look good to me (one spelling error in
the commit message).
//Eelco
Acked-by: Eelco Chaudron <[email protected]>
> python/ovs/flowviz/ofp/cli.py | 57 +++++++++++++++++++++++++++++-
> python/ovs/flowviz/ofp/logic.py | 61 +++++++++++++++++++++++++++++++++
> 2 files changed, 117 insertions(+), 1 deletion(-)
>
> diff --git a/python/ovs/flowviz/ofp/cli.py b/python/ovs/flowviz/ofp/cli.py
> index a0a94bd3b..291384bd4 100644
> --- a/python/ovs/flowviz/ofp/cli.py
> +++ b/python/ovs/flowviz/ofp/cli.py
> @@ -18,7 +18,7 @@ import click
>
> from ovs.flowviz.main import maincli
> from ovs.flowviz.ofp.html import HTMLProcessor
> -from ovs.flowviz.ofp.logic import LogicFlowProcessor
> +from ovs.flowviz.ofp.logic import CookieProcessor, LogicFlowProcessor
> from ovs.flowviz.process import (
> ConsoleProcessor,
> JSONOpenFlowProcessor,
> @@ -172,6 +172,61 @@ def logic(
> processor.print(show_flows)
>
>
> [email protected]()
> [email protected](
> + "-d",
> + "--ovn-detrace",
> + "ovn_detrace_flag",
> + is_flag=True,
> + show_default=True,
> + help="Use ovn-detrace to extract cookie information",
> +)
> [email protected](
> + "--ovn-detrace-path",
> + default="/usr/bin",
> + type=click.Path(),
> + help="Use an alternative path to where ovn_detrace.py is located. "
> + "Instead of using this option you can just set PYTHONPATH accordingly",
> + show_default=True,
> + callback=ovn_detrace_callback,
> +)
> [email protected](
> + "--ovnnb-db",
> + default=os.getenv("OVN_NB_DB") or "unix:/var/run/ovn/ovnnb_db.sock",
> + help="Specify the OVN NB database string (implies -d). "
> + "If the OVN_NB_DB environment variable is set, it's used as default. "
> + "Otherwise, the default is unix:/var/run/ovn/ovnnb_db.sock",
> + callback=ovn_detrace_callback,
> +)
> [email protected](
> + "--ovnsb-db",
> + default=os.getenv("OVN_SB_DB") or "unix:/var/run/ovn/ovnsb_db.sock",
> + help="Specify the OVN NB database string (implies -d). "
> + "If the OVN_NB_DB environment variable is set, it's used as default. "
> + "Otherwise, the default is unix:/var/run/ovn/ovnnb_db.sock",
> + callback=ovn_detrace_callback,
> +)
> [email protected](
> + "-o",
> + "--ovn-filter",
> + help="Specify a filter to be run on ovn-detrace information (implied
> -d). "
> + "Format: python regular expression "
> + "(see https://docs.python.org/3/library/re.html)",
> + callback=ovn_detrace_callback,
> +)
> [email protected]_obj
> +def cookie(
> + opts, ovn_detrace_flag, ovn_detrace_path, ovnnb_db, ovnsb_db, ovn_filter
> +):
> + """Print the flow tables sorted by cookie."""
> + if ovn_detrace_flag:
> + opts["ovn_detrace_flag"] = True
> +
> + processor = CookieProcessor(opts)
> + processor.process()
> + processor.print()
> +
> +
> @openflow.command()
> @click.pass_obj
> def html(opts):
> diff --git a/python/ovs/flowviz/ofp/logic.py b/python/ovs/flowviz/ofp/logic.py
> index dd5c29c5a..db5c2e699 100644
> --- a/python/ovs/flowviz/ofp/logic.py
> +++ b/python/ovs/flowviz/ofp/logic.py
> @@ -301,3 +301,64 @@ cookie_style_gen = hash_pallete(
> saturation=[0.5],
> value=[0.5 + x / 10 * (0.85 - 0.5) for x in range(0, 10)],
> )
> +
> +
> +class CookieProcessor(FileProcessor):
> + """Processor that sorts flows into cookies and tables."""
> +
> + def __init__(self, opts):
> + super().__init__(opts, "ofp")
> + self.data = dict()
> + self.ovn_detrace = (
> + OVNDetrace(opts) if opts.get("ovn_detrace_flag") else None
> + )
> +
> + def start_file(self, name, filename):
> + self.cookies = dict()
> +
> + def stop_file(self, name, filename):
> + self.data[name] = self.cookies
> +
> + def process_flow(self, flow, name):
> + """Sort the flows by table and logical flow."""
> + cookie = flow.info.get("cookie") or 0
> + if not self.cookies.get(cookie):
> + self.cookies[cookie] = dict()
> +
> + table = flow.info.get("table") or 0
> + if not self.cookies[cookie].get(table):
> + self.cookies[cookie][table] = list()
> + self.cookies[cookie][table].append(flow)
> +
> + def print(self):
> + ofconsole = ConsoleFormatter(opts=self.opts)
> + console = ofconsole.console
> + for name, cookies in self.data.items():
> + console.print("\n")
> + console.print(file_header(name))
> + tree = Tree("Ofproto Cookie Tree")
> +
> + for cookie, tables in cookies.items():
> + ovn_info = None
> + if self.ovn_detrace:
> + ovn_info = self.ovn_detrace.get_ovn_info(cookie)
> + if self.opts.get("ovn_filter"):
> + ovn_regexp = re.compile(self.opts.get("ovn_filter"))
> + if not ovn_regexp.search(ovn_info):
> + continue
> +
> + cookie_tree = tree.add("** Cookie {} **".format(hex(cookie)))
> + if ovn_info:
> + ovn = cookie_tree.add("OVN Info")
> + for part in ovn_info.split("\n"):
> + if part.strip():
> + ovn.add(part.strip())
> +
> + tables_tree = cookie_tree.add("Tables")
> + for table, flows in tables.items():
> + table_tree = tables_tree.add("* Table {} *
> ".format(table))
> + for flow in flows:
> + buf = ConsoleBuffer(Text())
> + ofconsole.format_flow(buf, flow)
> + table_tree.add(buf.text)
> + console.print(tree)
> --
> 2.45.2
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev