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 <echau...@redhat.com> > Signed-off-by: Adrian Moreno <amore...@redhat.com> > --- > 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 = 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.43.0 > > _______________________________________________ > dev mailing list > d...@openvswitch.org > https://mail.openvswitch.org/mailman/listinfo/ovs-dev _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev