On 5/7/24 16:30, Adrian Moreno wrote:
> The goal of this utility is to read both datapath and Openflow flows
> (using the flow library already available) and print them in different
> formats and styles to make it easier to understand them and troubleshoot
> issues.
> 
> The formats are quite opinionated and so are the colors chosen so I'm
> eager to hear what is the impression caused to the community.
> 
> Here is a summary of the formats and features supported:
> 
> - Openflow
>    - Console: Prints flows back to the console allowing filtering and
>      extensive formatting.
>    - Cookie: Arranges flows based on cookie (instead of table) to ease
>      visualization of OVN-generated flows.
>    - HTML: Prints an HTML file that shows the flows arranged by tables.
>      resubmit actions have a hyperlinke to the target table to ease
>      navegation.
>    - Logic: Many times OVN generates many "logically-equivalent" flows.
>      These are flows that have the same structure: match on the same
>      values and have the same actions. The only thing that changes is
>      the actual value they match against and maybe the arguments of the
>      actions. This format collapses these flows so you can visualize the
>      logical pipeline easier.
>    - JSON: JSON format.
> 
> More OpenFlow features:
>    - OVN metadata: Both the "cookie" and the "logic" format allow to
>      connect to a running OVN NB/SB databases and enrich the flows with
>      OVN context based on the flow's cookie.
> 
> - Datapath:
>    - Console: Prints flows back to the console allowing filtering and
>      extensive formatting.
>    - Tree: Datapath flows use recirculation to further execute
>      additional actions. This format builds a tree of flows following
>      the recirculation identifiers and prints it in the console.
>    - HTML: Prints the datapath flow tree in HTML. It includes some
>      minimal JS to support expanding and collapsing of entire branches.
>    - Graph: Following the "tree" format, this one prints the tree in
>      graphviz format. 
>    - JSON: JSON format.
> 
> Additional datapath features:
>    - Many datapath formats are based on the tree flow hierarchy. An
>      interesting feature of this structure is that filtering is done at
>      the branch level. This means that when a flow satisfies the filter,
>      the entire sub-tree leading to that flow is shown.
> 
> Additional common features:
>    - Styling: Styles for both console and HTML formats can be defined
>      using a configuration file.
>    - Heat maps: Some formats support heat-maps. A color pallete ranging
>      from blue (cold) to red (hot) is used to print the number of
>      packets and bytes of the flows. That way, the flows that are
>      handling more traffic are much easier to spot
> 
> --
> V3 -> V4:
>  - Add manpage to rpm package
>  - Fix Eelco's comments
> V2 -> V3:
>  - Fix grammar thanks to Eelco's review
> V1 -> V2:
>  - Fix typos and nits on documentation
>  - Split documentation in two: ovs-flowviz.8 man page and a topic
>    article with more detailed examples.
> RFC -> V1:
>  - Addressed Eelco's comments
>  - Added a documentation page
>  - Added support for dark style HTML pages
>  - Patch 3. Small fix in the way a style is looked up. Use the key in
>    the KV instead of the metadata string. This helps with "free" values
>    such as "output".
> 
> Adrian Moreno (12):
>   python: ovs: Add flowviz scheleton.
>   python: ovs: flowviz: Add file processing infra.
>   python: ovs: flowviz: Add console formatting.
>   python: ovs: flowviz: Add default config file.
>   python: ovs: flowviz: Add html formatting.
>   python: ovs: flowviz: Add datapath tree format.
>   python: ovs: flowviz: Add OpenFlow logical view.
>   python: ovs: flowviz: Add Openflow cookie format.
>   python: ovs: flowviz: Add datapath html format.
>   python: ovs: flowviz: Add datapath graph format.
>   python: ovs: flowviz: Support html dark style.
>   documentation: Document ovs-flowviz.
> 
>  Documentation/automake.mk                   |   4 +-
>  Documentation/conf.py                       |   2 +
>  Documentation/ref/index.rst                 |   1 +
>  Documentation/ref/ovs-flowviz.8.rst         | 531 ++++++++++++++++++++
>  Documentation/topics/flow-visualization.rst | 271 ++++++++++
>  Documentation/topics/index.rst              |   1 +
>  python/automake.mk                          |  32 +-
>  python/ovs/flowviz/__init__.py              |   2 +
>  python/ovs/flowviz/console.py               | 196 ++++++++
>  python/ovs/flowviz/format.py                | 371 ++++++++++++++
>  python/ovs/flowviz/html_format.py           | 138 +++++
>  python/ovs/flowviz/main.py                  | 196 ++++++++
>  python/ovs/flowviz/odp/__init__.py          |   0
>  python/ovs/flowviz/odp/cli.py               | 116 +++++
>  python/ovs/flowviz/odp/graph.py             | 418 +++++++++++++++
>  python/ovs/flowviz/odp/html.py              | 279 ++++++++++
>  python/ovs/flowviz/odp/tree.py              | 303 +++++++++++
>  python/ovs/flowviz/ofp/__init__.py          |   0
>  python/ovs/flowviz/ofp/cli.py               | 246 +++++++++
>  python/ovs/flowviz/ofp/html.py              |  98 ++++
>  python/ovs/flowviz/ofp/logic.py             | 364 ++++++++++++++
>  python/ovs/flowviz/ovs-flowviz              |  20 +
>  python/ovs/flowviz/ovs-flowviz.conf         | 128 +++++
>  python/ovs/flowviz/process.py               | 263 ++++++++++
>  python/setup.py                             |  14 +-
>  rhel/openvswitch-fedora.spec.in             |   1 +
>  rhel/openvswitch.spec.in                    |   1 +
>  27 files changed, 3986 insertions(+), 10 deletions(-)
>  create mode 100644 Documentation/ref/ovs-flowviz.8.rst
>  create mode 100644 Documentation/topics/flow-visualization.rst
>  create mode 100644 python/ovs/flowviz/__init__.py
>  create mode 100644 python/ovs/flowviz/console.py
>  create mode 100644 python/ovs/flowviz/format.py
>  create mode 100644 python/ovs/flowviz/html_format.py
>  create mode 100644 python/ovs/flowviz/main.py
>  create mode 100644 python/ovs/flowviz/odp/__init__.py
>  create mode 100644 python/ovs/flowviz/odp/cli.py
>  create mode 100644 python/ovs/flowviz/odp/graph.py
>  create mode 100644 python/ovs/flowviz/odp/html.py
>  create mode 100644 python/ovs/flowviz/odp/tree.py
>  create mode 100644 python/ovs/flowviz/ofp/__init__.py
>  create mode 100644 python/ovs/flowviz/ofp/cli.py
>  create mode 100644 python/ovs/flowviz/ofp/html.py
>  create mode 100644 python/ovs/flowviz/ofp/logic.py
>  create mode 100755 python/ovs/flowviz/ovs-flowviz
>  create mode 100644 python/ovs/flowviz/ovs-flowviz.conf
>  create mode 100644 python/ovs/flowviz/process.py
> 

