On Fri, Oct 25, 2024 at 12:11:06PM +0200, Ilya Maximets wrote:
> On 10/23/24 16:47, Eelco Chaudron wrote:
> >
> > On 21 Oct 2024, at 21:15, Ilya Maximets wrote:
> >
> >> There are few changes here:
> >>
> >>  * Make a separate recirculation node to not appear in case there is
> >>    only one flow with this id.  This saves a nesting level.
> >
> > When reviewing a large trace, I prefer consistency. If one entry has 
> > multiple
> > sub-entries, all of them should have the extra nesting to improve ease of 
> > reading.
>
> I do like consistency, but 8 nesting levels in 4-time recirculation
> do not allow me to understand what I'm looking at efficiently.
> Maybe we can add an option?  e.g. "datapath tree --compact" to hide
> single-node recirculations.  WDYT?

I guess this is very subjective. My eyes are OK with the lack of
indentation consistency. However, sometimes they miss the recirculation
block title that is present in others, i.e: [recirc_id(0x12) in_port(eth0)]

Maybe we could add the title within the same Panel(Group())?

Regarding, "--compact" I think this command has already quite a lot of
options and would prefer not to add more but if we cannot agree on a
style it's probably a good solution.

>
> >
> >>  * Put actions into the same panel as the flow matches.  This saves
> >>    another nesting level.
> >
> > I liked the extra separation with the boxes. However, if we decide to 
> > remove the
> > boxes, using the theme color alone would work. If we stick with the boxes, 
> > we could
> > simply remove the indent.
>
> I don't think rich allows to not have an indent.  Since we do have
> different preferences, maybe we could use an option here too, e.g.
> make the --compact affect both the recirculation and action node?
>

Separating the actions with blocks that have many flows. Specially if
dumped with "-m" where that can make individual flows be wrapped.

Maybe adding a newline between flows and actions would help the eye
while avoiding an extra indention level?

If we cannot agree on a style that is good enough for everyone we
can add a compact option but let's at least try to find some middle
grounds.

A combination of my two proposals is this snipped:

diff --git a/python/ovs/flowviz/odp/tree.py b/python/ovs/flowviz/odp/tree.py
index cd781e330..911387cf9 100644
--- a/python/ovs/flowviz/odp/tree.py
+++ b/python/ovs/flowviz/odp/tree.py
@@ -473,18 +473,19 @@ class ConsoleTreeProcessor(FileProcessor):

         visible_blocks = list(node.visible_blocks())

-        # If there is only one node with this recirc_id, don't create
-        # an extra nesting level, just print the node.
-        if len(visible_blocks) == 1:
-            self.print_block(visible_blocks[0], parent, recirc_style)
-            return
-
         node_text = Text(
             "[recirc_id({}) in_port({})]".format(
                 hex(node.recirc), node.in_port
             ),
             style=recirc_style,
         )
