Re: [ovs-dev] [PATCH v1 06/12] python: ovs: flowviz: Add datapath tree format.

2024-02-29 Thread Eelco Chaudron



On 19 Feb 2024, at 9:14, Adrian Moreno wrote:

> Datapath flows can be arranged into a "tree"-like structure based on
> recirculation ids, e.g:
>
>  recirc(0),eth(...),ipv4(...) actions=ct,recirc(0x42)
>\-> recirc(42),ct_state(0/0),eth(...),ipv4(...) actions=1
>\-> recirc(42),ct_state(1/0),eth(...),ipv4(...) actions=userspace(...)
>
> This patch adds support for building such logical datapath trees in a
> format-agnostic way and adds support for console-based formatting
> supporting:
> - head-maps formatting of statistics
> - hash-based pallete of recirculation ids: each recirculation id is
>   assigned a unique color to easily follow the sequence of related
>   actions.
> - full-tree filtering: if a user specifies a filter, an entire subtree
>   is filtered out if none of its branches satisfy it.
>
> Acked-by: Eelco Chaudron 
> Signed-off-by: Adrian Moreno 

Ack on the additional small changes.

Acked-by: Eelco Chaudron 

___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


[ovs-dev] [PATCH v1 06/12] python: ovs: flowviz: Add datapath tree format.

2024-02-19 Thread Adrian Moreno
Datapath flows can be arranged into a "tree"-like structure based on
recirculation ids, e.g:

 recirc(0),eth(...),ipv4(...) actions=ct,recirc(0x42)
   \-> recirc(42),ct_state(0/0),eth(...),ipv4(...) actions=1
   \-> recirc(42),ct_state(1/0),eth(...),ipv4(...) actions=userspace(...)

This patch adds support for building such logical datapath trees in a
format-agnostic way and adds support for console-based formatting
supporting:
- head-maps formatting of statistics
- hash-based pallete of recirculation ids: each recirculation id is
  assigned a unique color to easily follow the sequence of related
  actions.
- full-tree filtering: if a user specifies a filter, an entire subtree
  is filtered out if none of its branches satisfy it.

Acked-by: Eelco Chaudron 
Signed-off-by: Adrian Moreno 
---
 python/automake.mk |   1 +
 python/ovs/flowviz/console.py  |  21 +++
 python/ovs/flowviz/odp/cli.py  |  21 ++-
 python/ovs/flowviz/odp/tree.py | 291 +
 4 files changed, 332 insertions(+), 2 deletions(-)
 create mode 100644 python/ovs/flowviz/odp/tree.py

diff --git a/python/automake.mk b/python/automake.mk
index 0487494d0..b3fef9bed 100644
--- a/python/automake.mk
+++ b/python/automake.mk
@@ -71,6 +71,7 @@ ovs_flowviz = \
python/ovs/flowviz/main.py \
python/ovs/flowviz/odp/__init__.py \
python/ovs/flowviz/odp/cli.py \
+   python/ovs/flowviz/odp/tree.py \
python/ovs/flowviz/ofp/__init__.py \
python/ovs/flowviz/ofp/cli.py \
python/ovs/flowviz/ofp/html.py \
diff --git a/python/ovs/flowviz/console.py b/python/ovs/flowviz/console.py
index 4a3443360..93cd9b0b1 100644
--- a/python/ovs/flowviz/console.py
+++ b/python/ovs/flowviz/console.py
@@ -13,6 +13,8 @@
 # limitations under the License.
 
 import colorsys
+import itertools
+import zlib
 
 from rich.console import Console
 from rich.color import Color
@@ -170,6 +172,25 @@ def heat_pallete(min_value, max_value):
 return heat
 
 
+def hash_pallete(hue, saturation, value):
+"""Generates a color pallete with the cartesian product
+of the hsv values provided and returns a callable that assigns a color for
+each value hash
+"""
+HSV_tuples = itertools.product(hue, saturation, value)
+RGB_tuples = map(lambda x: colorsys.hsv_to_rgb(*x), HSV_tuples)
+styles = [
+Style(color=Color.from_rgb(r * 255, g * 255, b * 255))
+for r, g, b in RGB_tuples
+]
+
+def get_style(string):
+hash_val = zlib.crc32(bytes(str(string), "utf-8"))
+return styles[hash_val % len(styles)]
+
+return get_style
+
+
 def default_highlight():
 """Generates a default style for highlights."""
 return Style(underline=True)
diff --git a/python/ovs/flowviz/odp/cli.py b/python/ovs/flowviz/odp/cli.py
index 78f5cfff4..4740e753e 100644
--- a/python/ovs/flowviz/odp/cli.py
+++ b/python/ovs/flowviz/odp/cli.py
@@ -13,12 +13,12 @@
 # limitations under the License.
 
 import click
-
 from ovs.flowviz.main import maincli
+from ovs.flowviz.odp.tree import ConsoleTreeProcessor
 from ovs.flowviz.process import (
 DatapathFactory,
-JSONProcessor,
 ConsoleProcessor,
+JSONProcessor,
 )
 
 
@@ -65,3 +65,20 @@ def console(opts, heat_map):
 )
 proc.process()
 proc.print()
+
+
+@datapath.command()
+@click.option(
+"-h",
+"--heat-map",
+is_flag=True,
+default=False,
+show_default=True,
+help="Create heat-map with packet and byte counters",
+)
+@click.pass_obj
+def tree(opts, heat_map):
+"""Print the flows in a tree based on the 'recirc_id'."""
+processor = ConsoleTreeProcessor(opts)
+processor.process()
+processor.print(heat_map)
diff --git a/python/ovs/flowviz/odp/tree.py b/python/ovs/flowviz/odp/tree.py
new file mode 100644
index 0..d249e7d6d
--- /dev/null
+++ b/python/ovs/flowviz/odp/tree.py
@@ -0,0 +1,291 @@
+# Copyright (c) 2023 Red Hat, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from rich.style import Style
+from rich.text import Text
+from rich.tree import Tree
+
+from ovs.flowviz.console import (
+ConsoleFormatter,
+ConsoleBuffer,
+hash_pallete,
+heat_pallete,
+file_header,
+)
+from ovs.flowviz.process import (
+DatapathFactory,
+FileProcessor,
+)
+
+
+class TreeElem:
+"""Element in the tree.
+Args:
+children (list[TreeElem]): Optional, list of children
+is_root (bool): Optional; whether this is the root elemen
+