Re: [ovs-dev] [RFC PATCH 08/10] python: ovs: flowviz: Add Openflow cookie format.

2024-02-02 Thread Adrian Moreno



On 1/30/24 16:55, Eelco Chaudron wrote:

On 1 Dec 2023, at 20:14, Adrian Moreno wrote:


When anaylizing OVN issues, it might be useful to see what OpenFlow
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.


The code looks good to me, however, did not try with ovs-detrace. One comment 
on code that needs to move to the previous patch.
 > Maybe add an example in the commit message.


Sure.



Acked-by: Eelco Chaudron 


Signed-off-by: Adrian Moreno 
---
  python/ovs/flowviz/ofp/cli.py   | 57 -
  python/ovs/flowviz/ofp/logic.py | 63 -
  2 files changed, 118 insertions(+), 2 deletions(-)

diff --git a/python/ovs/flowviz/ofp/cli.py b/python/ovs/flowviz/ofp/cli.py
index 6b1435ea1..9658d00d3 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 (
  OpenFlowFactory,
  JSONProcessor,
@@ -182,6 +182,61 @@ def logic(
  processor.print(show_flows)


+@openflow.command()
+@click.option(
+"-d",
+"--ovn-detrace",
+"ovn_detrace_flag",
+is_flag=True,
+show_default=True,
+help="Use ovn-detrace to extract cookie information",
+)
+@click.option(
+"--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,
+)
+@click.option(
+"--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,
+)
+@click.option(
+"--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,
+)
+@click.option(
+"-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,
+)
+@click.pass_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 cb4568cf1..9d244d137 100644
--- a/python/ovs/flowviz/ofp/logic.py
+++ b/python/ovs/flowviz/ofp/logic.py
@@ -200,7 +200,7 @@ class LogicFlowProcessor(OpenFlowFactory, FileProcessor):
  if len(self.heat_map) > 0 and len(table.values()) > 0:
  for i, field in enumerate(self.heat_map):
  (min_val, max_val) = self.min_max[name][i]
-self.console.style.set_value_style(
+formatter.style.set_value_style(


This probably needs to move to patch 7.



Yep!


  field, heat_pallete(min_val, max_val)
  )

@@ -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(OpenFlowFactory, FileProcessor):
+"""Processor that sorts flows into cookies and tables."""
+
+def __init__(self, opts):
+super().__init__(opts)
+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()
+

Re: [ovs-dev] [RFC PATCH 08/10] python: ovs: flowviz: Add Openflow cookie format.

2024-01-30 Thread Eelco Chaudron
On 1 Dec 2023, at 20:14, Adrian Moreno wrote:

> When anaylizing OVN issues, it might be useful to see what OpenFlow
> 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.

The code looks good to me, however, did not try with ovs-detrace. One comment 
on code that needs to move to the previous patch.

Maybe add an example in the commit message.

Acked-by: Eelco Chaudron 

> Signed-off-by: Adrian Moreno 
> ---
>  python/ovs/flowviz/ofp/cli.py   | 57 -
>  python/ovs/flowviz/ofp/logic.py | 63 -
>  2 files changed, 118 insertions(+), 2 deletions(-)
>
> diff --git a/python/ovs/flowviz/ofp/cli.py b/python/ovs/flowviz/ofp/cli.py
> index 6b1435ea1..9658d00d3 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 (
>  OpenFlowFactory,
>  JSONProcessor,
> @@ -182,6 +182,61 @@ def logic(
>  processor.print(show_flows)
>
>
> +@openflow.command()
> +@click.option(
> +"-d",
> +"--ovn-detrace",
> +"ovn_detrace_flag",
> +is_flag=True,
> +show_default=True,
> +help="Use ovn-detrace to extract cookie information",
> +)
> +@click.option(
> +"--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,
> +)
> +@click.option(
> +"--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,
> +)
> +@click.option(
> +"--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,
> +)
> +@click.option(
> +"-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,
> +)
> +@click.pass_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 cb4568cf1..9d244d137 100644
> --- a/python/ovs/flowviz/ofp/logic.py
> +++ b/python/ovs/flowviz/ofp/logic.py
> @@ -200,7 +200,7 @@ class LogicFlowProcessor(OpenFlowFactory, FileProcessor):
>  if len(self.heat_map) > 0 and len(table.values()) > 0:
>  for i, field in enumerate(self.heat_map):
>  (min_val, max_val) = self.min_max[name][i]
> -self.console.style.set_value_style(
> +formatter.style.set_value_style(

This probably needs to move to patch 7.

>  field, heat_pallete(min_val, max_val)
>  )
>
> @@ -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(OpenFlowFactory, FileProcessor):
> +"""Processor that sorts flows into cookies and tables."""
> +
> +def __init__(self, opts):
> +super().__init__(opts)
> +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 

[ovs-dev] [RFC PATCH 08/10] python: ovs: flowviz: Add Openflow cookie format.

2023-12-01 Thread Adrian Moreno
When anaylizing OVN issues, it might be useful to see what OpenFlow
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.

Signed-off-by: Adrian Moreno 
---
 python/ovs/flowviz/ofp/cli.py   | 57 -
 python/ovs/flowviz/ofp/logic.py | 63 -
 2 files changed, 118 insertions(+), 2 deletions(-)

diff --git a/python/ovs/flowviz/ofp/cli.py b/python/ovs/flowviz/ofp/cli.py
index 6b1435ea1..9658d00d3 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 (
 OpenFlowFactory,
 JSONProcessor,
@@ -182,6 +182,61 @@ def logic(
 processor.print(show_flows)
 
 
+@openflow.command()
+@click.option(
+"-d",
+"--ovn-detrace",
+"ovn_detrace_flag",
+is_flag=True,
+show_default=True,
+help="Use ovn-detrace to extract cookie information",
+)
+@click.option(
+"--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,
+)
+@click.option(
+"--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,
+)
+@click.option(
+"--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,
+)
+@click.option(
+"-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,
+)
+@click.pass_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 cb4568cf1..9d244d137 100644
--- a/python/ovs/flowviz/ofp/logic.py
+++ b/python/ovs/flowviz/ofp/logic.py
@@ -200,7 +200,7 @@ class LogicFlowProcessor(OpenFlowFactory, FileProcessor):
 if len(self.heat_map) > 0 and len(table.values()) > 0:
 for i, field in enumerate(self.heat_map):
 (min_val, max_val) = self.min_max[name][i]
-self.console.style.set_value_style(
+formatter.style.set_value_style(
 field, heat_pallete(min_val, max_val)
 )
 
@@ -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(OpenFlowFactory, FileProcessor):
+"""Processor that sorts flows into cookies and tables."""
+
+def __init__(self, opts):
+super().__init__(opts)
+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():
+