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.

 * Put actions into the same panel as the flow matches.  This saves
   another nesting level.

 * 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.

 * 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.

Signed-off-by: Ilya Maximets <[email protected]>
---

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
 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
         )
 
-        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