mirror of
https://github.com/openvswitch/ovs
synced 2025-08-22 01:51:26 +00:00
documentation: Document ovs-flowviz.
Add a man page for ovs-flowviz as well as a topic page with some more detailed examples. Acked-by: Eelco Chaudron <echaudro@redhat.com> Signed-off-by: Adrian Moreno <amorenoz@redhat.com> Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
This commit is contained in:
parent
4214bf4b28
commit
e532f937f5
@ -45,7 +45,7 @@ DOC_SOURCE = \
|
||||
Documentation/topics/fuzzing/ovs-fuzzing-infrastructure.rst \
|
||||
Documentation/topics/fuzzing/ovs-fuzzers.rst \
|
||||
Documentation/topics/fuzzing/security-analysis-of-ovs-fuzzers.rst \
|
||||
Documentation/topics/testing.rst \
|
||||
Documentation/topics/flow-visualization.rst \
|
||||
Documentation/topics/integration.rst \
|
||||
Documentation/topics/language-bindings.rst \
|
||||
Documentation/topics/networking-namespaces.rst \
|
||||
@ -55,6 +55,7 @@ DOC_SOURCE = \
|
||||
Documentation/topics/ovsdb-replication.rst \
|
||||
Documentation/topics/porting.rst \
|
||||
Documentation/topics/record-replay.rst \
|
||||
Documentation/topics/testing.rst \
|
||||
Documentation/topics/tracing.rst \
|
||||
Documentation/topics/usdt-probes.rst \
|
||||
Documentation/topics/userspace-checksum-offloading.rst \
|
||||
@ -162,6 +163,7 @@ RST_MANPAGES = \
|
||||
ovs-actions.7.rst \
|
||||
ovs-appctl.8.rst \
|
||||
ovs-ctl.8.rst \
|
||||
ovs-flowviz.8.rst \
|
||||
ovs-l3ping.8.rst \
|
||||
ovs-parse-backtrace.8.rst \
|
||||
ovs-pki.8.rst \
|
||||
|
@ -112,6 +112,8 @@ html_static_path = ['_static']
|
||||
# Define the canonical URL for our domain configured on Read the Docs.
|
||||
html_baseurl = os.environ.get("READTHEDOCS_CANONICAL_URL", "")
|
||||
|
||||
option_emphasise_placeholders = True
|
||||
|
||||
# Tell Jinja2 templates the build is running on Read the Docs.
|
||||
html_context = {}
|
||||
if os.environ.get("READTHEDOCS", "") == "True":
|
||||
@ -128,6 +130,8 @@ _man_pages = [
|
||||
u'utility for configuring running Open vSwitch daemons'),
|
||||
('ovs-ctl.8',
|
||||
u'OVS startup helper script'),
|
||||
('ovs-flowviz.8',
|
||||
u'utility for visualizing OpenFlow and datapath flows'),
|
||||
('ovs-l3ping.8',
|
||||
u'check network deployment for L3 tunneling problems'),
|
||||
('ovs-parse-backtrace.8',
|
||||
|
@ -42,6 +42,7 @@ time:
|
||||
ovs-actions.7
|
||||
ovs-appctl.8
|
||||
ovs-ctl.8
|
||||
ovs-flowviz.8
|
||||
ovs-l3ping.8
|
||||
ovs-pki.8
|
||||
ovs-sim.1
|
||||
|
540
Documentation/ref/ovs-flowviz.8.rst
Normal file
540
Documentation/ref/ovs-flowviz.8.rst
Normal file
@ -0,0 +1,540 @@
|
||||
..
|
||||
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.
|
||||
|
||||
Convention for heading levels in Open vSwitch documentation:
|
||||
|
||||
======= Heading 0 (reserved for the title in a document)
|
||||
------- Heading 1
|
||||
~~~~~~~ Heading 2
|
||||
+++++++ Heading 3
|
||||
''''''' Heading 4
|
||||
|
||||
Avoid deeper levels because they do not render well.
|
||||
|
||||
===========
|
||||
ovs-flowviz
|
||||
===========
|
||||
|
||||
Synopsis
|
||||
========
|
||||
|
||||
``ovs-flowviz``
|
||||
[``-i`` [*alias*,]\ *file* | ``--input`` [*alias*,]\ *file*]
|
||||
[``-c`` *file* | ``--config`` *file*]
|
||||
[``-f`` *filter* | ``--filter`` *filter*]
|
||||
[``-h`` *filter* | ``--highlight`` *filter*]
|
||||
[``--style`` *style*]
|
||||
*flow-type* *format* [*args*...]
|
||||
|
||||
``ovs-flowviz --help``
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
``ovs-flowviz`` helps visualize OpenFlow and datapath flow dumps in different
|
||||
formats in order to make them more easily understood.
|
||||
|
||||
``ovs-flowviz`` reads flows from ``stdin`` or from a *file* specified by the
|
||||
``--input`` option, filters them, highlights them, and finally outputs
|
||||
them in one of the predefined *format*\ s.
|
||||
|
||||
|
||||
Options
|
||||
=======
|
||||
|
||||
.. program: ovs-flowviz
|
||||
|
||||
.. option:: -h, --help
|
||||
|
||||
Print a brief help message to the console.
|
||||
|
||||
.. option:: -i [<alias>,]<file>, --input [<alias>,]<file>
|
||||
|
||||
File to read flows from. If not provided, ``ovs-flowviz``
|
||||
will read flows from stdin.
|
||||
|
||||
This option can be specified multiple times.
|
||||
The file path can prepended by an alias that will be shown in the output.
|
||||
For example: ``--input node1,/path/to/file1 --input node2,/path/to/file2``
|
||||
|
||||
.. option:: -c <file>, --config <file>
|
||||
|
||||
Style configuration file to use, overriding the default one.
|
||||
Styles defined in the style configuration file can be selected using
|
||||
the ``--style`` option.
|
||||
|
||||
For more details on the style configuration file, see the
|
||||
`Style Configuration File`_ section below.
|
||||
|
||||
.. option:: -f <filter>, --filter <filter>
|
||||
|
||||
Flow filter expression. Only those flows matching the expression will be
|
||||
shown (although some formats implement filtering differently, see the
|
||||
`Datapath tree format`_ section below).
|
||||
|
||||
The filtering syntax is detailed in `Filtering Syntax`_.
|
||||
|
||||
.. option:: -h <filter>, --highlight <filter>
|
||||
|
||||
Highlight the flows that match the provided *filter* expression.
|
||||
|
||||
The filtering syntax is detailed in `Filtering Syntax`_.
|
||||
|
||||
.. option:: --style <style>
|
||||
|
||||
Style. The selected *style* must be defined in the style configuration file.
|
||||
|
||||
.. option:: flow-type
|
||||
|
||||
**openflow** or **datapath**.
|
||||
|
||||
.. option:: format
|
||||
|
||||
See the `Supported formats`_ section.
|
||||
|
||||
|
||||
Supported formats
|
||||
=================
|
||||
|
||||
``ovs-flowviz`` supports several visualization formats for both OpenFlow and
|
||||
datapath flows:
|
||||
|
||||
.. list-table::
|
||||
:widths: 20 10 70
|
||||
:align: center
|
||||
:header-rows: 1
|
||||
|
||||
* - Flow Type
|
||||
- Format
|
||||
- Description
|
||||
* - Both
|
||||
- console
|
||||
- Prints the flows in a configurable, colorful style in the console.
|
||||
* - Both
|
||||
- json
|
||||
- Prints the flows in JSON format.
|
||||
* - Both
|
||||
- html
|
||||
- Prints the flows in an HTML list.
|
||||
* - OpenFlow
|
||||
- cookie
|
||||
- Prints the flows in the console sorted by cookie.
|
||||
* - OpenFlow
|
||||
- logic
|
||||
- Prints the logical structure of flows in the console.
|
||||
* - Datapath
|
||||
- tree
|
||||
- Prints the flows as a tree structure arranged by ``recirc_id`` and
|
||||
``in_port``.
|
||||
* - Datapath
|
||||
- graph
|
||||
- Prints a graphviz graph of the flows arranged by ``recirc_id`` and
|
||||
``in_port``.
|
||||
|
||||
|
||||
Console format
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
The ``console`` format works for both OpenFlow and datapath flow types, and
|
||||
prints flows in the terminal using the style determined by the ``--style``
|
||||
option.
|
||||
|
||||
Arguments:
|
||||
|
||||
.. option:: -h, --heat-map
|
||||
|
||||
Color of the packet and byte counters to reflect their relative size.
|
||||
The color gradient goes through the following colors:
|
||||
blue (coldest, lowest), cyan, green, yellow, red (hottest, highest)
|
||||
|
||||
Note filtering is applied before the range is calculated.
|
||||
|
||||
|
||||
JSON format
|
||||
~~~~~~~~~~~
|
||||
|
||||
The ``json`` format works for both OpenFlow and datapath flow types, and prints
|
||||
flows in JSON format. See the `JSON Syntax`_ section for more details.
|
||||
|
||||
|
||||
HTML format
|
||||
~~~~~~~~~~~
|
||||
|
||||
The ``html`` format works for both OpenFlow and datapath flows, and prints
|
||||
flows in an HTML table that offers some basic interactivity. OpenFlow flows
|
||||
are sorted in tables and datapath flows are arranged in flow trees
|
||||
(see `Datapath tree format`_ for more details).
|
||||
|
||||
Styles defined via Style Configuration File and selected via ``--style`` option
|
||||
also apply to the ``html`` format.
|
||||
|
||||
|
||||
OpenFlow cookie format
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The OpenFlow ``cookie`` format is similar to the ``console`` format but
|
||||
instead of arranging the flows by table, it arranges the flows by cookie.
|
||||
|
||||
|
||||
OpenFlow logic format
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The OpenFlow ``logic`` format helps visualize the logic structure of OpenFlow
|
||||
pipelines by arranging flows into *logical blocks*.
|
||||
A logical block is a set of flows that have:
|
||||
|
||||
* Same ``priority``.
|
||||
* Match on the same fields (regardless of the match value and mask).
|
||||
* Execute the same actions (regardless of the actions' arguments,
|
||||
except for resubmit and output).
|
||||
* Optionally, the ``cookie`` can be included as part of the logical flow.
|
||||
|
||||
Arguments:
|
||||
|
||||
.. option:: -s, --show-flows
|
||||
|
||||
Show all the flows under each logical block.
|
||||
|
||||
.. option:: -d, --ovn-detrace
|
||||
|
||||
Use ovn-detrace.py script to extract cookie information (implies '-c').
|
||||
|
||||
.. option:: -c, --cookie
|
||||
|
||||
Consider the cookie in the logical block.
|
||||
|
||||
.. option:: --ovn-detrace-path <path>
|
||||
|
||||
Use an alternative path to search for ovn_detrace.py.
|
||||
|
||||
.. option:: --ovnnb-db <conn>
|
||||
|
||||
OVN NB database connection method (implies '-d').
|
||||
Default: "unix:/var/run/ovn/ovnnb_db.sock".
|
||||
|
||||
.. option:: --ovnsb-db <conn>
|
||||
|
||||
OVN SB database connection method (implies '-d').
|
||||
Default: "unix:/var/run/ovn/ovnsb_db.sock".
|
||||
|
||||
.. option:: --o <filter>, --ovn-filter <filter>
|
||||
|
||||
Specify the filter to be run on the ovn-detrace information.
|
||||
Syntax: python regular expression
|
||||
(See https://docs.python.org/3/library/re.html).
|
||||
|
||||
.. option:: -h, --heat-map
|
||||
|
||||
Change the color of the packet and byte counters to reflect their relative
|
||||
size. The color gradient goes through the following colors:
|
||||
blue (coldest, lowest), cyan, green, yellow, red (hottest, highest)
|
||||
|
||||
Note filtering is applied before the range is calculated.
|
||||
|
||||
|
||||
Datapath tree format
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The datapath ``tree`` format arranges datapath flows in a hierarchical tree.
|
||||
The tree is comprised of blocks with the same ``recirc_id`` and ``in_port``.
|
||||
Within those blocks, flows with the same action are combined. And matches
|
||||
which are the same are omitted to reduce the visual noise.
|
||||
|
||||
When a flow's actions includes the ``recirc()`` action with a specific
|
||||
``recirc_id``, flows matching on that ``recirc_id`` and the same ``in_port``
|
||||
are listed below. This is done recursively for all actions.
|
||||
|
||||
The result is a hierarchical representation that shows how actions are related
|
||||
to each other via recirculation. Note that flows with a specific non-zero
|
||||
``recirc_id`` are listed below each group of flows that have a corresponding
|
||||
``recirc()`` action. Therefore, the output contains duplicated flows and can be
|
||||
verbose.
|
||||
|
||||
Filtering works in a slightly different way for datapath flow trees.
|
||||
Unlike other formats where a filter simply removes non-matching flows,
|
||||
the output of a filtered datapath flow tree will show full sub-trees
|
||||
that contain at least one flow that satisfies the filter.
|
||||
|
||||
The ``html`` format prints this same tree as an interactive HTML table and
|
||||
the ``graph`` format shows the same tree as a graphviz graph.
|
||||
|
||||
|
||||
Datapath graph format
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The datapath ``graph`` generates a graphviz visual representation of the
|
||||
same tree-like flow hierarchy that the ``tree`` format prints.
|
||||
|
||||
Arguments:
|
||||
|
||||
.. option:: -h, --html
|
||||
|
||||
Print the graphviz format as an svg image alongside an interactive HTML
|
||||
table of flows.
|
||||
|
||||
|
||||
JSON Syntax
|
||||
===========
|
||||
|
||||
Printing a single-file OpenFlow or datapath dump without PMD thread blocks in
|
||||
``json`` format results in a list of JSON objects, each representing a flow.
|
||||
|
||||
This list can be found inside one or more levels of JSON dictionaries
|
||||
if multiple files are processed (filename used as key) or if PMD thread blocks
|
||||
are found in datapath flows (name of the thread used as key).
|
||||
|
||||
Each flow object includes the following keys:
|
||||
|
||||
**orig**
|
||||
Original flow string.
|
||||
|
||||
|
||||
**info**
|
||||
Object with the flow information such as: cookie, duration, table,
|
||||
n_packets, n_bytes, etc.
|
||||
|
||||
|
||||
**match**
|
||||
Object with the flow match.
|
||||
For each match, the object contains a key-value where the key is the name
|
||||
of the match as defined in ``ovs-fields(7)`` and ``ovs-ofctl(8)``, and the
|
||||
value represents the match value. The way each value is represented depends
|
||||
on its type. See `Value representation`_.
|
||||
|
||||
|
||||
**actions**
|
||||
List of action objects.
|
||||
Each action is represented by an JSON object that has one key and one value.
|
||||
The key corresponds to the action name. The value represents the arguments
|
||||
of the key. See `Action representation`_.
|
||||
|
||||
|
||||
**ufid**
|
||||
The UFID (datapath flows only).
|
||||
|
||||
|
||||
Value representation
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Values are represented differently depending on their type:
|
||||
|
||||
* Flags: The value of flags is ``true``.
|
||||
|
||||
* Decimal / Hexadecimal: Represented by their integer value.
|
||||
If they support masking, represented by a dictionary with two keys:
|
||||
``value`` contains the field value and ``mask`` contains the mask.
|
||||
Both are integers.
|
||||
|
||||
* Ethernet: Represented by a string: ``{address}[/{mask}]``
|
||||
|
||||
* IPv4 / IPv6: Represented by a string ``{address}[/{mask}]``
|
||||
|
||||
* Registers: Represented by a dictionary with three keys:
|
||||
``field``` contains the field value (string), ``start``, and ``end``
|
||||
represent the first and last bit of the register value.
|
||||
|
||||
For example, the register
|
||||
::
|
||||
|
||||
|
||||
NXM_NX_REG10[0..15]
|
||||
|
||||
|
||||
is represented as
|
||||
::
|
||||
|
||||
|
||||
{
|
||||
"field": "NXM_NX_REG10",
|
||||
"start": 0,
|
||||
"end": 15
|
||||
},
|
||||
|
||||
|
||||
Action representation
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Actions are generally represented by an object that has a single key and
|
||||
value. The key is the action name as defined ``ovs-actions(7)``.
|
||||
|
||||
The value of actions that have no arguments (such as ``drop``) is
|
||||
(boolean) ``true``.
|
||||
|
||||
The value of actions that have a list of arguments (e.g:
|
||||
``resubmit([port],[table],[ct])``) is an object that has the name of the
|
||||
argument as key. The argument names for each action is defined in
|
||||
ovs-actions. For example, the action
|
||||
::
|
||||
|
||||
resubmit(,10)
|
||||
|
||||
is represented as
|
||||
::
|
||||
|
||||
{
|
||||
"resubmit": {
|
||||
"port": "",
|
||||
"table": 10
|
||||
}
|
||||
}
|
||||
|
||||
The value of actions that have a key-word list as arguments
|
||||
(e.g: ``ct([argument])``) is an object whose keys correspond to the keys
|
||||
defined in ``ovs-actions(7)``. The way values are represented depends
|
||||
on the type of the argument.
|
||||
For example, the action
|
||||
::
|
||||
|
||||
ct(table=14,zone=NXM_NX_REG12[0..15],nat)
|
||||
|
||||
is represented as
|
||||
::
|
||||
|
||||
{
|
||||
"ct": {
|
||||
"table": 14,
|
||||
"zone": {
|
||||
"field": "NXM_NX_REG12",
|
||||
"start": 0,
|
||||
"end": 15
|
||||
},
|
||||
"nat": true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Style Configuration File
|
||||
========================
|
||||
|
||||
The style configuration file is selected via the ``--config`` option
|
||||
and has INI syntax. It can define any number of styles to be used by both
|
||||
``console`` and ``html`` formats. Once defined in the configuration file,
|
||||
formats are selected using the ``--style`` option.
|
||||
|
||||
INI sections are used to define styles, ``[styles.mystyle]`` defines a style
|
||||
called `mystle`. Within a section styles can be defined as:
|
||||
|
||||
::
|
||||
|
||||
[FORMAT].[PORTION].[SELECTOR].[ELEMENT] = [VALUE]
|
||||
|
||||
|
||||
**FORMAT**
|
||||
Either ``console`` or ``html``
|
||||
|
||||
**PORTION**
|
||||
Part of the key-value the style applies to:
|
||||
``key`` to indicate the key part of a key-value, ``value`` to indicate
|
||||
the value part of a key-value, ``flag`` to indicate a single flag
|
||||
or ``delim`` to indicate delimiters such as parentheses, brackets, etc.
|
||||
|
||||
**SELECTOR**
|
||||
Select the key-value the style applies to:
|
||||
``highlighted`` to indicate highlighted key-values, ``type.<type>``
|
||||
to indicate certain types such as ``IPAddress`` or ``EthMask`` or
|
||||
``<keyname>`` to select a particular key name.
|
||||
|
||||
**ELEMENT**
|
||||
Select the style element to modify:
|
||||
**color** or **underline** (only for ``console`` format).
|
||||
|
||||
**VALUE**
|
||||
Ether a color hex, other color names defined in the rich python
|
||||
library (https://rich.readthedocs.io/en/stable/appendix/colors.html) or
|
||||
**true** if the element is ``underline``.
|
||||
|
||||
A default configuration file is shipped with ``ovs-flowviz`` and its path is
|
||||
printed in the ``--help`` output. A detailed description of the syntax
|
||||
alongside some examples are available there.
|
||||
|
||||
|
||||
Filtering syntax
|
||||
================
|
||||
|
||||
``ovs-flowviz`` provides rich highlighting and filtering. The special command
|
||||
``ovs-flowviz filter`` dumps the filtering syntax:
|
||||
|
||||
::
|
||||
|
||||
$ ovs-flowviz filter
|
||||
Filter Syntax
|
||||
*************
|
||||
|
||||
[! | not ] {key}[[.subkey]...] [OPERATOR] {value})] [LOGICAL OPERATOR] ...
|
||||
|
||||
Comparison operators:
|
||||
= equality
|
||||
< less than
|
||||
> more than
|
||||
~= masking (valid for IP and Ethernet fields)
|
||||
|
||||
Logical operators:
|
||||
!{expr}: NOT
|
||||
{expr} && {expr}: AND
|
||||
{expr} || {expr}: OR
|
||||
|
||||
Matches and flow metadata:
|
||||
To compare against a match or info field, use the field directly, e.g:
|
||||
priority=100
|
||||
n_bytes>10
|
||||
Use simple keywords for flags:
|
||||
tcp and ip_src=192.168.1.1
|
||||
|
||||
Actions:
|
||||
Actions values might be dictionaries, use subkeys to access individual
|
||||
values, e.g:
|
||||
output.port=3
|
||||
Use simple keywords for flags
|
||||
drop
|
||||
|
||||
Examples of valid filters:
|
||||
nw_addr~=192.168.1.1 && (tcp_dst=80 || tcp_dst=443)
|
||||
arp=true && !arp_tsa=192.168.1.1
|
||||
n_bytes>0 && drop=true
|
||||
|
||||
|
||||
Example expressions:
|
||||
::
|
||||
|
||||
n_bytes > 0 and drop
|
||||
nw_src~=192.168.1.1 or arp.tsa=192.168.1.1
|
||||
! tcp && output.port=2
|
||||
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
Print OpenFlow flows sorted by cookie adding OVN data to each one:
|
||||
::
|
||||
|
||||
$ ovs-flowviz -i flows.txt openflow cookie --ovn-detrace
|
||||
|
||||
Print OpenFlow logical structure, showing the flows and heat-map:
|
||||
::
|
||||
|
||||
$ ovs-flowviz -i flows.txt openflow logic --show-flows --heat-map
|
||||
|
||||
Display OpenFlow flows in HTML format with "light" style and highlight drops:
|
||||
::
|
||||
|
||||
$ ovs-flowviz -i flows.txt --style "light" --highlight "n_packets > 0 and drop" openflow html > flows.html
|
||||
|
||||
Display the datapath flows in an interactive graphviz + HTML view:
|
||||
::
|
||||
|
||||
$ ovs-flowviz -i flows.txt datapath graph --html > flows.html
|
||||
|
||||
Display the datapath flow trees that lead to packets being sent to port 10:
|
||||
::
|
||||
|
||||
$ ovs-flowviz -i flows.txt --filter "output.port=10" datapath tree
|
313
Documentation/topics/flow-visualization.rst
Normal file
313
Documentation/topics/flow-visualization.rst
Normal file
@ -0,0 +1,313 @@
|
||||
..
|
||||
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.
|
||||
|
||||
Convention for heading levels in Open vSwitch documentation:
|
||||
|
||||
======= Heading 0 (reserved for the title in a document)
|
||||
------- Heading 1
|
||||
~~~~~~~ Heading 2
|
||||
+++++++ Heading 3
|
||||
''''''' Heading 4
|
||||
|
||||
Avoid deeper levels because they do not render well.
|
||||
|
||||
==================================
|
||||
Visualizing flows with ovs-flowviz
|
||||
==================================
|
||||
|
||||
When troubleshooting networking issues with OVS, it's common to end up looking
|
||||
at OpenFlow or datapath flow dumps. These dumps tend to be quite dense and
|
||||
difficult to reason about.
|
||||
|
||||
``ovs-flowviz`` is a utility script that helps visualizing OpenFlow and
|
||||
datapath flows to make it easier to understand what is going on.
|
||||
|
||||
The `ovs-flowviz(8)`_ manpage describes its basic usage. In this document a few
|
||||
of its advanced visualization formats will be expanded.
|
||||
|
||||
|
||||
Installing ovs-flowviz
|
||||
----------------------
|
||||
|
||||
``ovs-flowviz`` is part of the openvswitch python package but its
|
||||
extra dependencies have to be installed explicitly by running:
|
||||
::
|
||||
|
||||
$ pip install openvswitch[flowviz]
|
||||
|
||||
Or, if you are working with the OVS tree:
|
||||
::
|
||||
|
||||
$ cd python && pip install .[flowviz]
|
||||
|
||||
Visualizing OpenFlow logical block
|
||||
----------------------------------
|
||||
|
||||
When controllers such as OVN write OpenFlow flows, they typically organize
|
||||
flows in functional blocks. These blocks can expand to multiple flows that
|
||||
"look similar", in the sense that they match on the same fields and have
|
||||
similar actions.
|
||||
|
||||
However, looking at a flow dump the number of flows can make it difficult
|
||||
to perceive this logical functionality that the controller is trying to
|
||||
implement using OpenFlow.
|
||||
|
||||
``ovs-flowviz openflow logic`` visualization can be used to understand an OVN
|
||||
flow dump a bit better.
|
||||
|
||||
On a particular flow dump table 0 contains 23 flows:
|
||||
::
|
||||
|
||||
$ grep -c "table=0" flows.txt
|
||||
23
|
||||
|
||||
Looking at the first few lines, the amount of information can be
|
||||
overwhelming and difficult our analysis:
|
||||
|
||||
::
|
||||
|
||||
$ head flows.txt
|
||||
cookie=0xf76b4b20, duration=765.107s, table=0, n_packets=0, n_bytes=0, priority=180,vlan_tci=0x0000/0x1000 actions=conjunction(100,2/2)
|
||||
cookie=0xf76b4b20, duration=765.107s, table=0, n_packets=0, n_bytes=0, priority=180,conj_id=100,in_port="patch-br-int-to",vlan_tci=0x0000/0x1000 actions=load:0xa->NXM_NX_REG13[],load:0xc->NXM_NX_REG11[],load:0xb->NXM_NX_REG12[],load:0xb->OXM_OF_METADATA[],load:0x1->NXM_NX_REG14[],mod_dl_src:02:42:ac:12:00:03,resubmit(,8)
|
||||
cookie=0x0, duration=765.388s, table=0, n_packets=0, n_bytes=0, priority=100,in_port="ovn-6bb3b3-0" actions=move:NXM_NX_TUN_ID[0..23]->OXM_OF_METADATA[0..23],move:NXM_NX_TUN_METADATA0[16..30]->NXM_NX_REG14[0..14],move:NXM_NX_TUN_METADATA0[0..15]->NXM_NX_REG15[0..15],resubmit(,40)
|
||||
cookie=0x0, duration=765.388s, table=0, n_packets=0, n_bytes=0, priority=100,in_port="ovn-a6ff98-0" actions=move:NXM_NX_TUN_ID[0..23]->OXM_OF_METADATA[0..23],move:NXM_NX_TUN_METADATA0[16..30]->NXM_NX_REG14[0..14],move:NXM_NX_TUN_METADATA0[0..15]->NXM_NX_REG15[0..15],resubmit(,40)
|
||||
cookie=0xf2ca6195, duration=765.107s, table=0, n_packets=6, n_bytes=636, priority=100,in_port="ovn-k8s-mp0" actions=load:0x1->NXM_NX_REG13[],load:0x2->NXM_NX_REG11[],load:0x7->NXM_NX_REG12[],load:0x4->OXM_OF_METADATA[],load:0x2->NXM_NX_REG14[],resubmit(,8)
|
||||
cookie=0x236e941d, duration=408.874s, table=0, n_packets=11, n_bytes=846, priority=100,in_port=aceac9829941d11 actions=load:0x11->NXM_NX_REG13[],load:0x2->NXM_NX_REG11[],load:0x7->NXM_NX_REG12[],load:0x4->OXM_OF_METADATA[],load:0x3->NXM_NX_REG14[],resubmit(,8)
|
||||
cookie=0x3facf689, duration=405.581s, table=0, n_packets=11, n_bytes=846, priority=100,in_port="363ba22029cd92b" actions=load:0x12->NXM_NX_REG13[],load:0x2->NXM_NX_REG11[],load:0x7->NXM_NX_REG12[],load:0x4->OXM_OF_METADATA[],load:0x4->NXM_NX_REG14[],resubmit(,8)
|
||||
cookie=0xe7c8c4bb, duration=405.570s, table=0, n_packets=11, n_bytes=846, priority=100,in_port="6a62cde0d50ef44" actions=load:0x13->NXM_NX_REG13[],load:0x2->NXM_NX_REG11[],load:0x7->NXM_NX_REG12[],load:0x4->OXM_OF_METADATA[],load:0x5->NXM_NX_REG14[],resubmit(,8)
|
||||
cookie=0x99a0ffc1, duration=59.391s, table=0, n_packets=8, n_bytes=636, priority=100,in_port="5ff3bfaaa4eb622" actions=load:0x14->NXM_NX_REG13[],load:0x2->NXM_NX_REG11[],load:0x7->NXM_NX_REG12[],load:0x4->OXM_OF_METADATA[],load:0x6->NXM_NX_REG14[],resubmit(,8)
|
||||
cookie=0xe1b5c263, duration=59.365s, table=0, n_packets=8, n_bytes=636, priority=100,in_port="8d9e0bc76347e59" actions=load:0x15->NXM_NX_REG13[],load:0x2->NXM_NX_REG11[],load:0x7->NXM_NX_REG12[],load:0x4->OXM_OF_METADATA[],load:0x7->NXM_NX_REG14[],resubmit(,8)
|
||||
|
||||
|
||||
However, table 0 can be better understood by looking at its logical
|
||||
representation:
|
||||
::
|
||||
|
||||
$ ovs-flowviz -i flows.txt -f "table=0" openflow logic
|
||||
Ofproto Flows (logical)
|
||||
└── ** TABLE 0 **
|
||||
├── priority=180 priority,vlan_tci ---> conjunction ( x 1 )
|
||||
├── priority=180 priority,conj_id,in_port,vlan_tci ---> load,load,load,load,load,mod_dl_src resubmit(,8), ( x 1 )
|
||||
├── priority=100 priority,in_port ---> move,move,move resubmit(,40), ( x 2 )
|
||||
├── priority=100 priority,in_port ---> load,load,load,load,load resubmit(,8), ( x 16 )
|
||||
├── priority=100 priority,in_port,vlan_tci ---> load,load,load,load,load resubmit(,8), ( x 1 )
|
||||
├── priority=100 priority,in_port,dl_vlan ---> strip_vlan,load,load,load,load,load resubmit(,8), ( x 1 )
|
||||
└── priority=0 priority ---> drop, ( x 1 )
|
||||
|
||||
|
||||
In only a few logical blocks, there is a good overview of what this table is
|
||||
doing. It looks like it's adding metadata based on input ports and vlan
|
||||
IDs and mainly sending traffic to table 8.
|
||||
|
||||
A possible next step might be to look at table 8, and in this case, filter out
|
||||
the flows that have not been hit by actual traffic.
|
||||
This is quite easy to do with the arithmetic filtering expressions:
|
||||
::
|
||||
|
||||
$ ovs-flowviz -i flows.txt -f "table=8 and n_packets>0" openflow logic
|
||||
|
||||
Ofproto Flows (logical)
|
||||
└── ** TABLE 8 **
|
||||
├── priority=50 priority,reg14,metadata,dl_dst ---> load resubmit(,9), ( x 3 )
|
||||
└── priority=50 priority,metadata ---> load,move resubmit(,73),resubmit(,9), ( x 2 )
|
||||
|
||||
At this point, understanding the output might be difficult without relating it
|
||||
to the matadata OVN stored in the previous table. This is where
|
||||
``ovs-flowviz``'s OVN integration is useful:
|
||||
::
|
||||
|
||||
$ export OVN_NB_DB=tcp:172.18.0.4:6641
|
||||
$ export OVN_SB_DB=tcp:172.18.0.4:6642
|
||||
$ ovs-flowviz -i flows.txt -f "table=8 and n_packets>0" openflow logic --ovn-detrace
|
||||
Ofproto Flows (logical)
|
||||
└── ** TABLE 8 **
|
||||
├── cookie=0xe10c34ee priority=50 priority,reg14,metadata,dl_dst ---> load resubmit(,9), ( x 1 )
|
||||
│ └── OVN Info
|
||||
│ ├── * Logical datapaths:
|
||||
│ ├── * "ovn_cluster_router" (366e1c41-0f3d-4420-b796-10692b64e3e4)
|
||||
│ ├── * Logical flow: table=0 (lr_in_admission), priority=50, match=(eth.mcast && inport == "rtos-ovn-worker2), actions=(xreg0[0..47] = 0a:58:0a:f4:01:01; next;)
|
||||
│ └── * Logical Router Port: rtos-ovn-worker2 mac 0a:58:0a:f4:01:01 networks ['10.244.1.1/24'] ipv6_ra_configs {}
|
||||
├── cookie=0x11e1adbc priority=50 priority,reg14,metadata,dl_dst ---> load resubmit(,9), ( x 1 )
|
||||
│ └── OVN Info
|
||||
│ ├── * Logical datapaths:
|
||||
│ ├── * "GR_ovn-worker2" (c07f8387-6479-4e81-9304-9f8e54f81c56)
|
||||
│ ├── * Logical flow: table=0 (lr_in_admission), priority=50, match=(eth.mcast && inport == "rtoe-GR_ovn-worker2), actions=(xreg0[0..47] = 02:42:ac:12:00:03; next;)
|
||||
│ └── * Logical Router Port: rtoe-GR_ovn-worker2 mac 02:42:ac:12:00:03 networks ['172.18.0.3/16'] ipv6_ra_configs {}
|
||||
├── cookie=0xf42133f priority=50 priority,reg14,metadata,dl_dst ---> load resubmit(,9), ( x 1 )
|
||||
│ └── OVN Info
|
||||
│ ├── * Logical datapaths:
|
||||
│ ├── * "GR_ovn-worker2" (c07f8387-6479-4e81-9304-9f8e54f81c56)
|
||||
│ ├── * Logical flow: table=0 (lr_in_admission), priority=50, match=(eth.dst == 02:42:ac:12:00:03 && inport == "rtoe-GR_ovn-worker2), actions=(xreg0[0..47] = 02:42:ac:12:00:03; next;)
|
||||
│ └── * Logical Router Port: rtoe-GR_ovn-worker2 mac 02:42:ac:12:00:03 networks ['172.18.0.3/16'] ipv6_ra_configs {}
|
||||
└── cookie=0x43a0327 priority=50 priority,metadata ---> load,move resubmit(,73),resubmit(,9), ( x 2 )
|
||||
└── OVN Info
|
||||
├── * Logical datapaths:
|
||||
├── * "ovn-worker" (24280d0b-fee0-4f8e-ba4f-036a9b9af921)
|
||||
├── * "ovn-control-plane" (3262a782-8961-416b-805e-08233e8fda72)
|
||||
├── * "ext_ovn-worker2" (3f88dcd2-c56d-478f-a3b1-c7aee2efe967)
|
||||
├── * "ext_ovn-worker" (5facbaf0-485d-4cf5-8940-eff9678ef7bb)
|
||||
├── * "ext_ovn-control-plane" (8b0aecb6-b05a-48a7-ad09-72524bb91d40)
|
||||
├── * "join" (e2dc230e-2f2a-4b93-93fa-0fe495163514)
|
||||
├── * "ovn-worker2" (f7709fbf-d728-4cff-9b9b-150461cc75d2)
|
||||
└── * Logical flow: table=0 (ls_in_check_port_sec), priority=50, match=(1), actions=(reg0[15] = check_in_port_sec(); next;)
|
||||
|
||||
``ovs-flowviz`` has automatically added the `cookie` to the logical block key
|
||||
so more blocks have been printed. In exchange, it has looked up each cookie on
|
||||
the running OVN databases and inserted the known information on each
|
||||
block.
|
||||
|
||||
The logical flow that generated each OpenFlow flow and the logical datapath
|
||||
it belongs to are now printed, making OVN's pipeline clearer.
|
||||
|
||||
Visualizing datapath flow trees
|
||||
-------------------------------
|
||||
|
||||
Another typical usecase that can lead to eyestrain is understanding datapath
|
||||
conntrack recirculations.
|
||||
|
||||
OVS makes heavy use of connection tracking and the ``recirc()`` action
|
||||
to build complex datapaths. Typically, OVS will insert a flow that,
|
||||
when matched, will send the packet through conntrack (using the ``ct`` action)
|
||||
and recirculate it with a particular recirculation id (``recirc_id``). Then,
|
||||
flows matching on that ``recirc_id`` will be matched and further process the
|
||||
packet. This can happen more than once for a given packet.
|
||||
|
||||
This sequential set of events is, however, difficult to visualize when you
|
||||
look at a datapath flow dump. Flows are unordered so recirculations need to
|
||||
be followed manually (typically, with heavy use of "grep").
|
||||
|
||||
For this use-case, ``ovs-flowviz datapath tree`` format can be extremely
|
||||
useful. It builds a hierarchical tree based on the ``recirc_id``, ``in_port``
|
||||
and ``recirc()`` actions.
|
||||
|
||||
Furthermore, it is common to end up with multiple flows that have the same
|
||||
list of actions. An example of this is a number flows that perform mac/vlan
|
||||
checks for a given port and send the traffic though the same conntrack zone.
|
||||
In order to better visualize this and reduce the amount of duplicated flows
|
||||
that are printed in this view, these flows are combined into a block, and the
|
||||
match keys that are equal for all flows are removed.
|
||||
|
||||
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 │
|
||||
│ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
|
||||
|
||||
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
|
||||
addresses and protocols, and send traffic through conntrack (zone 32).
|
||||
|
||||
Then some additional flows at ``recirc_id(0xc1)`` process each
|
||||
connection independently. One of them, shown in the example, sends packets
|
||||
through conntrack zone 14, and after another recirculation the packet is
|
||||
ultimately sent through a port.
|
||||
|
||||
This is a truly complex multi-zone conntrack pipeline that is now significantly
|
||||
clearer thanks to this visualization.
|
||||
|
||||
Also note, the flows in the block are conveniently sorted by sent packets.
|
||||
|
||||
This example shows only a single "subtree". Even though the combination of
|
||||
flows with the same action helps, if we use this command to display a large
|
||||
dump, the output can be verbose. There are two, combinable, mechanisms that
|
||||
can help.
|
||||
|
||||
|
||||
Plotting datapath trees
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
By using the ``ovs-flowviz datapath html`` format, long datapath trees can
|
||||
be displayed in an interactive HTML table. The resulting web page allows
|
||||
subtrees to be expanded and collapsed, allowing focus on the desired
|
||||
information.
|
||||
|
||||
The ``ovs-flowviz datapath graph`` format generates a graphviz
|
||||
graph definition where blocks of flows with the same ``recirc_id`` match
|
||||
are arranged together, and edges are created to represent recirculations.
|
||||
This format comes with further features such as displaying the conntrack
|
||||
zones, which are key to understanding what the datapath is really doing with a
|
||||
packet.
|
||||
|
||||
The ``html`` and ``graph`` can also be combined.
|
||||
``ovs-flowviz datapath graph --html`` command will output an interactive
|
||||
HTML table alongside a SVG graphical representation of the flows. Flows in the
|
||||
SVG representation link to the corresponding entry in the HTML table.
|
||||
|
||||
|
||||
Filtering
|
||||
~~~~~~~~~
|
||||
|
||||
As well as allowing expanding and collapsing subtrees, filtering can be used.
|
||||
|
||||
However, filtering works in a slightly different way than it does with OpenFlow
|
||||
flows. Instead of just removing non-matching flows, the output of a filtered
|
||||
datapath flow tree will show full sub-trees containing at least one flow that
|
||||
satisfies the filter.
|
||||
|
||||
For example, the following command allows understanding the flows in the above
|
||||
example in the context of traffic going out on port ``ovn-k8s-mp0``:
|
||||
::
|
||||
|
||||
$ ovs-appctl dpctl/dump-flows | ovs-flowviz -f "output.port=ovn-k8s-mp0" datapath tree
|
||||
|
||||
The resulting flow tree will contain all of the flows above, including those
|
||||
with ``recirc_id(0)`` and ``recirc_id(0xc1)`` that don't actually output
|
||||
traffic to port ``ovn-k8s-mp0``. This is because they are part of a subtree
|
||||
that contains flows that output packets on port ``ovn-k8s-mp0``
|
||||
|
||||
This provides a "full picture" of how traffic, ending up in a particular
|
||||
port, is being processed.
|
||||
|
||||
.. _ovs-flowviz(8): https://docs.openvswitch.org/en/latest/ref/ovs-flowviz.8
|
@ -58,3 +58,4 @@ OVS
|
||||
userspace-checksum-offloading
|
||||
userspace-tx-steering
|
||||
usdt-probes
|
||||
flow-visualization
|
||||
|
4
NEWS
4
NEWS
@ -5,6 +5,10 @@ Post-v3.4.0
|
||||
that does not have a specific value defined, rather than being
|
||||
treated as a global value, aligning the behavior with that of
|
||||
the kernel datapath.
|
||||
- Python:
|
||||
* Added tool called "ovs-flowviz" capable of parsing OpenFlow
|
||||
and datapath flow dumps and displaying them in several different
|
||||
formats.
|
||||
|
||||
|
||||
v3.4.0 - 15 Aug 2024
|
||||
|
@ -500,6 +500,7 @@ fi
|
||||
%{_mandir}/man8/ovs-ctl.8*
|
||||
%{_mandir}/man8/ovs-dpctl.8*
|
||||
%{_mandir}/man8/ovs-dpctl-top.8*
|
||||
%{_mandir}/man8/ovs-flowviz.8*
|
||||
%{_mandir}/man8/ovs-kmod-ctl.8*
|
||||
%{_mandir}/man8/ovs-ofctl.8*
|
||||
%{_mandir}/man8/ovs-pki.8*
|
||||
|
@ -223,6 +223,7 @@ exit 0
|
||||
/usr/share/man/man8/ovs-ctl.8.gz
|
||||
/usr/share/man/man8/ovs-dpctl.8.gz
|
||||
/usr/share/man/man8/ovs-dpctl-top.8.gz
|
||||
/usr/share/man/man8/ovs-flowviz.8.gz
|
||||
/usr/share/man/man8/ovs-kmod-ctl.8.gz
|
||||
/usr/share/man/man8/ovs-ofctl.8.gz
|
||||
/usr/share/man/man8/ovs-parse-backtrace.8.gz
|
||||
|
Loading…
x
Reference in New Issue
Block a user