mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-04-29 12:18:12 +00:00
doc: minor update based on mininet removal
Signed-off-by: Christian Hopps <chopps@labn.net>
This commit is contained in:
parent
351bc82cac
commit
77f3acb45e
@ -12,8 +12,8 @@ Installing Dependencies
|
|||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt-get install \
|
sudo apt-get install \
|
||||||
git autoconf automake libtool make libreadline-dev texinfo \
|
git autoconf automake libtool make libreadline-dev texinfo \
|
||||||
pkg-config libpam0g-dev libjson-c-dev bison flex python3-pytest \
|
pkg-config libpam0g-dev libjson-c-dev bison flex \
|
||||||
libc-ares-dev python3-dev python-ipaddress python3-sphinx \
|
libc-ares-dev python3-dev python3-sphinx \
|
||||||
install-info build-essential libsnmp-dev perl libcap-dev \
|
install-info build-essential libsnmp-dev perl libcap-dev \
|
||||||
libelf-dev
|
libelf-dev
|
||||||
|
|
||||||
|
@ -12,8 +12,8 @@ Installing Dependencies
|
|||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt-get install \
|
sudo apt-get install \
|
||||||
git autoconf automake libtool make libreadline-dev texinfo \
|
git autoconf automake libtool make libreadline-dev texinfo \
|
||||||
pkg-config libpam0g-dev libjson-c-dev bison flex python3-pytest \
|
pkg-config libpam0g-dev libjson-c-dev bison flex \
|
||||||
libc-ares-dev python3-dev python-ipaddress python3-sphinx \
|
libc-ares-dev python3-dev python3-sphinx \
|
||||||
install-info build-essential libsnmp-dev perl \
|
install-info build-essential libsnmp-dev perl \
|
||||||
libcap-dev python2 libelf-dev
|
libcap-dev python2 libelf-dev
|
||||||
|
|
||||||
|
@ -373,23 +373,18 @@ Building topology and configurations
|
|||||||
Topology and initial configuration will be created in setup_module(). Following
|
Topology and initial configuration will be created in setup_module(). Following
|
||||||
is the sample code::
|
is the sample code::
|
||||||
|
|
||||||
class TemplateTopo(Topo):
|
|
||||||
def build(self, *_args, **_opts):
|
|
||||||
"Build function"
|
|
||||||
tgen = get_topogen(self)
|
|
||||||
|
|
||||||
# Building topology from json file
|
|
||||||
build_topo_from_json(tgen, topo)
|
|
||||||
|
|
||||||
def setup_module(mod):
|
def setup_module(mod):
|
||||||
tgen = Topogen(TemplateTopo, mod.__name__)
|
json_file = "{}/my_test_name.json".format(CWD)
|
||||||
|
tgen = Topogen(json_file, mod.__name__)
|
||||||
|
|
||||||
|
# json topo object is now available in tgen.json_topo
|
||||||
|
|
||||||
# Starting topology, create tmp files which are loaded to routers
|
# Starting topology, create tmp files which are loaded to routers
|
||||||
# to start deamons and then start routers
|
# to start deamons and then start routers
|
||||||
start_topology(tgen)
|
start_topology(tgen)
|
||||||
|
|
||||||
# Creating configuration from JSON
|
# Creating configuration from JSON
|
||||||
build_config_from_json(tgen, topo)
|
build_config_from_json(tgen)
|
||||||
|
|
||||||
def teardown_module(mod):
|
def teardown_module(mod):
|
||||||
tgen = get_topogen()
|
tgen = get_topogen()
|
||||||
@ -412,10 +407,12 @@ configurations are like, static routes, prefixlists and route maps etc configs,
|
|||||||
these configs can be used by any other protocols as it is.
|
these configs can be used by any other protocols as it is.
|
||||||
BGP config will be specific to BGP protocol testing.
|
BGP config will be specific to BGP protocol testing.
|
||||||
|
|
||||||
* JSON file is passed to API build_config_from_json(), which looks for
|
* json file is passed to API Topogen() which saves the JSON object in
|
||||||
configuration tags in JSON file.
|
`self.json_topo`
|
||||||
* If tag is found in JSON, configuration is created as per input and written
|
* The Topogen object is then passed to API build_config_from_json(), which looks
|
||||||
to file frr_json.conf
|
for configuration tags in new JSON object.
|
||||||
|
* If tag is found in the JSON object, configuration is created as per input and
|
||||||
|
written to file frr_json.conf
|
||||||
* Once JSON parsing is over, frr_json.conf is loaded onto respective router.
|
* Once JSON parsing is over, frr_json.conf is loaded onto respective router.
|
||||||
Config loading is done using 'vtysh -f <file>'. Initial config at this point
|
Config loading is done using 'vtysh -f <file>'. Initial config at this point
|
||||||
is also saved frr_json_initial.conf. This file can be used to reset
|
is also saved frr_json_initial.conf. This file can be used to reset
|
||||||
@ -428,10 +425,10 @@ Writing Tests
|
|||||||
"""""""""""""
|
"""""""""""""
|
||||||
|
|
||||||
Test topologies should always be bootstrapped from the
|
Test topologies should always be bootstrapped from the
|
||||||
example-test/test_example.py, because it contains important boilerplate code
|
example_test/test_template_json.py, because it contains important boilerplate
|
||||||
that can't be avoided, like:
|
code that can't be avoided, like:
|
||||||
|
|
||||||
imports: os, sys, pytest, topotest/topogen and mininet topology class
|
imports: os, sys, pytest, and topotest/topogen.
|
||||||
|
|
||||||
The global variable CWD (Current Working directory): which is most likely going
|
The global variable CWD (Current Working directory): which is most likely going
|
||||||
to be used to reference the routers configuration file location
|
to be used to reference the routers configuration file location
|
||||||
|
@ -3,32 +3,37 @@
|
|||||||
Topotests
|
Topotests
|
||||||
=========
|
=========
|
||||||
|
|
||||||
Topotests is a suite of topology tests for FRR built on top of Mininet.
|
Topotests is a suite of topology tests for FRR built on top of micronet.
|
||||||
|
|
||||||
Installation and Setup
|
Installation and Setup
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
Only tested with Ubuntu 16.04 and Ubuntu 18.04 (which uses Mininet 2.2.x).
|
Topotests run under python3. Additionally, for ExaBGP (which is used in some of
|
||||||
|
the BGP tests) an older python2 version must be installed.
|
||||||
|
|
||||||
|
Tested with Ubuntu 20.04 and Ubuntu 18.04 and Debian 11.
|
||||||
|
|
||||||
Instructions are the same for all setups (i.e. ExaBGP is only used for BGP
|
Instructions are the same for all setups (i.e. ExaBGP is only used for BGP
|
||||||
tests).
|
tests).
|
||||||
|
|
||||||
Installing Mininet Infrastructure
|
Installing Topotest Requirements
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
.. code:: shell
|
.. code:: shell
|
||||||
|
|
||||||
apt-get install mininet
|
apt-get install iproute2
|
||||||
apt-get install python-pip
|
apt-get install net-tools
|
||||||
apt-get install iproute
|
apt-get install python3-pip
|
||||||
apt-get install iperf
|
python3 -m pip install wheel
|
||||||
pip install ipaddr
|
python3 -m pip install 'pytest>=6.2.4'
|
||||||
pip install "pytest<5"
|
python3 -m pip install 'pytest-xdist>=2.3.0'
|
||||||
pip install "scapy>=2.4.2"
|
python3 -m pip install 'scapy>=2.4.5'
|
||||||
pip install exabgp==3.4.17 (Newer 4.0 version of exabgp is not yet
|
python3 -m pip install xmltodict
|
||||||
supported)
|
# Use python2 pip to install older ExaBGP
|
||||||
|
python2 -m pip install 'exabgp<4.0.0'
|
||||||
useradd -d /var/run/exabgp/ -s /bin/false exabgp
|
useradd -d /var/run/exabgp/ -s /bin/false exabgp
|
||||||
|
|
||||||
|
|
||||||
Enable Coredumps
|
Enable Coredumps
|
||||||
""""""""""""""""
|
""""""""""""""""
|
||||||
|
|
||||||
@ -125,20 +130,125 @@ And create ``frr`` user and ``frrvty`` group as follows:
|
|||||||
Executing Tests
|
Executing Tests
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
Execute all tests with output to console
|
Execute all tests in distributed test mode
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
.. code:: shell
|
.. code:: shell
|
||||||
|
|
||||||
py.test -s -v --tb=no
|
py.test -s -v -nauto --dist=loadfile
|
||||||
|
|
||||||
The above command must be executed from inside the topotests directory.
|
The above command must be executed from inside the topotests directory.
|
||||||
|
|
||||||
All test\_\* scripts in subdirectories are detected and executed (unless
|
All test\_\* scripts in subdirectories are detected and executed (unless
|
||||||
disabled in ``pytest.ini`` file).
|
disabled in ``pytest.ini`` file). Pytest will execute up to N tests in parallel
|
||||||
|
where N is based on the number of cores on the host.
|
||||||
|
|
||||||
|
Analyze Test Results (``analyze.py``)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
By default router and execution logs are saved in ``/tmp/topotests`` and an XML
|
||||||
|
results file is saved in ``/tmp/topotests.xml``. An analysis tool ``analyze.py``
|
||||||
|
is provided to archive and analyze these results after the run completes.
|
||||||
|
|
||||||
|
After the test run completes one should pick an archive directory to store the
|
||||||
|
results in and pass this value to ``analyze.py``. On first execution the results
|
||||||
|
are copied to that directory from ``/tmp``, and subsequent runs use that
|
||||||
|
directory for analyzing the results. Below is an example of this which also
|
||||||
|
shows the default behavior which is to display all failed and errored tests in
|
||||||
|
the run.
|
||||||
|
|
||||||
|
.. code:: shell
|
||||||
|
|
||||||
|
~/frr/tests/topotests# ./analyze.py -Ar run-save
|
||||||
|
bgp_multiview_topo1/test_bgp_multiview_topo1.py::test_bgp_converge
|
||||||
|
ospf_basic_functionality/test_ospf_lan.py::test_ospf_lan_tc1_p0
|
||||||
|
bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py::test_BGP_GR_10_p2
|
||||||
|
bgp_multiview_topo1/test_bgp_multiview_topo1.py::test_bgp_routingTable
|
||||||
|
|
||||||
|
Here we see that 4 tests have failed. We an dig deeper by displaying the
|
||||||
|
captured logs and errors. First let's redisplay the results enumerated by adding
|
||||||
|
the ``-E`` flag
|
||||||
|
|
||||||
|
.. code:: shell
|
||||||
|
|
||||||
|
~/frr/tests/topotests# ./analyze.py -Ar run-save -E
|
||||||
|
0 bgp_multiview_topo1/test_bgp_multiview_topo1.py::test_bgp_converge
|
||||||
|
1 ospf_basic_functionality/test_ospf_lan.py::test_ospf_lan_tc1_p0
|
||||||
|
2 bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py::test_BGP_GR_10_p2
|
||||||
|
3 bgp_multiview_topo1/test_bgp_multiview_topo1.py::test_bgp_routingTable
|
||||||
|
|
||||||
|
Now to look at the error message for a failed test we use ``-T N`` where N is
|
||||||
|
the number of the test we are interested in along with ``--errmsg`` option.
|
||||||
|
|
||||||
|
.. code:: shell
|
||||||
|
|
||||||
|
~/frr/tests/topotests# ./analyze.py -Ar run-save -T0 --errmsg
|
||||||
|
bgp_multiview_topo1/test_bgp_multiview_topo1.py::test_bgp_converge: AssertionError: BGP did not converge:
|
||||||
|
|
||||||
|
IPv4 Unicast Summary (VIEW 1):
|
||||||
|
BGP router identifier 172.30.1.1, local AS number 100 vrf-id -1
|
||||||
|
BGP table version 1
|
||||||
|
RIB entries 1, using 184 bytes of memory
|
||||||
|
Peers 3, using 2169 KiB of memory
|
||||||
|
|
||||||
|
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt Desc
|
||||||
|
172.16.1.1 4 65001 0 0 0 0 0 never Connect 0 N/A
|
||||||
|
172.16.1.2 4 65002 0 0 0 0 0 never Connect 0 N/A
|
||||||
|
172.16.1.5 4 65005 0 0 0 0 0 never Connect 0 N/A
|
||||||
|
|
||||||
|
Total number of neighbors 3
|
||||||
|
|
||||||
|
assert False
|
||||||
|
|
||||||
|
Now to look at the full text of the error for a failed test we use ``-T N``
|
||||||
|
where N is the number of the test we are interested in along with ``--errtext``
|
||||||
|
option.
|
||||||
|
|
||||||
|
.. code:: shell
|
||||||
|
|
||||||
|
~/frr/tests/topotests# ./analyze.py -Ar run-save -T0 --errtext
|
||||||
|
bgp_multiview_topo1/test_bgp_multiview_topo1.py::test_bgp_converge: def test_bgp_converge():
|
||||||
|
"Check for BGP converged on all peers and BGP views"
|
||||||
|
|
||||||
|
global fatal_error
|
||||||
|
global net
|
||||||
|
[...]
|
||||||
|
else:
|
||||||
|
# Bail out with error if a router fails to converge
|
||||||
|
bgpStatus = net["r%s" % i].cmd('vtysh -c "show ip bgp view %s summary"' % view)
|
||||||
|
> assert False, "BGP did not converge:\n%s" % bgpStatus
|
||||||
|
E AssertionError: BGP did not converge:
|
||||||
|
E
|
||||||
|
E IPv4 Unicast Summary (VIEW 1):
|
||||||
|
E BGP router identifier 172.30.1.1, local AS number 100 vrf-id -1
|
||||||
|
[...]
|
||||||
|
E Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt Desc
|
||||||
|
E 172.16.1.1 4 65001 0 0 0 0 0 never Connect 0 N/A
|
||||||
|
E 172.16.1.2 4 65002 0 0 0 0 0 never Connect 0 N/A
|
||||||
|
[...]
|
||||||
|
|
||||||
|
To look at the full capture for a test including the stdout and stderr which
|
||||||
|
includes full debug logs, just use the ``-T N`` option without the ``--errmsg``
|
||||||
|
or ``--errtext`` options.
|
||||||
|
|
||||||
|
.. code:: shell
|
||||||
|
|
||||||
|
~/frr/tests/topotests# ./analyze.py -Ar run-save -T0
|
||||||
|
@classname: bgp_multiview_topo1.test_bgp_multiview_topo1
|
||||||
|
@name: test_bgp_converge
|
||||||
|
@time: 141.401
|
||||||
|
@message: AssertionError: BGP did not converge:
|
||||||
|
[...]
|
||||||
|
system-out: --------------------------------- Captured Log ---------------------------------
|
||||||
|
2021-08-09 02:55:06,581 DEBUG: lib.micronet_compat.topo: Topo(unnamed): Creating
|
||||||
|
2021-08-09 02:55:06,581 DEBUG: lib.micronet_compat.topo: Topo(unnamed): addHost r1
|
||||||
|
[...]
|
||||||
|
2021-08-09 02:57:16,932 DEBUG: topolog.r1: LinuxNamespace(r1): cmd_status("['/bin/bash', '-c', 'vtysh -c "show ip bgp view 1 summary" 2> /dev/null | grep ^[0-9] | grep -vP " 11\\s+(\\d+)"']", kwargs: {'encoding': 'utf-8', 'stdout': -1, 'stderr': -2, 'shell': False})
|
||||||
|
2021-08-09 02:57:22,290 DEBUG: topolog.r1: LinuxNamespace(r1): cmd_status("['/bin/bash', '-c', 'vtysh -c "show ip bgp view 1 summary" 2> /dev/null | grep ^[0-9] | grep -vP " 11\\s+(\\d+)"']", kwargs: {'encoding': 'utf-8', 'stdout': -1, 'stderr': -2, 'shell': False})
|
||||||
|
2021-08-09 02:57:27,636 DEBUG: topolog.r1: LinuxNamespace(r1): cmd_status("['/bin/bash', '-c', 'vtysh -c "show ip bgp view 1 summary"']", kwargs: {'encoding': 'utf-8', 'stdout': -1, 'stderr': -2, 'shell': False})
|
||||||
|
--------------------------------- Captured Out ---------------------------------
|
||||||
|
system-err: --------------------------------- Captured Err ---------------------------------
|
||||||
|
|
||||||
``--tb=no`` disables the python traceback which might be irrelevant unless the
|
|
||||||
test script itself is debugged.
|
|
||||||
|
|
||||||
Execute single test
|
Execute single test
|
||||||
^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^
|
||||||
@ -161,9 +271,6 @@ Test will set exit code which can be used with ``git bisect``.
|
|||||||
|
|
||||||
For the simulated topology, see the description in the python file.
|
For the simulated topology, see the description in the python file.
|
||||||
|
|
||||||
If you need to clear the mininet setup between tests (if it isn't cleanly
|
|
||||||
shutdown), then use the ``mn -c`` command to clean up the environment.
|
|
||||||
|
|
||||||
StdErr log from daemos after exit
|
StdErr log from daemos after exit
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
@ -235,18 +342,64 @@ and create ``frr`` user and ``frrvty`` group as shown above.
|
|||||||
Debugging Topotest Failures
|
Debugging Topotest Failures
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
For the below debugging options which launch programs, if the topotest is run
|
Install and run tests inside ``tmux`` or ``byobu`` for best results.
|
||||||
within screen_ or tmux_, ``gdb``, the shell or ``vtysh`` will be launched using
|
|
||||||
that windowing program, otherwise mininet's ``xterm`` functionality will be used
|
|
||||||
to launch the given program.
|
|
||||||
|
|
||||||
If you wish to force the use of ``xterm`` rather than ``tmux`` or ``screen``, or
|
``XTerm`` is also fully supported. GNU ``screen`` can be used in most
|
||||||
wish to use ``gnome-terminal`` instead of ``xterm``, set the environment
|
situations; however, it does not work as well with launching ``vtysh`` or shell
|
||||||
variable ``FRR_TOPO_TERMINAL`` to either ``xterm`` or ``gnome-terminal``.
|
on error.
|
||||||
|
|
||||||
|
For the below debugging options which launch programs or CLIs, topotest should
|
||||||
|
be run within ``tmux`` (or ``screen``)_, as ``gdb``, the shell or ``vtysh`` will
|
||||||
|
be launched using that windowing program, otherwise ``xterm`` will be attempted
|
||||||
|
to launch the given programs.
|
||||||
|
|
||||||
.. _screen: https://www.gnu.org/software/screen/
|
.. _screen: https://www.gnu.org/software/screen/
|
||||||
.. _tmux: https://github.com/tmux/tmux/wiki
|
.. _tmux: https://github.com/tmux/tmux/wiki
|
||||||
|
|
||||||
|
Spawning Debugging CLI, ``vtysh`` or Shells on Routers on Test Failure
|
||||||
|
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||||
|
|
||||||
|
One can have a debugging CLI invoked on test failures by specifying the
|
||||||
|
``--cli-on-error`` CLI option as shown in the example below.
|
||||||
|
|
||||||
|
.. code:: shell
|
||||||
|
|
||||||
|
pytest --cli-on-error all-protocol-startup
|
||||||
|
|
||||||
|
The debugging CLI can run shell or vtysh commands on any combination of routers
|
||||||
|
It can also open shells or vtysh in their own windows for any combination of
|
||||||
|
routers. This is usually the most useful option when debugging failures. Here is
|
||||||
|
the help command from within a CLI launched on error:
|
||||||
|
|
||||||
|
.. code:: shell
|
||||||
|
|
||||||
|
test_bgp_multiview_topo1/test_bgp_routingTable> help
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
help :: this help
|
||||||
|
sh [hosts] <shell-command> :: execute <shell-command> on <host>
|
||||||
|
term [hosts] :: open shell terminals for hosts
|
||||||
|
vtysh [hosts] :: open vtysh terminals for hosts
|
||||||
|
[hosts] <vtysh-command> :: execute vtysh-command on hosts
|
||||||
|
|
||||||
|
test_bgp_multiview_topo1/test_bgp_routingTable> r1 show int br
|
||||||
|
------ Host: r1 ------
|
||||||
|
Interface Status VRF Addresses
|
||||||
|
--------- ------ --- ---------
|
||||||
|
erspan0 down default
|
||||||
|
gre0 down default
|
||||||
|
gretap0 down default
|
||||||
|
lo up default
|
||||||
|
r1-eth0 up default 172.16.1.254/24
|
||||||
|
r1-stub up default 172.20.0.1/28
|
||||||
|
|
||||||
|
----------------------
|
||||||
|
test_bgp_multiview_topo1/test_bgp_routingTable>
|
||||||
|
|
||||||
|
Additionally, one can have ``vtysh`` or a shell launched on all routers when a
|
||||||
|
test fails. To launch the given process on each router after a test failure
|
||||||
|
specify one of ``--shell-on-error`` or ``--vtysh-on-error``.
|
||||||
|
|
||||||
Spawning ``vtysh`` or Shells on Routers
|
Spawning ``vtysh`` or Shells on Routers
|
||||||
"""""""""""""""""""""""""""""""""""""""
|
"""""""""""""""""""""""""""""""""""""""
|
||||||
|
|
||||||
@ -255,8 +408,8 @@ a test. This is enabled by specifying 1 of 2 CLI arguments ``--shell`` or
|
|||||||
``--vtysh``. Both of these options can be set to a single router value, multiple
|
``--vtysh``. Both of these options can be set to a single router value, multiple
|
||||||
comma-seperated values, or ``all``.
|
comma-seperated values, or ``all``.
|
||||||
|
|
||||||
When either of these options are specified topotest will pause after each test
|
When either of these options are specified topotest will pause after setup and
|
||||||
to allow for inspection of the router state.
|
each test to allow for inspection of the router state.
|
||||||
|
|
||||||
Here's an example of launching ``vtysh`` on routers ``rt1`` and ``rt2``.
|
Here's an example of launching ``vtysh`` on routers ``rt1`` and ``rt2``.
|
||||||
|
|
||||||
@ -264,29 +417,6 @@ Here's an example of launching ``vtysh`` on routers ``rt1`` and ``rt2``.
|
|||||||
|
|
||||||
pytest --vtysh=rt1,rt2 all-protocol-startup
|
pytest --vtysh=rt1,rt2 all-protocol-startup
|
||||||
|
|
||||||
Spawning Mininet CLI, ``vtysh`` or Shells on Routers on Test Failure
|
|
||||||
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
|
||||||
|
|
||||||
Similar to the previous section one can have ``vtysh`` or a shell launched on
|
|
||||||
routers, but in this case only when a test fails. To launch the given process on
|
|
||||||
each router after a test failure specify one of ``--shell-on-error`` or
|
|
||||||
``--vtysh-on-error``.
|
|
||||||
|
|
||||||
|
|
||||||
Here's an example of having ``vtysh`` launched on test failure.
|
|
||||||
|
|
||||||
.. code:: shell
|
|
||||||
|
|
||||||
pytest --vtysh-on-error all-protocol-startup
|
|
||||||
|
|
||||||
|
|
||||||
Additionally, one can have the mininet CLI invoked on test failures by
|
|
||||||
specifying the ``--mininet-on-error`` CLI option as shown in the example below.
|
|
||||||
|
|
||||||
.. code:: shell
|
|
||||||
|
|
||||||
pytest --mininet-on-error all-protocol-startup
|
|
||||||
|
|
||||||
Debugging with GDB
|
Debugging with GDB
|
||||||
""""""""""""""""""
|
""""""""""""""""""
|
||||||
|
|
||||||
@ -424,7 +554,7 @@ top level directory of topotest:
|
|||||||
|
|
||||||
$ # Change to the top level directory of topotests.
|
$ # Change to the top level directory of topotests.
|
||||||
$ cd path/to/topotests
|
$ cd path/to/topotests
|
||||||
$ # Tests must be run as root, since Mininet requires it.
|
$ # Tests must be run as root, since micronet requires it.
|
||||||
$ sudo pytest
|
$ sudo pytest
|
||||||
|
|
||||||
In order to run a specific test, you can use the following command:
|
In order to run a specific test, you can use the following command:
|
||||||
@ -493,15 +623,16 @@ Some things to keep in mind:
|
|||||||
- Avoid including unstable data in your test: don't rely on link-local
|
- Avoid including unstable data in your test: don't rely on link-local
|
||||||
addresses or ifindex values, for example, because these can change
|
addresses or ifindex values, for example, because these can change
|
||||||
from run to run.
|
from run to run.
|
||||||
- Using sleep is almost never appropriate to wait for some convergence
|
- Using sleep is almost never appropriate. As an example: if the test resets the
|
||||||
event as the sole item done. As an example: if the test resets the peers
|
peers in BGP, the test should look for the peers re-converging instead of just
|
||||||
in BGP, the test should look for the peers reconverging instead of just
|
sleeping an arbitrary amount of time and continuing on. See
|
||||||
sleeping an arbitrary amount of time and continuing on. It is ok to
|
`verify_bgp_convergence` as a good example of this. In particular look at it's
|
||||||
use sleep in a tight loop with appropriate show commands to ensure that
|
use of the `@retry` decorator. If you are having troubles figuring out what to
|
||||||
the protocol reaches the desired state. This should be bounded by
|
look for, please do not be afraid to ask.
|
||||||
appropriate timeouts for the protocol in question though. See
|
- Don't duplicate effort. There exists many protocol utility functions that can
|
||||||
verify_bgp_convergence as a good example of this. If you are having
|
be found in their eponymous module under `tests/topotests/lib/` (e.g.,
|
||||||
troubles figuring out what to look for, please do not be afraid to ask.
|
`ospf.py`)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Topotest File Hierarchy
|
Topotest File Hierarchy
|
||||||
@ -661,25 +792,32 @@ Here is the template topology described in the previous section in python code:
|
|||||||
|
|
||||||
.. code:: py
|
.. code:: py
|
||||||
|
|
||||||
class TemplateTopo(Topo):
|
topodef = {
|
||||||
"Test topology builder"
|
"s1": "r1"
|
||||||
def build(self, *_args, **_opts):
|
"s2": ("r1", "r2")
|
||||||
"Build function"
|
}
|
||||||
tgen = get_topogen(self)
|
|
||||||
|
|
||||||
# Create 2 routers
|
If more specialized topology definitions, or router initialization arguments are
|
||||||
for routern in range(1, 3):
|
required a build function can be used instead of a dictionary:
|
||||||
tgen.add_router('r{}'.format(routern))
|
|
||||||
|
|
||||||
# Create a switch with just one router connected to it to simulate a
|
.. code:: py
|
||||||
# empty network.
|
|
||||||
switch = tgen.add_switch('s1')
|
|
||||||
switch.add_link(tgen.gears['r1'])
|
|
||||||
|
|
||||||
# Create a connection between r1 and r2
|
def build_topo(tgen):
|
||||||
switch = tgen.add_switch('s2')
|
"Build function"
|
||||||
switch.add_link(tgen.gears['r1'])
|
|
||||||
switch.add_link(tgen.gears['r2'])
|
# Create 2 routers
|
||||||
|
for routern in range(1, 3):
|
||||||
|
tgen.add_router("r{}".format(routern))
|
||||||
|
|
||||||
|
# Create a switch with just one router connected to it to simulate a
|
||||||
|
# empty network.
|
||||||
|
switch = tgen.add_switch("s1")
|
||||||
|
switch.add_link(tgen.gears["r1"])
|
||||||
|
|
||||||
|
# Create a connection between r1 and r2
|
||||||
|
switch = tgen.add_switch("s2")
|
||||||
|
switch.add_link(tgen.gears["r1"])
|
||||||
|
switch.add_link(tgen.gears["r2"])
|
||||||
|
|
||||||
- Run the topology
|
- Run the topology
|
||||||
|
|
||||||
@ -701,8 +839,8 @@ Parameters explanation:
|
|||||||
|
|
||||||
.. option:: -s
|
.. option:: -s
|
||||||
|
|
||||||
Actives input/output capture. This is required by mininet in order to show
|
Actives input/output capture. If this is not specified a new window will be
|
||||||
the interactive shell.
|
opened for the interactive CLI, otherwise it will be activated inline.
|
||||||
|
|
||||||
.. option:: --topology-only
|
.. option:: --topology-only
|
||||||
|
|
||||||
@ -713,110 +851,84 @@ output:
|
|||||||
|
|
||||||
.. code:: shell
|
.. code:: shell
|
||||||
|
|
||||||
=== test session starts ===
|
frr/tests/topotests# sudo pytest -s --topology-only ospf_topo1/test_ospf_topo1.py
|
||||||
platform linux2 -- Python 2.7.12, pytest-3.1.2, py-1.4.34, pluggy-0.4.0
|
============================= test session starts ==============================
|
||||||
rootdir: /media/sf_src/topotests, inifile: pytest.ini
|
platform linux -- Python 3.9.2, pytest-6.2.4, py-1.10.0, pluggy-0.13.1
|
||||||
collected 3 items
|
rootdir: /home/chopps/w/frr/tests/topotests, configfile: pytest.ini
|
||||||
|
plugins: forked-1.3.0, xdist-2.3.0
|
||||||
|
collected 11 items
|
||||||
|
|
||||||
ospf-topo1/test_ospf_topo1.py *** Starting controller
|
[...]
|
||||||
|
unet>
|
||||||
|
|
||||||
*** Starting 6 switches
|
The last line shows us that we are now using the CLI (Command Line
|
||||||
switch1 switch2 switch3 switch4 switch5 switch6 ...
|
|
||||||
r2: frr zebra started
|
|
||||||
r2: frr ospfd started
|
|
||||||
r3: frr zebra started
|
|
||||||
r3: frr ospfd started
|
|
||||||
r1: frr zebra started
|
|
||||||
r1: frr ospfd started
|
|
||||||
r4: frr zebra started
|
|
||||||
r4: frr ospfd started
|
|
||||||
*** Starting CLI:
|
|
||||||
mininet>
|
|
||||||
|
|
||||||
The last line shows us that we are now using the Mininet CLI (Command Line
|
|
||||||
Interface), from here you can call your router ``vtysh`` or even bash.
|
Interface), from here you can call your router ``vtysh`` or even bash.
|
||||||
|
|
||||||
|
Here's the help text:
|
||||||
|
|
||||||
|
.. code:: shell
|
||||||
|
unet> help
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
help :: this help
|
||||||
|
sh [hosts] <shell-command> :: execute <shell-command> on <host>
|
||||||
|
term [hosts] :: open shell terminals for hosts
|
||||||
|
vtysh [hosts] :: open vtysh terminals for hosts
|
||||||
|
[hosts] <vtysh-command> :: execute vtysh-command on hosts
|
||||||
|
|
||||||
|
.. code:: shell
|
||||||
|
|
||||||
Here are some commands example:
|
Here are some commands example:
|
||||||
|
|
||||||
.. code:: shell
|
.. code:: shell
|
||||||
|
|
||||||
mininet> r1 ping 10.0.3.1
|
unet> sh r1 ping 10.0.3.1
|
||||||
PING 10.0.3.1 (10.0.3.1) 56(84) bytes of data.
|
PING 10.0.3.1 (10.0.3.1) 56(84) bytes of data.
|
||||||
64 bytes from 10.0.3.1: icmp_seq=1 ttl=64 time=0.576 ms
|
64 bytes from 10.0.3.1: icmp_seq=1 ttl=64 time=0.576 ms
|
||||||
64 bytes from 10.0.3.1: icmp_seq=2 ttl=64 time=0.083 ms
|
64 bytes from 10.0.3.1: icmp_seq=2 ttl=64 time=0.083 ms
|
||||||
64 bytes from 10.0.3.1: icmp_seq=3 ttl=64 time=0.088 ms
|
64 bytes from 10.0.3.1: icmp_seq=3 ttl=64 time=0.088 ms
|
||||||
^C
|
^C
|
||||||
--- 10.0.3.1 ping statistics ---
|
--- 10.0.3.1 ping statistics ---
|
||||||
3 packets transmitted, 3 received, 0% packet loss, time 1998ms
|
3 packets transmitted, 3 received, 0% packet loss, time 1998ms
|
||||||
rtt min/avg/max/mdev = 0.083/0.249/0.576/0.231 ms
|
rtt min/avg/max/mdev = 0.083/0.249/0.576/0.231 ms
|
||||||
|
|
||||||
|
unet> r1 show run
|
||||||
|
Building configuration...
|
||||||
|
|
||||||
|
Current configuration:
|
||||||
|
!
|
||||||
|
frr version 8.1-dev-my-manual-build
|
||||||
|
frr defaults traditional
|
||||||
|
hostname r1
|
||||||
|
log file /tmp/topotests/ospf_topo1.test_ospf_topo1/r1/zebra.log
|
||||||
|
[...]
|
||||||
|
end
|
||||||
|
|
||||||
mininet> r1 ping 10.0.3.3
|
unet> show daemons
|
||||||
PING 10.0.3.3 (10.0.3.3) 56(84) bytes of data.
|
------ Host: r1 ------
|
||||||
64 bytes from 10.0.3.3: icmp_seq=1 ttl=64 time=2.87 ms
|
zebra ospfd ospf6d staticd
|
||||||
64 bytes from 10.0.3.3: icmp_seq=2 ttl=64 time=0.080 ms
|
------- End: r1 ------
|
||||||
64 bytes from 10.0.3.3: icmp_seq=3 ttl=64 time=0.091 ms
|
------ Host: r2 ------
|
||||||
^C
|
zebra ospfd ospf6d staticd
|
||||||
--- 10.0.3.3 ping statistics ---
|
------- End: r2 ------
|
||||||
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
|
------ Host: r3 ------
|
||||||
rtt min/avg/max/mdev = 0.080/1.014/2.872/1.313 ms
|
zebra ospfd ospf6d staticd
|
||||||
|
------- End: r3 ------
|
||||||
|
------ Host: r4 ------
|
||||||
|
zebra ospfd ospf6d staticd
|
||||||
mininet> r3 vtysh
|
------- End: r4 ------
|
||||||
|
|
||||||
Hello, this is FRRouting (version 3.1-devrzalamena-build).
|
|
||||||
Copyright 1996-2005 Kunihiro Ishiguro, et al.
|
|
||||||
|
|
||||||
frr-1# show running-config
|
|
||||||
Building configuration...
|
|
||||||
|
|
||||||
Current configuration:
|
|
||||||
!
|
|
||||||
frr version 3.1-devrzalamena-build
|
|
||||||
frr defaults traditional
|
|
||||||
hostname r3
|
|
||||||
no service integrated-vtysh-config
|
|
||||||
!
|
|
||||||
log file zebra.log
|
|
||||||
!
|
|
||||||
log file ospfd.log
|
|
||||||
!
|
|
||||||
interface r3-eth0
|
|
||||||
ip address 10.0.3.1/24
|
|
||||||
!
|
|
||||||
interface r3-eth1
|
|
||||||
ip address 10.0.10.1/24
|
|
||||||
!
|
|
||||||
interface r3-eth2
|
|
||||||
ip address 172.16.0.2/24
|
|
||||||
!
|
|
||||||
router ospf
|
|
||||||
ospf router-id 10.0.255.3
|
|
||||||
redistribute kernel
|
|
||||||
redistribute connected
|
|
||||||
redistribute static
|
|
||||||
network 10.0.3.0/24 area 0
|
|
||||||
network 10.0.10.0/24 area 0
|
|
||||||
network 172.16.0.0/24 area 1
|
|
||||||
!
|
|
||||||
line vty
|
|
||||||
!
|
|
||||||
end
|
|
||||||
frr-1#
|
|
||||||
|
|
||||||
After you successfully configured your topology, you can obtain the
|
After you successfully configured your topology, you can obtain the
|
||||||
configuration files (per-daemon) using the following commands:
|
configuration files (per-daemon) using the following commands:
|
||||||
|
|
||||||
.. code:: shell
|
.. code:: shell
|
||||||
|
|
||||||
mininet> r3 vtysh -d ospfd
|
unet> sh r3 vtysh -d ospfd
|
||||||
|
|
||||||
Hello, this is FRRouting (version 3.1-devrzalamena-build).
|
Hello, this is FRRouting (version 3.1-devrzalamena-build).
|
||||||
Copyright 1996-2005 Kunihiro Ishiguro, et al.
|
Copyright 1996-2005 Kunihiro Ishiguro, et al.
|
||||||
|
|
||||||
frr-1# show running-config
|
r1# show running-config
|
||||||
Building configuration...
|
Building configuration...
|
||||||
|
|
||||||
Current configuration:
|
Current configuration:
|
||||||
@ -839,7 +951,7 @@ configuration files (per-daemon) using the following commands:
|
|||||||
line vty
|
line vty
|
||||||
!
|
!
|
||||||
end
|
end
|
||||||
frr-1#
|
r1#
|
||||||
|
|
||||||
Writing Tests
|
Writing Tests
|
||||||
"""""""""""""
|
"""""""""""""
|
||||||
@ -848,15 +960,12 @@ Test topologies should always be bootstrapped from
|
|||||||
:file:`tests/topotests/example-test/test_template.py` because it contains
|
:file:`tests/topotests/example-test/test_template.py` because it contains
|
||||||
important boilerplate code that can't be avoided, like:
|
important boilerplate code that can't be avoided, like:
|
||||||
|
|
||||||
- imports: os, sys, pytest, topotest/topogen and mininet topology class
|
|
||||||
- The global variable CWD (Current Working directory): which is most likely
|
|
||||||
going to be used to reference the routers configuration file location
|
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
.. code:: py
|
.. code:: py
|
||||||
|
|
||||||
# For all registered routers, load the zebra configuration file
|
# For all registered routers, load the zebra configuration file
|
||||||
|
CWD = os.path.dirname(os.path.realpath(__file__))
|
||||||
for rname, router in router_list.items():
|
for rname, router in router_list.items():
|
||||||
router.load_config(
|
router.load_config(
|
||||||
TopoRouter.RD_ZEBRA,
|
TopoRouter.RD_ZEBRA,
|
||||||
@ -865,21 +974,28 @@ Example:
|
|||||||
# os.path.join() joins the CWD string with arguments adding the necessary
|
# os.path.join() joins the CWD string with arguments adding the necessary
|
||||||
# slashes ('/'). Arguments must not begin with '/'.
|
# slashes ('/'). Arguments must not begin with '/'.
|
||||||
|
|
||||||
- The topology class that inherits from Mininet Topo class:
|
- The topology definition or build function
|
||||||
|
|
||||||
.. code:: py
|
.. code:: py
|
||||||
|
|
||||||
class TemplateTopo(Topo):
|
topodef = {
|
||||||
def build(self, *_args, **_opts):
|
"s1": ("r1", "r2"),
|
||||||
tgen = get_topogen(self)
|
"s2": ("r2", "r3")
|
||||||
|
}
|
||||||
|
|
||||||
|
def build_topo(tgen):
|
||||||
# topology build code
|
# topology build code
|
||||||
|
...
|
||||||
|
|
||||||
- pytest ``setup_module()`` and ``teardown_module()`` to start the topology
|
- pytest ``setup_module()`` and ``teardown_module()`` to start the topology
|
||||||
|
|
||||||
.. code:: py
|
.. code:: py
|
||||||
|
|
||||||
def setup_module(_m):
|
def setup_module(module):
|
||||||
tgen = Topogen(TemplateTopo)
|
tgen = Topogen(topodef, module.__name__)
|
||||||
|
# or
|
||||||
|
tgen = Topogen(build_topo, module.__name__)
|
||||||
|
|
||||||
tgen.start_topology('debug')
|
tgen.start_topology('debug')
|
||||||
|
|
||||||
def teardown_module(_m):
|
def teardown_module(_m):
|
||||||
@ -1042,11 +1158,10 @@ Example of pdb usage:
|
|||||||
(Pdb) router1 = tgen.gears[router]
|
(Pdb) router1 = tgen.gears[router]
|
||||||
(Pdb) router1.vtysh_cmd('show ip ospf route')
|
(Pdb) router1.vtysh_cmd('show ip ospf route')
|
||||||
'============ OSPF network routing table ============\r\nN 10.0.1.0/24 [10] area: 0.0.0.0\r\n directly attached to r1-eth0\r\nN 10.0.2.0/24 [20] area: 0.0.0.0\r\n via 10.0.3.3, r1-eth1\r\nN 10.0.3.0/24 [10] area: 0.0.0.0\r\n directly attached to r1-eth1\r\nN 10.0.10.0/24 [20] area: 0.0.0.0\r\n via 10.0.3.1, r1-eth1\r\nN IA 172.16.0.0/24 [20] area: 0.0.0.0\r\n via 10.0.3.1, r1-eth1\r\nN IA 172.16.1.0/24 [30] area: 0.0.0.0\r\n via 10.0.3.1, r1-eth1\r\n\r\n============ OSPF router routing table =============\r\nR 10.0.255.2 [10] area: 0.0.0.0, ASBR\r\n via 10.0.3.3, r1-eth1\r\nR 10.0.255.3 [10] area: 0.0.0.0, ABR, ASBR\r\n via 10.0.3.1, r1-eth1\r\nR 10.0.255.4 IA [20] area: 0.0.0.0, ASBR\r\n via 10.0.3.1, r1-eth1\r\n\r\n============ OSPF external routing table ===========\r\n\r\n\r\n'
|
'============ OSPF network routing table ============\r\nN 10.0.1.0/24 [10] area: 0.0.0.0\r\n directly attached to r1-eth0\r\nN 10.0.2.0/24 [20] area: 0.0.0.0\r\n via 10.0.3.3, r1-eth1\r\nN 10.0.3.0/24 [10] area: 0.0.0.0\r\n directly attached to r1-eth1\r\nN 10.0.10.0/24 [20] area: 0.0.0.0\r\n via 10.0.3.1, r1-eth1\r\nN IA 172.16.0.0/24 [20] area: 0.0.0.0\r\n via 10.0.3.1, r1-eth1\r\nN IA 172.16.1.0/24 [30] area: 0.0.0.0\r\n via 10.0.3.1, r1-eth1\r\n\r\n============ OSPF router routing table =============\r\nR 10.0.255.2 [10] area: 0.0.0.0, ASBR\r\n via 10.0.3.3, r1-eth1\r\nR 10.0.255.3 [10] area: 0.0.0.0, ABR, ASBR\r\n via 10.0.3.1, r1-eth1\r\nR 10.0.255.4 IA [20] area: 0.0.0.0, ASBR\r\n via 10.0.3.1, r1-eth1\r\n\r\n============ OSPF external routing table ===========\r\n\r\n\r\n'
|
||||||
(Pdb) tgen.mininet_cli()
|
(Pdb) tgen.cli()
|
||||||
*** Starting CLI:
|
unet>
|
||||||
mininet>
|
|
||||||
|
|
||||||
To enable more debug messages in other Topogen subsystems (like Mininet), more
|
To enable more debug messages in other Topogen subsystems, more
|
||||||
logging messages can be displayed by modifying the test configuration file
|
logging messages can be displayed by modifying the test configuration file
|
||||||
``pytest.ini``:
|
``pytest.ini``:
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user