Re: [ovs-dev] [RFC PATCH 08/10] python: ovs: flowviz: Add Openflow cookie format.
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.
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.
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(): +