+        # If there is only one node with this recirc_id, don't create
+        # an extra nesting level, just print the node.
+        if len(visible_blocks) == 1:
+            self.print_block(visible_blocks[0], parent, recirc_style,
+                             title=node_text)
+            return
+
         console_node = parent.add(
             Panel(node_text, box=TreeBox, border_style=recirc_style),
             guide_style=recirc_style
@@ -493,9 +494,13 @@ class ConsoleTreeProcessor(FileProcessor):
         for block in visible_blocks:
             self.print_block(block, console_node, recirc_style)

-    def print_block(self, block, parent, style):
+    def print_block(self, block, parent, style, title=None):
         # Print the flow matches and the statistics.
         flow_text = []
+        if title:
+            flow_text.append(title)
+            flow_text.append("\n")
+
         omit_first = {
             "actions": "all",
         }
@@ -520,6 +525,7 @@ class ConsoleTreeProcessor(FileProcessor):
         act_buf.append_extra("actions: ", Style(bold=(self.style is not None)))

         self.ofconsole.format_flow(act_buf, block.flows[0].flow, omitted=omit)
+        flow_text.append("\n")
         flow_text.append(act_buf.text)

         flows_node = parent.add(



> >
> >>  * Replace default panel box with a custom one, which is essentially
> >>    only the side border with some angles.  This makes the output much
> >>    less busy and much easier on eyes, IMO.
> >>
> >>    The bottom hook looks a little awkward if there is a guide line
> >>    right below it, but it doesn't seem too distracting, and I didn't
> >>    find an ASCII top-half of a vertical line symbol.  This one also
> >>    looks nice closing the blocks.
> >>
> >>    Discontinuous lines of '|' symbols are also a smaller distraction
> >>    than a continuous line of '│' symbols.
> >
> > I don't have a strong preference either way. Both options get the job done.
> > For the new mode, I'd even suggest removing the ending |, since there's no
> > real box anymore.
>
> Yeah, I thought about that too, but then I added the ending side back,
> just because I don't like trailing spaces and rich doesn't have ability
> to not add anything.  It will add a symbol, we only can choose if it is
> a space or a vertical line.

I don't have a strong opinion on the last character, and my eyes also
appreciate this lighter box.

>
> >
> >>  * Make recirculation color propagate down, so panels are colored in
> >>    the color of their recirculation.  This also fixes the guide line
> >>    color to a recirc node to not be a default white and so to not be
> >>    a visual distraction.
> >
> > I do like this.
> >

+1 this is great.

> >> Signed-off-by: Ilya Maximets <[email protected]>
> >> ---
> >
> > I didn’t find any coding or documentation issues, aside from the comments
> > mentioned above. I assume Adrian has some thoughts on this as well, so let’s
> > wait for his feedback.
>
> Sure, let's see if Adrian has some opinion on these changes.

Some nits below. A general question though: the HTML format is still using
boxes and a different indentation level for actions. Should we also
change it keep it consistent?

Thanks for improving this view.
Adrián.

>
> Thanks for taking a look!
>
> Best regards, Ilya Maximets.
>
> >
> > Cheers,
> >
> > Eelco
> >
> >> There are a few checkpatch warnings, but the long lines in the doc and
> >> the trailing spaces in the box definition are on purpose.
> >>
> >>  Documentation/topics/flow-visualization.rst | 74 +++++++++------------
> >>  python/ovs/flowviz/odp/tree.py              | 47 +++++++++----
> >>  2 files changed, 65 insertions(+), 56 deletions(-)
> >>
> >> diff --git a/Documentation/topics/flow-visualization.rst 
> >> b/Documentation/topics/flow-visualization.rst
> >> index 3165f796f..518487b45 100644
> >> --- a/Documentation/topics/flow-visualization.rst
> >> +++ b/Documentation/topics/flow-visualization.rst
> >> @@ -201,49 +201,37 @@ For example:
> >>  ::
> >>
> >>    Datapath Flows (logical)
> >> -  └── ╭────────────────────────────────╮
> >> -      │ [recirc_id(0x0) in_port(eth0)] │
> >> -      ╰────────────────────────────────╯
> >> -      └── 
> >> ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
> >> -          │ 
> >> recirc_id(0),dp_hash(0/0),skb_priority(0/0),in_port(eth0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),eth(src=0a:58:0a:84:00:07,dst=22:a1:5d:dc:95:50),eth_type(0x0800),ipv4(src=10.132.0.7,dst=1
> >>  │
> >> -          │ 
> >> 0.128.0.0/255.128.0.0,proto=6,tos=0/0,ttl=0/0,frag=no),tcp(src=0/0,dst=0/0),tcp_flags(0/0),
> >>  packets:4924, bytes:468961,                                               
> >>                                                     │
> >> -          │ 
> >> recirc_id(0),dp_hash(...),skb_priority(...),in_port(eth0),skb_mark(...),ct_state(...),ct_zone(...),ct_mark(...),ct_label(...),eth(src=0a:58:0a:84:00:07,dst=0a:58:0a:84:00:01),eth_type(......),ipv4(src=10.132.0.7,dst=1
> >>  │
> >> -          │ 
> >> 0.0.0.0/255.255.128.0,proto=17,tos=0/0,ttl=0/0,frag=no),udp(src=32768/0x8000,dst=0/0),
> >>  packets:711, bytes:114236,                                                
> >>                                                          │
> >> -          │ 
> >> recirc_id(0),dp_hash(...),skb_priority(...),in_port(eth0),skb_mark(...),ct_state(...),ct_zone(...),ct_mark(...),ct_label(...),eth(src=0a:58:0a:84:00:07,dst=0a:58:0a:84:00:14),eth_type(......),ipv4(src=10.132.0.7,dst=1
> >>  │
> >> -          │ 
> >> 0.128.0.0/255.128.0.0,proto=17,tos=0/0,ttl=0/0,frag=no),udp(src=4096/0xf000,dst=0/0),
> >>  packets:140, bytes:114660,                                                
> >>                                                           │
> >> -          │ 
> >> recirc_id(0),dp_hash(...),skb_priority(...),in_port(eth0),skb_mark(...),ct_state(...),ct_zone(...),ct_mark(...),ct_label(...),eth(src=0a:58:0a:84:00:07,dst=0a:58:0a:84:00:22),eth_type(......),ipv4(src=10.132.0.7,dst=1
> >>  │
> >> -          │ 
> >> 0.128.0.0/255.128.0.0,proto=6,tos=0/0,ttl=0/0,frag=no),tcp(src=0/0,dst=0/0),tcp_flags(0/0),
> >>  packets:1, bytes:66,                                                      
> >>                                                     │
> >> -          │ 
> >> recirc_id(0),dp_hash(...),skb_priority(...),in_port(eth0),skb_mark(...),ct_state(...),ct_zone(...),ct_mark(...),ct_label(...),eth(src=0a:58:0a:84:00:07,dst=0a:58:0a:84:00:09),eth_type(......),ipv4(src=10.132.0.7,dst=1
> >>  │
> >> -          │ 
> >> 0.128.0.0/255.128.0.0,proto=17,tos=0/0,ttl=0/0,frag=no),udp(src=4096/0xf000,dst=0/0),
> >>  packets:0, bytes:0,                                                       
> >>                                                           │
> >> -          
> >> ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
> >> -          └── ╭───────────────────────────────────────╮
> >> -              │ actions: ct(zone=32,nat),recirc(0xc1) │
> >> -              ╰───────────────────────────────────────╯
> >> -              └── ╭─────────────────────────────────╮
> >> -                  │ [recirc_id(0xc1) in_port(eth0)] │
> >> -                  ╰─────────────────────────────────╯
> >> -                  ├── 
> >> ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
> >> -                  │   │ 
> >> recirc_id(0xc1),dp_hash(0/0),skb_priority(0/0),in_port(eth0),skb_mark(0/0),ct_state(0x2a/0x3f),ct_zone(0/0),ct_mark(0/0xf),ct_label(0/0),eth(src=0a:58:0a:84:00:07,dst=22:a1:5d:dc:95:50),eth_type(0x0800),ip
> >>  │
> >> -                  │   │ 
> >> v4(src=0.0.0.0/0.0.0.0,dst=0.0.0.0/0.0.0.0,proto=6,tos=0/0,ttl=0/0,frag=no),tcp(src=0/0,dst=0/0),tcp_flags(0/0),
> >>  packets:4924, bytes:468961,                                               
> >>                    │
> >> -                  │   
> >> ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
> >> -                  │   └── ╭───────────────────────────────────────╮
> >> -                  │       │ actions: ct(zone=14,nat),recirc(0xc2) │
> >> -                  │       ╰───────────────────────────────────────╯
> >> -                  │       └── ╭─────────────────────────────────╮
> >> -                  │           │ [recirc_id(0xc2) in_port(eth0)] │
> >> -                  │           ╰─────────────────────────────────╯
> >> -                  │           └── 
> >> ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
> >> -                  │               │ 
> >> recirc_id(0xc2),dp_hash(0/0),skb_priority(0/0),in_port(eth0),skb_mark(0/0),ct_state(0x2a/0x3f),ct_zone(0/0),ct_mark(0/0x1),ct_label(0/0),eth(src=00:00:00:00:00:00/00:00:00:00:00:00,dst=00:00:00
> >>  │
> >> -                  │               │ 
> >> :00:00:00/01:00:00:00:00:00),eth_type(0x0800),ipv4(src=0.0.0.0/0.0.0.0,dst=0.0.0.0/0.0.0.0,proto=0/0,tos=0/0,ttl=0/0,frag=no),
> >>  packets:4924, bytes:468961,                                        │
> >> -                  │               
> >> ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
> >> -                  │               └── ╭──────────────────────╮
> >> -                  │                   │ actions: ovn-k8s-mp0 │
> >> -                  │                   ╰──────────────────────╯
> >> -                  ├── 
> >> ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
> >> -                  │   │ 
> >> recirc_id(0xc1),dp_hash(0/0),skb_priority(0/0),in_port(eth0),skb_mark(0/0),ct_state(0x2a/0x3f),ct_zone(0/0),ct_mark(0/0xf),ct_label(0/0),eth(src=0a:58:0a:84:00:07,dst=0a:58:0a:84:00:14),eth_type(0x0800),ip
> >>  │
> >> -                  │   │ 
> >> v4(src=0.0.0.0/0.0.0.0,dst=0.0.0.0/0.0.0.0,proto=17,tos=0/0,ttl=0/0,frag=no),udp(src=4096/0xf000,dst=0/0),
> >>  packets:140, bytes:114660                                                 
> >>                          │
> >> -                  │   
> >> ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
> >> -
> >> +  └── ╮
> >> +      | 
> >> recirc_id(0),dp_hash(0/0),skb_priority(0/0),in_port(eth0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),eth(src=0a:58:0a:84:00:07,dst=22:a1:5d:dc:95:50),eth_type(0x0800),ipv4(src=10.132.0.7,dst=10.12
> >>  |
> >> +      | 
> >> 8.0.0/255.128.0.0,proto=6,tos=0/0,ttl=0/0,frag=no),tcp(src=0/0,dst=0/0),tcp_flags(0/0),
> >>  packets:4924, bytes:468961,                                               
> >>                                                             |
> >> +      | 
> >> recirc_id(0),dp_hash(...),skb_priority(...),in_port(eth0),skb_mark(...),ct_state(...),ct_zone(...),ct_mark(...),ct_label(...),eth(src=0a:58:0a:84:00:07,dst=0a:58:0a:84:00:01),eth_type(......),ipv4(src=10.132.0.7,dst=10.0.
> >>  |
> >> +      | 
> >> 0.0/255.255.128.0,proto=17,tos=0/0,ttl=0/0,frag=no),udp(src=32768/0x8000,dst=0/0),
> >>  packets:711, bytes:114236,                                                
> >>                                                                  |
> >> +      | 
> >> recirc_id(0),dp_hash(...),skb_priority(...),in_port(eth0),skb_mark(...),ct_state(...),ct_zone(...),ct_mark(...),ct_label(...),eth(src=0a:58:0a:84:00:07,dst=0a:58:0a:84:00:14),eth_type(......),ipv4(src=10.132.0.7,dst=10.12
> >>  |
> >> +      | 
> >> 8.0.0/255.128.0.0,proto=17,tos=0/0,ttl=0/0,frag=no),udp(src=4096/0xf000,dst=0/0),
> >>  packets:140, bytes:114660,                                                
> >>                                                                   |
> >> +      | 
> >> recirc_id(0),dp_hash(...),skb_priority(...),in_port(eth0),skb_mark(...),ct_state(...),ct_zone(...),ct_mark(...),ct_label(...),eth(src=0a:58:0a:84:00:07,dst=0a:58:0a:84:00:22),eth_type(......),ipv4(src=10.132.0.7,dst=10.12
> >>  |
> >> +      | 
> >> 8.0.0/255.128.0.0,proto=6,tos=0/0,ttl=0/0,frag=no),tcp(src=0/0,dst=0/0),tcp_flags(0/0),
> >>  packets:1, bytes:66,                                                      
> >>                                                             |
> >> +      | 
> >> recirc_id(0),dp_hash(...),skb_priority(...),in_port(eth0),skb_mark(...),ct_state(...),ct_zone(...),ct_mark(...),ct_label(...),eth(src=0a:58:0a:84:00:07,dst=0a:58:0a:84:00:09),eth_type(......),ipv4(src=10.132.0.7,dst=10.12
> >>  |
> >> +      | 
> >> 8.0.0/255.128.0.0,proto=17,tos=0/0,ttl=0/0,frag=no),udp(src=4096/0xf000,dst=0/0),
> >>  packets:0, bytes:0,                                                       
> >>                                                                   |
> >> +      | actions: ct(zone=32,nat),recirc(0xc1)                             
> >>                                                                            
> >>                                                                            
> >>       |
> >> +      └
> >> +      └── ╮
> >> +          | [recirc_id(0xc1) in_port(eth0)]                               
> >>                                                                            
> >>                                                                            
> >>       |
> >> +          └
> >> +          ├── ╮
> >> +          │   | 
> >> recirc_id(0xc1),dp_hash(0/0),skb_priority(0/0),in_port(eth0),skb_mark(0/0),ct_state(0x2a/0x3f),ct_zone(0/0),ct_mark(0/0xf),ct_label(0/0),eth(src=0a:58:0a:84:00:07,dst=22:a1:5d:dc:95:50),eth_type(0x0800),ipv4(src=0
> >>  |
> >> +          │   | 
> >> .0.0.0/0.0.0.0,dst=0.0.0.0/0.0.0.0,proto=6,tos=0/0,ttl=0/0,frag=no),tcp(src=0/0,dst=0/0),tcp_flags(0/0),
> >>  packets:4924, bytes:468961,                                               
> >>                                    |
> >> +          │   | actions: ct(zone=14,nat),recirc(0xc2)                     
> >>                                                                            
> >>                                                                            
> >>       |
> >> +          │   └
> >> +          │   └──
> >> +          │       | 
> >> recirc_id(0xc2),dp_hash(0/0),skb_priority(0/0),in_port(eth0),skb_mark(0/0),ct_state(0x2a/0x3f),ct_zone(0/0),ct_mark(0/0x1),ct_label(0/0),eth(src=00:00:00:00:00:00/00:00:00:00:00:00,dst=00:00:00:00:00:00/01:00:
> >>  |
> >> +          │       | 
> >> 00:00:00:00),eth_type(0x0800),ipv4(src=0.0.0.0/0.0.0.0,dst=0.0.0.0/0.0.0.0,proto=0/0,tos=0/0,ttl=0/0,frag=no),
> >>  packets:4924, bytes:468961,                                               
> >>                          |
> >> +          │       | actions: ovn-k8s-mp0                                  
> >>                                                                            
> >>                                                                            
> >>       |
> >> +          │       └
> >> +          ├── ╮
> >> +          │   | 
> >> recirc_id(0xc1),dp_hash(0/0),skb_priority(0/0),in_port(eth0),skb_mark(0/0),ct_state(0x2a/0x3f),ct_zone(0/0),ct_mark(0/0xf),ct_label(0/0),eth(src=0a:58:0a:84:00:07,dst=0a:58:0a:84:00:14),eth_type(0x0800),ipv4(src=0
> >>  |
> >> +          │   | 
> >> .0.0.0/0.0.0.0,dst=0.0.0.0/0.0.0.0,proto=17,tos=0/0,ttl=0/0,frag=no),udp(src=4096/0xf000,dst=0/0),
> >>  packets:140, bytes:114660                                                 
> >>                                          |
> >> +          │   | actions: ct(zone=14,nat),drop                             
> >>                                                                            
> >>                                                                            
> >>       |
> >> +          │   └
> >>
> >>  The above shows a part of a bigger tree with an initial block of flows
> >>  at ``recirc_id(0)`` which match on different destination Ethernet
> >> diff --git a/python/ovs/flowviz/odp/tree.py 
> >> b/python/ovs/flowviz/odp/tree.py
> >> index d6526504b..cd781e330 100644
> >> --- a/python/ovs/flowviz/odp/tree.py
> >> +++ b/python/ovs/flowviz/odp/tree.py
> >> @@ -14,6 +14,7 @@
> >>
> >>  import sys
> >>
> >> +from rich import box

I don't think there is global consensus around this but following the
style of the file, I think it should be either:

import rich.box # module import
or
from rich.box import Box # class import

Given only one class is being used I tend to prefer the later.

> >>  from rich.style import Style
> >>  from rich.console import Group
> >>  from rich.panel import Panel
> >> @@ -33,6 +34,21 @@ from ovs.flowviz.process import (
> >>  )
> >>
> >>
> >> +TreeBox = box.Box(
> >> +    """\
> >> +╮
> >> +|  |
> >> +|  |
> >> +|  |
> >> +|  |
> >> +|  |
> >> +|  |
> >> +└
> >> +""",  # noqa: W291
> >> +    ascii=True,
> >> +)
> >> +
> >> +
> >>  class TreeFlow(object):
> >>      """A flow within a Tree."""
> >>
> >> @@ -453,7 +469,15 @@ class ConsoleTreeProcessor(FileProcessor):
> >>          if self.ofconsole.style:
> >>              recirc_style = self.recirc_style_gen(hex(node.recirc))
> >>          else:
> >> -            recirc_style = None
> >> +            recirc_style = Style(color="default")
> >> +
> >> +        visible_blocks = list(node.visible_blocks())
> >> +
> >> +        # If there is only one node with this recirc_id, don't create
> >> +        # an extra nesting level, just print the node.
> >> +        if len(visible_blocks) == 1:
> >> +            self.print_block(visible_blocks[0], parent, recirc_style)
> >> +            return
> >>
> >>          node_text = Text(
> >>              "[recirc_id({}) in_port({})]".format(
> >> @@ -462,13 +486,14 @@ class ConsoleTreeProcessor(FileProcessor):
> >>              style=recirc_style,
> >>          )
> >>          console_node = parent.add(
> >> -            Panel.fit(node_text), guide_style=recirc_style
> >> +            Panel(node_text, box=TreeBox, border_style=recirc_style),
> >> +            guide_style=recirc_style

super-nit: my nit-picky eyes, probably shaped by "black", ask for a
comma at the end of this line. Same for multi-line argument list below.

> >>          )
> >>
> >> -        for block in node.visible_blocks():
> >> -            self.print_block(block, console_node)
> >> +        for block in visible_blocks:
> >> +            self.print_block(block, console_node, recirc_style)
> >>
> >> -    def print_block(self, block, parent):
> >> +    def print_block(self, block, parent, style):
> >>          # Print the flow matches and the statistics.
> >>          flow_text = []
> >>          omit_first = {
> >> @@ -495,18 +520,14 @@ class ConsoleTreeProcessor(FileProcessor):
> >>          act_buf.append_extra("actions: ", Style(bold=(self.style is not 
> >> None)))
> >>
> >>          self.ofconsole.format_flow(act_buf, block.flows[0].flow, 
> >> omitted=omit)
> >> +        flow_text.append(act_buf.text)
> >>
> >>          flows_node = parent.add(
> >> -            Panel(Group(*flow_text)), guide_style=Style(color="default")
> >> -        )
> >> -        action_node = flows_node.add(
> >> -            Panel.fit(
> >> -                act_buf.text, border_style="green" if self.style else 
> >> "default"
> >> -            ),
> >> -            guide_style=Style(color="default"),
> >> +            Panel(Group(*flow_text), box=TreeBox, border_style=style),
> >> +            guide_style=style
> >>          )
> >>
> >>          # Nested to the action, print the next recirc nodes.
> >>          for node in block.next_recirc_nodes:
> >>              if node.visible:
> >> -                self.print_recirc_node(action_node, node)
> >> +                self.print_recirc_node(flows_node, node)
> >> --
> >> 2.46.0
> >
>
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to