Hi, Adrian.  Thanks for v4!

Not a full review, but I was trying to use this version of flowviz today
on a real flow dump from an ovn-kubernetes cluster and it crashes unable
to parse check_pkt_len datapath actions:

# ovs-flowviz -i snippet1.txt datapath tree                                     

Traceback (most recent call last):                                              
                                                                                
             
  File "/python/ovs/flow/kv.py", line 294, in parse                             
             
    key, val = self._decoders.decode(keyword, value_str)                        
                                                                                
             
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^                        
                                                                                
             
  File "/python/ovs/flow/kv.py", line 150, in decode                            
             
    raise ParseError(                                                           
                                                                                
             
ovs.flow.kv.ParseError: Cannot parse key check_pkt_len: No decoder found        
                                                                                
             
                                                                                
                                                                                
             
The above exception was the direct cause of the following exception:            
                                                                                
             
                                                                                
                                                                                
             
Traceback (most recent call last):                                              
                                                                                
             
  File "/python/ovs/flow/kv.py", line 294, in parse                             
             
    key, val = self._decoders.decode(keyword, value_str)                        
                                                                                
             
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^                        
                                                                                
             
  File "/python/ovs/flow/kv.py", line 137, in decode                            
             
    result = decoder(value_str)                                                 
                                                                                
             
             ^^^^^^^^^^^^^^^^^^                                                 
                                                                                
             
  File "/python/ovs/flow/kv.py", line 347, in decode_nested_kv_list             
             
    parser.parse()                                                              
                                                                                
             
  File "/python/ovs/flow/kv.py", line 296, in parse                             
             
    raise ParseError(                                                           
                                                                                
             
ovs.flow.kv.ParseError: Error parsing key-value (check_pkt_len, 
size=8514,gt(sample(sample=100.0%,actions(meter(4),userspace(pid=4294967295,controller(reason=1,dont_send=0,c
ontinuation=0,recirc_id=33861757,rule_cookie=0x9ac6aa33,controller_id=0,max_len=65535))))),le(ct(zone=12,nat),recirc(0x204b07e)))
                                            
                                                                                
                                                                                
             
The above exception was the direct cause of the following exception:            
                                                                                
             
                                                                                
                                    
The above exception was the direct cause of the following exception:            
                                                                                
             
                                                                                
                                                                                
             
Traceback (most recent call last):                                              
                                                                                
             
  File "/python/ovs/flow/kv.py", line 294, in parse                             
             
    key, val = self._decoders.decode(keyword, value_str)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/python/ovs/flow/kv.py", line 137, in decode
    result = decoder(value_str)
             ^^^^^^^^^^^^^^^^^^
  File "/python/ovs/flow/kv.py", line 330, in decode_nested_kv
    parser.parse()
  File "/python/ovs/flow/kv.py", line 296, in parse
    raise ParseError(
ovs.flow.kv.ParseError: Error parsing key-value (le, 
set(eth(src=0a:0b:0c:0d:08:08,dst=aa:bb:cc:dd:ee:ff)),set(ipv4(ttl=62)),check_pkt_len(size=8514,gt(sample(sample=100.0%,
actions(meter(4),userspace(pid=4294967295,controller(reason=1,dont_send=0,continuation=0,recirc_id=33861757,rule_cookie=0x9ac6aa33,controller_id=0,max_len=65535))))),le(ct(z
one=12,nat),recirc(0x204b07e))))

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/venv/bin/ovs-flowviz", line 20, in <module>
    main.main()
  File "/python/ovs/flowviz/main.py", line 196, in main
    maincli()
  File "/venv/lib64/python3.12/site-packages/click/core.py", line 1157, in 
__call__
    return self.main(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib64/python3.12/site-packages/click/core.py", line 1078, in main
    rv = self.invoke(ctx)
         ^^^^^^^^^^^^^^^^
File "/venv/lib64/python3.12/site-packages/click/core.py", line 1688, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib64/python3.12/site-packages/click/core.py", line 1688, in 
invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib64/python3.12/site-packages/click/core.py", line 1434, in 
invoke
    return ctx.invoke(self.callback, **ctx.params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib64/python3.12/site-packages/click/core.py", line 783, in invoke
    return __callback(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib64/python3.12/site-packages/click/decorators.py", line 45, in 
new_func
    return f(get_current_context().obj, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/python/ovs/flowviz/odp/cli.py", line 85, in tree
    processor.process()
  File "/python/ovs/flowviz/odp/tree.py", line 233, in process
    super().process(False)
  File "/python/ovs/flowviz/process.py", line 113, in process
    flow = self.create_flow(line, idx)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/python/ovs/flowviz/process.py", line 158, in create_flow
    return ODPFlow(line, idx)
           ^^^^^^^^^^^^^^^^^^
  File "/python/ovs/flow/odp.py", line 153, in __init__
    aparser.parse()
  File "/python/ovs/flow/kv.py", line 296, in parse
    raise ParseError(
ovs.flow.kv.ParseError: Error parsing key-value (check_pkt_len, 
size=8514,gt(sample(sample=100.0%,actions(meter(4),userspace(pid=4294967295,controller(reason=1,dont_send=0,continuation=0,recirc_id=29551991,rule_cookie=0x769b5340,controller_id=0,max_len=65535))))),le(set(eth(src=0a:0b:0c:0d:08:08,dst=aa:bb:cc:dd:ee:ff)),set(ipv4(ttl=62)),check_pkt_len(size=8514,gt(sample(sample=100.0%,actions(meter(4),userspace(pid=4294967295,controller(reason=1,dont_send=0,continuation=0,recirc_id=33861757,rule_cookie=0x9ac6aa33,controller_id=0,max_len=65535))))),le(ct(zone=12,nat),recirc(0x204b07e)))))


Not the exact same line, but a similar crash happens while parsing:

recirc_id(0x204ae73),in_port(20),ct_state(+new-est-rel-rpl-inv+trk),ct_mark(0/0xffff000f),eth(src=1a:1b:1c:1d:18:18,dst=2a:2b:2c:2d:2e:2f),eth_type(0x0800),ipv4(src=192.168.10.1/255.255.255.254,dst=10.64.0.0/255.192.0.0,proto=6,ttl=64,frag=no),
 packets:7, bytes:518, used:9.077s, flags:S, 
actions:ct(commit,zone=269,mark=0/0x1,nat(src)),set(eth(src=3a:3b:3c:3d:3e:3f,dst=4a:4b:4c:4d:4e:4f)),set(ipv4(ttl=63)),check_pkt_len(size=8514,gt(sample(sample=100.0%,actions(meter(4),userspace(pid=4294967295,controller(reason=1,dont_send=0,continuation=0,recirc_id=29551991,rule_cookie=0x769b5340,controller_id=0,max_len=65535))))),le(set(eth(src=0a:0b:0c:0d:08:08,dst=aa:bb:cc:dd:ee:ff)),set(ipv4(ttl=62)),check_pkt_len(size=8514,gt(sample(sample=100.0%,actions(meter(4),userspace(pid=4294967295,controller(reason=1,dont_send=0,continuation=0,recirc_id=33861236,rule_cookie=0x9ac6aa33,controller_id=0,max_len=65535))))),le(ct(zone=12,nat),recirc(0x204ae75)))))

My guess is that it has some trouble with nested check_pkt_len.

Best regards, Ilya Maximets.
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to