summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_rpki.c22
-rw-r--r--doc/developer/conf.py2
-rw-r--r--doc/developer/index.rst1
-rw-r--r--doc/developer/subdir.am3
-rw-r--r--doc/developer/testing.rst10
-rw-r--r--doc/developer/topotests-snippets.rst272
-rw-r--r--doc/developer/topotests.rst927
-rw-r--r--doc/user/sharp.rst14
-rw-r--r--lib/memory.c1
-rw-r--r--lib/memory.h1
-rw-r--r--lib/prefix.c1
-rw-r--r--lib/workqueue.c5
-rw-r--r--lib/workqueue.h13
-rw-r--r--sharpd/sharp_globals.h55
-rw-r--r--sharpd/sharp_main.c15
-rw-r--r--sharpd/sharp_nht.c67
-rw-r--r--sharpd/sharp_nht.h38
-rw-r--r--sharpd/sharp_vty.c111
-rw-r--r--sharpd/sharp_zebra.c60
-rw-r--r--sharpd/sharp_zebra.h3
-rw-r--r--sharpd/subdir.am3
-rw-r--r--tests/Makefile.in1338
-rw-r--r--tests/topotests/GUIDELINES.md571
-rw-r--r--tests/topotests/README.md200
-rw-r--r--tests/topotests/SNIPPETS.md275
-rw-r--r--zebra/rt.h4
-rw-r--r--zebra/zebra_dplane.c226
-rw-r--r--zebra/zebra_dplane.h25
-rw-r--r--zebra/zebra_mpls_netlink.c10
-rw-r--r--zebra/zebra_mpls_null.c9
-rw-r--r--zebra/zebra_mpls_openbsd.c67
-rw-r--r--zebra/zebra_pw.c9
-rw-r--r--zebra/zebra_pw.h4
-rw-r--r--zebra/zebra_rib.c35
34 files changed, 3225 insertions, 1172 deletions
diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c
index b614e87d23..a38d78916c 100644
--- a/bgpd/bgp_rpki.c
+++ b/bgpd/bgp_rpki.c
@@ -1134,7 +1134,7 @@ DEFPY (no_rpki_cache,
{
struct cache *cache_p = find_cache(preference);
- if (!cache) {
+ if (!cache_p) {
vty_out(vty, "Could not find cache %ld\n", preference);
return CMD_WARNING;
}
@@ -1190,9 +1190,23 @@ DEFUN (show_rpki_cache_server,
struct cache *cache;
for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) {
- vty_out(vty, "host: %s port: %s\n",
- cache->tr_config.tcp_config->host,
- cache->tr_config.tcp_config->port);
+ if (cache->type == TCP) {
+ vty_out(vty, "host: %s port: %s\n",
+ cache->tr_config.tcp_config->host,
+ cache->tr_config.tcp_config->port);
+
+ } else if (cache->type == SSH) {
+ vty_out(vty,
+ "host: %s port: %d username: %s "
+ "server_hostkey_path: %s client_privkey_path: %s\n",
+ cache->tr_config.ssh_config->host,
+ cache->tr_config.ssh_config->port,
+ cache->tr_config.ssh_config->username,
+ cache->tr_config.ssh_config
+ ->server_hostkey_path,
+ cache->tr_config.ssh_config
+ ->client_privkey_path);
+ }
}
return CMD_SUCCESS;
diff --git a/doc/developer/conf.py b/doc/developer/conf.py
index 254c9f6bfc..ad501ae39d 100644
--- a/doc/developer/conf.py
+++ b/doc/developer/conf.py
@@ -131,7 +131,7 @@ language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
-exclude_patterns = ['_build', 'building-libyang.rst']
+exclude_patterns = ['_build', 'building-libyang.rst', 'topotests-snippets.rst']
# The reST default role (used for this markup: `text`) to use for all
# documents.
diff --git a/doc/developer/index.rst b/doc/developer/index.rst
index 9838e1098c..3a33d9a5ec 100644
--- a/doc/developer/index.rst
+++ b/doc/developer/index.rst
@@ -9,6 +9,7 @@ FRRouting Developer's Guide
packaging
process-architecture
library
+ testing
bgpd
ospf
zebra
diff --git a/doc/developer/subdir.am b/doc/developer/subdir.am
index 575722a805..19910e7627 100644
--- a/doc/developer/subdir.am
+++ b/doc/developer/subdir.am
@@ -38,6 +38,9 @@ dev_RSTFILES = \
doc/developer/ospf-api.rst \
doc/developer/ospf-sr.rst \
doc/developer/ospf.rst \
+ doc/developer/testing.rst \
+ doc/developer/topotests-snippets.rst \
+ doc/developer/topotests.rst \
doc/developer/workflow.rst \
doc/developer/zebra.rst \
# end
diff --git a/doc/developer/testing.rst b/doc/developer/testing.rst
new file mode 100644
index 0000000000..6396faf9a6
--- /dev/null
+++ b/doc/developer/testing.rst
@@ -0,0 +1,10 @@
+.. _testing:
+
+*******
+Testing
+*******
+
+.. toctree::
+ :maxdepth: 2
+
+ topotests
diff --git a/doc/developer/topotests-snippets.rst b/doc/developer/topotests-snippets.rst
new file mode 100644
index 0000000000..649229b433
--- /dev/null
+++ b/doc/developer/topotests-snippets.rst
@@ -0,0 +1,272 @@
+.. _topotests-snippets:
+
+Snippets
+--------
+
+This document will describe common snippets of code that are frequently needed
+to perform some test checks.
+
+Checking for router / test failures
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The following check uses the topogen API to check for software failure (e.g.
+zebra died) and/or for errors manually set by ``Topogen.set_error()``.
+
+.. code:: py
+
+ # Get the topology reference
+ tgen = get_topogen()
+
+ # Check for errors in the topology
+ if tgen.routers_have_failure():
+ # Skip the test with the topology errors as reason
+ pytest.skip(tgen.errors)
+
+Checking FRR routers version
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This code snippet is usually run after the topology setup to make sure all
+routers instantiated in the topology have the correct software version.
+
+.. code:: py
+
+ # Get the topology reference
+ tgen = get_topogen()
+
+ # Get the router list
+ router_list = tgen.routers()
+
+ # Run the check for all routers
+ for router in router_list.values():
+ if router.has_version('<', '3'):
+ # Set topology error, so the next tests are skipped
+ tgen.set_error('unsupported version')
+
+A sample of this snippet in a test can be found `here
+<ldp-vpls-topo1/test_ldp_vpls_topo1.py>`__.
+
+Interacting with equipment
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+You might want to interact with the topology equipments during the tests and
+there are different ways to do so.
+
+Notes:
+
+1. When using the Topogen API, all the equipments code derive from ``Topogear``
+ (`lib/topogen.py <lib/topogen.py>`__). If you feel brave you can look by
+ yourself how the abstractions that will be mentioned here works.
+
+2. When not using the ``Topogen`` API there is only one way to interact with
+ the equipments, which is by calling the ``mininet`` API functions directly
+ to spawn commands.
+
+Interacting with the Linux sandbox
+""""""""""""""""""""""""""""""""""
+
+Without ``Topogen``:
+
+.. code:: py
+
+ global net
+ output = net['r1'].cmd('echo "foobar"')
+ print 'output is: {}'.format(output)
+
+With ``Topogen``:
+
+.. code:: py
+
+ tgen = get_topogen()
+ output = tgen.gears['r1'].run('echo "foobar"')
+ print 'output is: {}'.format(output)
+
+Interacting with VTYSH
+""""""""""""""""""""""
+
+Without ``Topogen``:
+
+.. code:: py
+
+ global net
+ output = net['r1'].cmd('vtysh "show ip route" 2>/dev/null')
+ print 'output is: {}'.format(output)
+
+With ``Topogen``:
+
+.. code:: py
+
+ tgen = get_topogen()
+ output = tgen.gears['r1'].vtysh_cmd("show ip route")
+ print 'output is: {}'.format(output)
+
+``Topogen`` also supports sending multiple lines of command:
+
+.. code:: py
+
+ tgen = get_topogen()
+ output = tgen.gears['r1'].vtysh_cmd("""
+ configure terminal
+ router bgp 10
+ bgp router-id 10.0.255.1
+ neighbor 1.2.3.4 remote-as 10
+ !
+ router bgp 11
+ bgp router-id 10.0.255.2
+ !
+ """)
+ print 'output is: {}'.format(output)
+
+You might also want to run multiple commands and get only the commands that
+failed:
+
+.. code:: py
+
+ tgen = get_topogen()
+ output = tgen.gears['r1'].vtysh_multicmd("""
+ configure terminal
+ router bgp 10
+ bgp router-id 10.0.255.1
+ neighbor 1.2.3.4 remote-as 10
+ !
+ router bgp 11
+ bgp router-id 10.0.255.2
+ !
+ """, pretty_output=false)
+ print 'output is: {}'.format(output)
+
+Translating vtysh JSON output into Python structures:
+
+.. code:: py
+
+ tgen = get_topogen()
+ json_output = tgen.gears['r1'].vtysh_cmd("show ip route json", isjson=True)
+ output = json.dumps(json_output, indent=4)
+ print 'output is: {}'.format(output)
+
+ # You can also access the data structure as normal. For example:
+ # protocol = json_output['1.1.1.1/32']['protocol']
+ # assert protocol == "ospf", "wrong protocol"
+
+.. note::
+
+ ``vtysh_(multi)cmd`` is only available for router type of equipments.
+
+Invoking mininet CLI
+^^^^^^^^^^^^^^^^^^^^
+
+Without ``Topogen``:
+
+.. code:: py
+
+ CLI(net)
+
+With ``Topogen``:
+
+.. code:: py
+
+ tgen = get_topogen()
+ tgen.mininet_cli()
+
+Reading files
+^^^^^^^^^^^^^
+
+Loading a normal text file content in the current directory:
+
+.. code:: py
+
+ # If you are using Topogen
+ # CURDIR = CWD
+ #
+ # Otherwise find the directory manually:
+ CURDIR = os.path.dirname(os.path.realpath(__file__))
+
+ file_name = '{}/r1/show_ip_route.txt'.format(CURDIR)
+ file_content = open(file_name).read()
+
+Loading JSON from a file:
+
+.. code:: py
+
+ import json
+
+ file_name = '{}/r1/show_ip_route.json'.format(CURDIR)
+ file_content = json.loads(open(file_name).read())
+
+Comparing JSON output
+^^^^^^^^^^^^^^^^^^^^^
+
+After obtaining JSON output formated with Python data structures, you may use
+it to assert a minimalist schema:
+
+.. code:: py
+
+ tgen = get_topogen()
+ json_output = tgen.gears['r1'].vtysh_cmd("show ip route json", isjson=True)
+
+ expect = {
+ '1.1.1.1/32': {
+ 'protocol': 'ospf'
+ }
+ }
+
+ assertmsg = "route 1.1.1.1/32 was not learned through OSPF"
+ assert json_cmp(json_output, expect) is None, assertmsg
+
+``json_cmp`` function description (it might be outdated, you can find the
+latest description in the source code at
+:file:`tests/topotests/lib/topotest.py`
+
+.. code:: text
+
+ JSON compare function. Receives two parameters:
+ * `d1`: json value
+ * `d2`: json subset which we expect
+
+ Returns `None` when all keys that `d1` has matches `d2`,
+ otherwise a string containing what failed.
+
+ Note: key absence can be tested by adding a key with value `None`.
+
+Pausing execution
+^^^^^^^^^^^^^^^^^
+
+Preferably, choose the ``sleep`` function that ``topotest`` provides, as it
+prints a notice during the test execution to help debug topology test execution
+time.
+
+.. code:: py
+
+ # Using the topotest sleep
+ from lib import topotest
+
+ topotest.sleep(10, 'waiting 10 seconds for bla')
+ # or just tell it the time:
+ # topotest.sleep(10)
+ # It will print 'Sleeping for 10 seconds'.
+
+ # Or you can also use the Python sleep, but it won't show anything
+ from time import sleep
+ sleep(5)
+
+iproute2 Linux commands as JSON
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+``topotest`` has two helpers implemented that parses the output of ``ip route``
+commands to JSON. It might simplify your comparison needs by only needing to
+provide a Python dictionary.
+
+.. code:: py
+
+ from lib import topotest
+
+ tgen = get_topogen()
+ routes = topotest.ip4_route(tgen.gears['r1'])
+ expected = {
+ '10.0.1.0/24': {},
+ '10.0.2.0/24': {
+ 'dev': 'r1-eth0'
+ }
+ }
+
+ assertmsg = "failed to find 10.0.1.0/24 and/or 10.0.2.0/24"
+ assert json_cmp(routes, expected) is None, assertmsg
diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst
new file mode 100644
index 0000000000..aa06c8dffd
--- /dev/null
+++ b/doc/developer/topotests.rst
@@ -0,0 +1,927 @@
+.. _topotests:
+
+Topotests
+=========
+
+Topotests is a suite of topology tests for FRR built on top of Mininet.
+
+Installation and Setup
+----------------------
+
+Only tested with Ubuntu 16.04 and Ubuntu 18.04 (which uses Mininet 2.2.x).
+
+Instructions are the same for all setups (i.e. ExaBGP is only used for BGP
+tests).
+
+Installing Mininet Infrastructure
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code:: shell
+
+ apt-get install mininet
+ apt-get install python-pip
+ apt-get install iproute
+ pip install ipaddr
+ pip install pytest
+ pip install exabgp==3.4.17 (Newer 4.0 version of exabgp is not yet
+ supported)
+ useradd -d /var/run/exabgp/ -s /bin/false exabgp
+
+Enable Coredumps
+""""""""""""""""
+
+Optional, will give better output.
+
+.. code:: shell
+
+ apt-get install gdb
+ disable apport (which move core files)
+
+Set ``enabled=0`` in ``/etc/default/apport``.
+
+Next, update security limits by changing :file:`/etc/security/limits.conf` to::
+
+ #<domain> <type> <item> <value>
+ * soft core unlimited
+ root soft core unlimited
+ * hard core unlimited
+ root hard core unlimited
+
+Reboot for options to take effect.
+
+FRR Installation
+^^^^^^^^^^^^^^^^
+
+FRR needs to be installed separately. It is assume to be configured like the
+standard Ubuntu Packages:
+
+- Binaries in :file:`/usr/lib/frr`
+- State Directory :file:`/var/run/frr`
+- Running under user ``frr``, group ``frr``
+- vtygroup: ``frrvty``
+- config directory: :file:`/etc/frr`
+- For FRR Packages, install the dbg package as well for coredump decoding
+
+No FRR config needs to be done and no FRR daemons should be run ahead of the
+test. They are all started as part of the test.
+
+Manual FRR build
+""""""""""""""""
+
+If you prefer to manually build FRR, then use the following suggested config:
+
+.. code:: shell
+
+ ./configure \
+ --prefix=/usr \
+ --localstatedir=/var/run/frr \
+ --sbindir=/usr/lib/frr \
+ --sysconfdir=/etc/frr \
+ --enable-vtysh \
+ --enable-pimd \
+ --enable-multipath=64 \
+ --enable-user=frr \
+ --enable-group=frr \
+ --enable-vty-group=frrvty \
+ --with-pkg-extra-version=-my-manual-build
+
+And create ``frr`` user and ``frrvty`` group as follows:
+
+.. code:: shell
+
+ addgroup --system --gid 92 frr
+ addgroup --system --gid 85 frrvty
+ adduser --system --ingroup frr --home /var/run/frr/ \
+ --gecos "FRRouting suite" --shell /bin/false frr
+ usermod -G frrvty frr
+
+Executing Tests
+---------------
+
+Execute all tests with output to console
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code:: shell
+
+ py.test -s -v --tb=no
+
+All test\_\* scripts in subdirectories are detected and executed (unless
+disabled in ``pytest.ini`` file).
+
+``--tb=no`` disables the python traceback which might be irrelevant unless the
+test script itself is debugged.
+
+Execute single test
+^^^^^^^^^^^^^^^^^^^
+
+.. code:: shell
+
+ cd test_to_be_run
+ ./test_to_be_run.py
+
+For further options, refer to pytest documentation.
+
+Test will set exit code which can be used with ``git bisect``.
+
+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
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+To enable the reporting of any messages seen on StdErr after the daemons exit,
+the following env variable can be set::
+
+ export TOPOTESTS_CHECK_STDERR=Yes
+
+(The value doesn't matter at this time. The check is if the env variable exists
+or not) There is no pass/fail on this reporting. The Output will be reported to
+the console::
+
+ export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_"
+
+This will enable the check and output to console and the writing of the
+information to files with the given prefix (followed by testname), ie
+:file:`/home/mydir/memcheck_test_bgp_multiview_topo1.txt` in case of a memory
+leak.
+
+Collect Memory Leak Information
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+FRR processes have the capabilities to report remaining memory allocations upon
+exit. To enable the reporting of the memory, define an enviroment variable
+``TOPOTESTS_CHECK_MEMLEAK`` with the file prefix, i.e.::
+
+ export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_"
+
+This will enable the check and output to console and the writing of the
+information to files with the given prefix (followed by testname), ie
+:file:`/home/mydir/memcheck_test_bgp_multiview_topo1.txt` in case of a memory
+leak.
+
+Running Topotests with AddressSanitizer
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Topotests can be run with AddressSanitizer. It requires GCC 4.8 or newer.
+(Ubuntu 16.04 as suggested here is fine with GCC 5 as default). For more
+information on AddressSanitizer, see
+https://github.com/google/sanitizers/wiki/AddressSanitizer.
+
+The checks are done automatically in the library call of ``checkRouterRunning``
+(ie at beginning of tests when there is a check for all daemons running). No
+changes or extra configuration for topotests is required beside compiling the
+suite with AddressSanitizer enabled.
+
+If a daemon crashed, then the errorlog is checked for AddressSanitizer output.
+If found, then this is added with context (calling test) to
+:file:`/tmp/AddressSanitizer.txt` in Markdown compatible format.
+
+Compiling for GCC AddressSanitizer requires to use ``gcc`` as a linker as well
+(instead of ``ld``). Here is a suggest way to compile frr with AddressSanitizer
+for ``stable/3.0`` branch:
+
+.. code:: shell
+
+ git clone https://github.com/FRRouting/frr.git
+ cd frr
+ git checkout stable/3.0
+ ./bootstrap.sh
+ export CC=gcc
+ export CFLAGS="-O1 -g -fsanitize=address -fno-omit-frame-pointer"
+ export LD=gcc
+ export LDFLAGS="-g -fsanitize=address -ldl"
+ ./configure --enable-shared=no \
+ --prefix=/usr/lib/frr --sysconfdir=/etc/frr \
+ --localstatedir=/var/run/frr \
+ --sbindir=/usr/lib/frr --bindir=/usr/lib/frr \
+ --enable-exampledir=/usr/lib/frr/examples \
+ --with-moduledir=/usr/lib/frr/modules \
+ --enable-multipath=0 --enable-rtadv \
+ --enable-tcp-zebra --enable-fpm --enable-pimd
+ make
+ sudo make install
+ # Create symlink for vtysh, so topotest finds it in /usr/lib/frr
+ sudo ln -s /usr/lib/frr/vtysh /usr/bin/
+
+and create ``frr`` user and ``frrvty`` group as shown above.
+
+.. _topotests_docker:
+
+Running Tests with Docker
+-------------------------
+
+There is a Docker image which allows to run topotests.
+
+Quickstart
+^^^^^^^^^^
+
+If you have Docker installed, you can run the topotests in Docker. The easiest
+way to do this, is to use the make targets from this repository.
+
+Your current user needs to have access to the Docker daemon. Alternatively you
+can run these commands as root.
+
+.. code:: console
+
+ make topotests
+
+This command will pull the most recent topotests image from Dockerhub, compile
+FRR inside of it, and run the topotests.
+
+Advanced Usage
+^^^^^^^^^^^^^^
+
+Internally, the topotests make target uses a shell script to pull the image and
+spawn the Docker container.
+
+There are several environment variables which can be used to modify the
+behavior of the script, these can be listed by calling it with ``-h``:
+
+.. code:: console
+
+ ./tests/topotests/docker/frr-topotests.sh -h
+
+For example, a volume is used to cache build artifacts between multiple runs of
+the image. If you need to force a complete recompile, you can set
+``TOPOTEST_CLEAN``:
+
+.. code:: console
+
+ TOPOTEST_CLEAN=1 ./tests/topotests/docker/frr-topotests.sh
+
+By default, ``frr-topotests.sh`` will build frr and run pytest. If you append
+arguments and the first one starts with ``/`` or ``./``, they will replace the
+call to pytest. If the appended arguments do not match this patttern, they will
+be provided to pytest as arguments. So, to run a specific test with more
+verbose logging:
+
+.. code:: console
+
+ ./tests/topotests/docker/frr-topotests.sh -vv -s all-protocol-startup/test_all_protocol_startup.py
+
+And to compile FRR but drop into a shell instead of running pytest:
+
+.. code:: console
+
+ ./tests/topotests/docker/frr-topotests.sh /bin/bash
+
+Development
+^^^^^^^^^^^
+
+The Docker image just includes all the components to run the topotests, but not
+the topotests themselves. So if you just want to write tests and don't want to
+make changes to the environment provided by the Docker image. You don't need to
+build your own Docker image if you do not want to.
+
+When developing new tests, there is one caveat though: The startup script of
+the container will run a ``git-clean`` on its copy of the FRR tree to avoid any
+pollution of the container with build artefacts from the host. This will also
+result in your newly written tests being unavailable in the container unless at
+least added to the index with ``git-add``.
+
+If you do want to test changes to the Docker image, you can locally build the
+image and run the tests without pulling from the registry using the following
+commands:
+
+.. code:: console
+
+ make topotests-build
+ TOPOTEST_PULL=0 make topotests
+
+
+.. _topotests-guidelines:
+
+Guidelines
+----------
+
+Executing Tests
+^^^^^^^^^^^^^^^
+
+To run the whole suite of tests the following commands must be executed at the
+top level directory of topotest:
+
+.. code:: shell
+
+ $ # Change to the top level directory of topotests.
+ $ cd path/to/topotests
+ $ # Tests must be run as root, since Mininet requires it.
+ $ sudo pytest
+
+In order to run a specific test, you can use the following command:
+
+.. code:: shell
+
+ $ # running a specific topology
+ $ sudo pytest ospf-topo1/
+ $ # or inside the test folder
+ $ cd ospf-topo1
+ $ sudo pytest # to run all tests inside the directory
+ $ sudo pytest test_ospf_topo1.py # to run a specific test
+ $ # or outside the test folder
+ $ cd ..
+ $ sudo pytest ospf-topo1/test_ospf_topo1.py # to run a specific one
+
+The output of the tested daemons will be available at the temporary folder of
+your machine:
+
+.. code:: shell
+
+ $ ls /tmp/topotest/ospf-topo1.test_ospf-topo1/r1
+ ...
+ zebra.err # zebra stderr output
+ zebra.log # zebra log file
+ zebra.out # zebra stdout output
+ ...
+
+You can also run memory leak tests to get reports:
+
+.. code:: shell
+
+ $ # Set the environment variable to apply to a specific test...
+ $ sudo env TOPOTESTS_CHECK_MEMLEAK="/tmp/memleak_report_" pytest ospf-topo1/test_ospf_topo1.py
+ $ # ...or apply to all tests adding this line to the configuration file
+ $ echo 'memleak_path = /tmp/memleak_report_' >> pytest.ini
+ $ # You can also use your editor
+ $ $EDITOR pytest.ini
+ $ # After running tests you should see your files:
+ $ ls /tmp/memleak_report_*
+ memleak_report_test_ospf_topo1.txt
+
+Writing a New Test
+^^^^^^^^^^^^^^^^^^
+
+This section will guide you in all recommended steps to produce a standard
+topology test.
+
+This is the recommended test writing routine:
+
+- Write a topology (Graphviz recommended)
+- Obtain configuration files
+- Write the test itself
+- Create a Pull Request
+
+Topotest File Hierarchy
+"""""""""""""""""""""""
+
+Before starting to write any tests one must know the file hierarchy. The
+repository hierarchy looks like this:
+
+.. code:: shell
+
+ $ cd path/to/topotest
+ $ find ./*
+ ...
+ ./README.md # repository read me
+ ./GUIDELINES.md # this file
+ ./conftest.py # test hooks - pytest related functions
+ ./example-test # example test folder
+ ./example-test/__init__.py # python package marker - must always exist.
+ ./example-test/test_template.jpg # generated topology picture - see next section
+ ./example-test/test_template.dot # Graphviz dot file
+ ./example-test/test_template.py # the topology plus the test
+ ...
+ ./ospf-topo1 # the ospf topology test
+ ./ospf-topo1/r1 # router 1 configuration files
+ ./ospf-topo1/r1/zebra.conf # zebra configuration file
+ ./ospf-topo1/r1/ospfd.conf # ospf configuration file
+ ./ospf-topo1/r1/ospfroute.txt # 'show ip ospf' output reference file
+ # removed other for shortness sake
+ ...
+ ./lib # shared test/topology functions
+ ./lib/topogen.py # topogen implementation
+ ./lib/topotest.py # topotest implementation
+
+Guidelines for creating/editing topotest:
+
+- New topologies that don't fit the existing directories should create its own
+- Always remember to add the ``__init__.py`` to new folders, this makes auto
+ complete engines and pylint happy
+- Router (Quagga/FRR) specific code should go on topotest.py
+- Generic/repeated router actions should have an abstraction in
+ topogen.TopoRouter.
+- Generic/repeated non-router code should go to topotest.py
+- pytest related code should go to conftest.py (e.g. specialized asserts)
+
+Defining the Topology
+"""""""""""""""""""""
+
+The first step to write a new test is to define the topology. This step can be
+done in many ways, but the recommended is to use Graphviz to generate a drawing
+of the topology. It allows us to see the topology graphically and to see the
+names of equipments, links and addresses.
+
+Here is an example of Graphviz dot file that generates the template topology
+:file:`tests/topotests/example-test/test_template.dot` (the inlined code might
+get outdated, please see the linked file)::
+
+ graph template {
+ label="template";
+
+ # Routers
+ r1 [
+ shape=doubleoctagon,
+ label="r1",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r2 [
+ shape=doubleoctagon,
+ label="r2",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+
+ # Switches
+ s1 [
+ shape=oval,
+ label="s1\n192.168.0.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ s2 [
+ shape=oval,
+ label="s2\n192.168.1.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+
+ # Connections
+ r1 -- s1 [label="eth0\n.1"];
+
+ r1 -- s2 [label="eth1\n.100"];
+ r2 -- s2 [label="eth0\n.1"];
+ }
+
+Here is the produced graph:
+
+.. graphviz::
+
+ graph template {
+ label="template";
+
+ # Routers
+ r1 [
+ shape=doubleoctagon,
+ label="r1",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r2 [
+ shape=doubleoctagon,
+ label="r2",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+
+ # Switches
+ s1 [
+ shape=oval,
+ label="s1\n192.168.0.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ s2 [
+ shape=oval,
+ label="s2\n192.168.1.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+
+ # Connections
+ r1 -- s1 [label="eth0\n.1"];
+
+ r1 -- s2 [label="eth1\n.100"];
+ r2 -- s2 [label="eth0\n.1"];
+ }
+
+Generating / Obtaining Configuration Files
+""""""""""""""""""""""""""""""""""""""""""
+
+In order to get the configuration files or command output for each router, we
+need to run the topology and execute commands in ``vtysh``. The quickest way to
+achieve that is writing the topology building code and running the topology.
+
+To bootstrap your test topology, do the following steps:
+
+- Copy the template test
+
+.. code:: shell
+
+ $ mkdir new-topo/
+ $ touch new-topo/__init__.py
+ $ cp example-test/test_template.py new-topo/test_new_topo.py
+
+- Modify the template according to your dot file
+
+Here is the template topology described in the previous section in python code:
+
+.. code:: py
+
+ class TemplateTopo(Topo):
+ "Test topology builder"
+ def build(self, *_args, **_opts):
+ "Build function"
+ tgen = get_topogen(self)
+
+ # 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
+
+Topogen allows us to run the topology without running any tests, you can do
+that using the following example commands:
+
+.. code:: shell
+
+ $ # Running your bootstraped topology
+ $ sudo pytest -s --topology-only new-topo/test_new_topo.py
+ $ # Running the test_template.py topology
+ $ sudo pytest -s --topology-only example-test/test_template.py
+ $ # Running the ospf_topo1.py topology
+ $ sudo pytest -s --topology-only ospf-topo1/test_ospf_topo1.py
+
+Parameters explanation:
+
+.. program:: pytest
+
+.. option:: -s
+
+ Actives input/output capture. This is required by mininet in order to show
+ the interactive shell.
+
+.. option:: --topology-only
+
+ Don't run any tests, just build the topology.
+
+After executing the commands above, you should get the following terminal
+output:
+
+.. code:: shell
+
+ === test session starts ===
+ platform linux2 -- Python 2.7.12, pytest-3.1.2, py-1.4.34, pluggy-0.4.0
+ rootdir: /media/sf_src/topotests, inifile: pytest.ini
+ collected 3 items
+
+ ospf-topo1/test_ospf_topo1.py *** Starting controller
+
+ *** Starting 6 switches
+ 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.
+
+Here are some commands example:
+
+.. code:: shell
+
+ mininet> r1 ping 10.0.3.1
+ 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=2 ttl=64 time=0.083 ms
+ 64 bytes from 10.0.3.1: icmp_seq=3 ttl=64 time=0.088 ms
+ ^C
+ --- 10.0.3.1 ping statistics ---
+ 3 packets transmitted, 3 received, 0% packet loss, time 1998ms
+ rtt min/avg/max/mdev = 0.083/0.249/0.576/0.231 ms
+
+
+
+ mininet> r1 ping 10.0.3.3
+ PING 10.0.3.3 (10.0.3.3) 56(84) bytes of data.
+ 64 bytes from 10.0.3.3: icmp_seq=1 ttl=64 time=2.87 ms
+ 64 bytes from 10.0.3.3: icmp_seq=2 ttl=64 time=0.080 ms
+ 64 bytes from 10.0.3.3: icmp_seq=3 ttl=64 time=0.091 ms
+ ^C
+ --- 10.0.3.3 ping statistics ---
+ 3 packets transmitted, 3 received, 0% packet loss, time 2003ms
+ rtt min/avg/max/mdev = 0.080/1.014/2.872/1.313 ms
+
+
+
+ mininet> r3 vtysh
+
+ 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
+configuration files (per-daemon) using the following commands:
+
+.. code:: shell
+
+ mininet> r3 vtysh -d ospfd
+
+ 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
+ no service integrated-vtysh-config
+ !
+ log file ospfd.log
+ !
+ 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#
+
+Writing Tests
+"""""""""""""
+
+Test topologies should always be bootstrapped from
+:file:`tests/topotests/example-test/test_template.py` because it contains
+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:
+
+.. code:: py
+
+ # For all registered routers, load the zebra configuration file
+ for rname, router in router_list.iteritems():
+ router.load_config(
+ TopoRouter.RD_ZEBRA,
+ os.path.join(CWD, '{}/zebra.conf'.format(rname))
+ )
+ # os.path.join() joins the CWD string with arguments adding the necessary
+ # slashes ('/'). Arguments must not begin with '/'.
+
+- The topology class that inherits from Mininet Topo class:
+
+.. code:: py
+
+ class TemplateTopo(Topo):
+ def build(self, *_args, **_opts):
+ tgen = get_topogen(self)
+ # topology build code
+
+- pytest ``setup_module()`` and ``teardown_module()`` to start the topology
+
+.. code:: py
+
+ def setup_module(_m):
+ tgen = Topogen(TemplateTopo)
+ tgen.start_topology('debug')
+
+ def teardown_module(_m):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+- ``__main__`` initialization code (to support running the script directly)
+
+.. code:: py
+
+ if __name__ == '__main__':
+ sys.exit(pytest.main(["-s"]))
+
+Requirements:
+
+- Test code should always be declared inside functions that begin with the
+ ``test_`` prefix. Functions beginning with different prefixes will not be run
+ by pytest.
+- Configuration files and long output commands should go into separated files
+ inside folders named after the equipment.
+- Tests must be able to run without any interaction. To make sure your test
+ conforms with this, run it without the :option:`-s` parameter.
+
+Tips:
+
+- Keep results in stack variables, so people inspecting code with ``pdb`` can
+ easily print their values.
+
+Don't do this:
+
+.. code:: py
+
+ assert foobar(router1, router2)
+
+Do this instead:
+
+.. code:: py
+
+ result = foobar(router1, router2)
+ assert result
+
+- Use ``assert`` messages to indicate where the test failed.
+
+Example:
+
+.. code:: py
+
+ for router in router_list:
+ # ...
+ assert condition, 'Router "{}" condition failed'.format(router.name)
+
+Debugging Execution
+^^^^^^^^^^^^^^^^^^^
+
+The most effective ways to inspect topology tests are:
+
+- Run pytest with ``--pdb`` option. This option will cause a pdb shell to
+ appear when an assertion fails
+
+Example: ``pytest -s --pdb ospf-topo1/test_ospf_topo1.py``
+
+- Set a breakpoint in the test code with ``pdb``
+
+Example:
+
+.. code:: py
+
+ # Add the pdb import at the beginning of the file
+ import pdb
+ # ...
+
+ # Add a breakpoint where you think the problem is
+ def test_bla():
+ # ...
+ pdb.set_trace()
+ # ...
+
+The `Python Debugger <https://docs.python.org/2.7/library/pdb.html>`__ (pdb)
+shell allows us to run many useful operations like:
+
+- Setting breaking point on file/function/conditions (e.g. ``break``,
+ ``condition``)
+- Inspecting variables (e.g. ``p`` (print), ``pp`` (pretty print))
+- Running python code
+
+.. tip::
+
+ The TopoGear (equipment abstraction class) implements the ``__str__`` method
+ that allows the user to inspect equipment information.
+
+Example of pdb usage:
+
+.. code:: shell
+
+ > /media/sf_src/topotests/ospf-topo1/test_ospf_topo1.py(121)test_ospf_convergence()
+ -> for rnum in range(1, 5):
+ (Pdb) help
+ Documented commands (type help <topic>):
+ ========================================
+ EOF bt cont enable jump pp run unt
+ a c continue exit l q s until
+ alias cl d h list quit step up
+ args clear debug help n r tbreak w
+ b commands disable ignore next restart u whatis
+ break condition down j p return unalias where
+
+ Miscellaneous help topics:
+ ==========================
+ exec pdb
+
+ Undocumented commands:
+ ======================
+ retval rv
+
+ (Pdb) list
+ 116 title2="Expected output")
+ 117
+ 118 def test_ospf_convergence():
+ 119 "Test OSPF daemon convergence"
+ 120 pdb.set_trace()
+ 121 -> for rnum in range(1, 5):
+ 122 router = 'r{}'.format(rnum)
+ 123
+ 124 # Load expected results from the command
+ 125 reffile = os.path.join(CWD, '{}/ospfroute.txt'.format(router))
+ 126 expected = open(reffile).read()
+ (Pdb) step
+ > /media/sf_src/topotests/ospf-topo1/test_ospf_topo1.py(122)test_ospf_convergence()
+ -> router = 'r{}'.format(rnum)
+ (Pdb) step
+ > /media/sf_src/topotests/ospf-topo1/test_ospf_topo1.py(125)test_ospf_convergence()
+ -> reffile = os.path.join(CWD, '{}/ospfroute.txt'.format(router))
+ (Pdb) print rnum
+ 1
+ (Pdb) print router
+ r1
+ (Pdb) tgen = get_topogen()
+ (Pdb) pp tgen.gears[router]
+ <lib.topogen.TopoRouter object at 0x7f74e06c9850>
+ (Pdb) pp str(tgen.gears[router])
+ 'TopoGear<name="r1",links=["r1-eth0"<->"s1-eth0","r1-eth1"<->"s3-eth0"]> TopoRouter<>'
+ (Pdb) l 125
+ 120 pdb.set_trace()
+ 121 for rnum in range(1, 5):
+ 122 router = 'r{}'.format(rnum)
+ 123
+ 124 # Load expected results from the command
+ 125 -> reffile = os.path.join(CWD, '{}/ospfroute.txt'.format(router))
+ 126 expected = open(reffile).read()
+ 127
+ 128 # Run test function until we get an result. Wait at most 60 seconds.
+ 129 test_func = partial(compare_show_ip_ospf, router, expected)
+ 130 result, diff = topotest.run_and_expect(test_func, '',
+ (Pdb) router1 = tgen.gears[router]
+ (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'
+ (Pdb) tgen.mininet_cli()
+ *** Starting CLI:
+ mininet>
+
+To enable more debug messages in other Topogen subsystems (like Mininet), more
+logging messages can be displayed by modifying the test configuration file
+``pytest.ini``:
+
+.. code:: ini
+
+ [topogen]
+ # Change the default verbosity line from 'info'...
+ #verbosity = info
+ # ...to 'debug'
+ verbosity = debug
+
+Instructions for use, write or debug topologies can be found in :ref:`topotests-guidelines`.
+To learn/remember common code snippets see :ref:`topotests-snippets`.
+
+Before creating a new topology, make sure that there isn't one already that
+does what you need. If nothing is similar, then you may create a new topology,
+preferably, using the newest template
+(:file:`tests/topotests/example-test/test_template.py`).
+
+.. include:: topotests-snippets.rst
+
+License
+-------
+
+All the configs and scripts are licensed under a ISC-style license. See Python
+scripts for details.
diff --git a/doc/user/sharp.rst b/doc/user/sharp.rst
index c2d32a718e..a78fac8fc1 100644
--- a/doc/user/sharp.rst
+++ b/doc/user/sharp.rst
@@ -56,6 +56,14 @@ keyword. At present, no sharp commands will be preserved in the config.
log and when all routes have been successfully deleted the debug log will be
updated with this information as well.
+.. index:: sharp data route
+.. clicmd:: sharp data route
+
+ Allow end user doing route install and deletion to get timing information
+ from the vty or vtysh instead of having to read the log file. This command
+ is informational only and you should look at sharp_vty.c for explanation
+ of the output as that it may change.
+
.. index:: sharp label
.. clicmd:: sharp label <ipv4|ipv6> vrf NAME label (0-1000000)
@@ -67,3 +75,9 @@ keyword. At present, no sharp commands will be preserved in the config.
Instruct zebra to monitor and notify sharp when the specified nexthop is
changed. The notification from zebra is written into the debug log.
+
+.. index:: sharp data nexthop
+.. clicmd:: sharp data nexthop
+
+ Allow end user to dump associated data with the nexthop tracking that
+ may have been turned on.
diff --git a/lib/memory.c b/lib/memory.c
index fee23a75ac..149e294d50 100644
--- a/lib/memory.c
+++ b/lib/memory.c
@@ -35,7 +35,6 @@ struct memgroup **mg_insert = &mg_first;
DEFINE_MGROUP(LIB, "libfrr")
DEFINE_MTYPE(LIB, TMP, "Temporary memory")
-DEFINE_MTYPE(LIB, PREFIX_FLOWSPEC, "Prefix Flowspec")
static inline void mt_count_alloc(struct memtype *mt, size_t size, void *ptr)
{
diff --git a/lib/memory.h b/lib/memory.h
index 2d6c144778..1a0269f8bb 100644
--- a/lib/memory.h
+++ b/lib/memory.h
@@ -137,7 +137,6 @@ struct memgroup {
DECLARE_MGROUP(LIB)
DECLARE_MTYPE(TMP)
-DECLARE_MTYPE(PREFIX_FLOWSPEC)
extern void *qmalloc(struct memtype *mt, size_t size)
diff --git a/lib/prefix.c b/lib/prefix.c
index 07eb1785b7..babd4304d1 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -30,6 +30,7 @@
#include "lib_errors.h"
DEFINE_MTYPE_STATIC(LIB, PREFIX, "Prefix")
+DEFINE_MTYPE_STATIC(LIB, PREFIX_FLOWSPEC, "Prefix Flowspec")
/* Maskbit. */
static const uint8_t maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0,
diff --git a/lib/workqueue.c b/lib/workqueue.c
index 24ef24c774..93bbc52e3b 100644
--- a/lib/workqueue.c
+++ b/lib/workqueue.c
@@ -99,7 +99,10 @@ struct work_queue *work_queue_new(struct thread_master *m,
return new;
}
-void work_queue_free_original(struct work_queue *wq)
+/*
+ * Internal helper api; used to be public.
+ */
+static void work_queue_free_original(struct work_queue *wq)
{
if (wq->thread != NULL)
thread_cancel(wq->thread);
diff --git a/lib/workqueue.h b/lib/workqueue.h
index 7c84655063..cbbacc0561 100644
--- a/lib/workqueue.h
+++ b/lib/workqueue.h
@@ -159,19 +159,10 @@ extern struct work_queue *work_queue_new(struct thread_master *, const char *);
* The usage of work_queue_free is being transitioned to pass
* in the double pointer to remove use after free's.
*/
-#if CONFDATE > 20190205
-CPP_NOTICE("work_queue_free without double pointer is deprecated, please fixup")
-#endif
-extern void work_queue_free_and_null(struct work_queue **);
-extern void work_queue_free_original(struct work_queue *);
-#define work_queue_free(X) \
- do { \
- work_queue_free_original((X)); \
- CPP_WARN("Please use work_queue_free_and_null"); \
- } while (0)
+extern void work_queue_free_and_null(struct work_queue **wqp);
/* Add the supplied data as an item onto the workqueue */
-extern void work_queue_add(struct work_queue *, void *);
+extern void work_queue_add(struct work_queue *wq, void *item);
/* plug the queue, ie prevent it from being drained / processed */
extern void work_queue_plug(struct work_queue *wq);
diff --git a/sharpd/sharp_globals.h b/sharpd/sharp_globals.h
new file mode 100644
index 0000000000..065fb092d4
--- /dev/null
+++ b/sharpd/sharp_globals.h
@@ -0,0 +1,55 @@
+/*
+ * SHARP - code to track globals
+ * Copyright (C) 2019 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef __SHARP_GLOBAL_H__
+#define __SHARP_GLOBAL_H__
+
+DECLARE_MGROUP(SHARPD)
+
+struct sharp_routes {
+ /* The original prefix for route installation */
+ struct prefix orig_prefix;
+
+ /* The nexthop group we are using for installation */
+ struct nexthop nhop;
+ struct nexthop_group nhop_group;
+
+ uint32_t total_routes;
+ uint32_t installed_routes;
+ uint32_t removed_routes;
+ int32_t repeat;
+
+ uint8_t inst;
+
+ struct timeval t_start;
+ struct timeval t_end;
+};
+
+struct sharp_global {
+ /* Global data about route install/deletions */
+ struct sharp_routes r;
+
+ /* The list of nexthops that we are watching and data about them */
+ struct list *nhs;
+};
+
+extern struct sharp_global sg;
+#endif
diff --git a/sharpd/sharp_main.c b/sharpd/sharp_main.c
index 175a276089..39453ee9ad 100644
--- a/sharpd/sharp_main.c
+++ b/sharpd/sharp_main.c
@@ -46,10 +46,9 @@
#include "sharp_zebra.h"
#include "sharp_vty.h"
+#include "sharp_globals.h"
-uint32_t total_routes = 0;
-uint32_t installed_routes = 0;
-uint32_t removed_routes = 0;
+DEFINE_MGROUP(SHARPD, "sharpd")
zebra_capabilities_t _caps_p[] = {
};
@@ -125,7 +124,13 @@ FRR_DAEMON_INFO(sharpd, SHARP, .vty_port = SHARP_VTY_PORT,
.privs = &sharp_privs, .yang_modules = sharpd_yang_modules,
.n_yang_modules = array_size(sharpd_yang_modules), )
-extern void sharp_vty_init(void);
+struct sharp_global sg;
+
+static void sharp_global_init(void)
+{
+ memset(&sg, 0, sizeof(sg));
+ sg.nhs = list_new();
+}
int main(int argc, char **argv, char **envp)
{
@@ -151,6 +156,8 @@ int main(int argc, char **argv, char **envp)
master = frr_init();
+ sharp_global_init();
+
nexthop_group_init(NULL, NULL, NULL, NULL);
vrf_init(NULL, NULL, NULL, NULL, NULL);
diff --git a/sharpd/sharp_nht.c b/sharpd/sharp_nht.c
new file mode 100644
index 0000000000..174f186863
--- /dev/null
+++ b/sharpd/sharp_nht.c
@@ -0,0 +1,67 @@
+/*
+ * SHARP - code to track nexthops
+ * Copyright (C) Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <zebra.h>
+
+#include "memory.h"
+#include "nexthop.h"
+#include "nexthop_group.h"
+#include "vty.h"
+
+#include "sharp_nht.h"
+#include "sharp_globals.h"
+
+DEFINE_MTYPE_STATIC(SHARPD, NH_TRACKER, "Nexthop Tracker")
+
+struct sharp_nh_tracker *sharp_nh_tracker_get(struct prefix *p)
+{
+ struct listnode *node;
+ struct sharp_nh_tracker *nht;
+
+ for (ALL_LIST_ELEMENTS_RO(sg.nhs, node, nht)) {
+ if (prefix_same(&nht->p, p))
+ break;
+ }
+
+ if (nht)
+ return nht;
+
+ nht = XCALLOC(MTYPE_NH_TRACKER, sizeof(*nht));
+ prefix_copy(&nht->p, p);
+
+ listnode_add(sg.nhs, nht);
+ return nht;
+}
+
+void sharp_nh_tracker_dump(struct vty *vty)
+{
+ struct listnode *node;
+ struct sharp_nh_tracker *nht;
+
+ for (ALL_LIST_ELEMENTS_RO(sg.nhs, node, nht)) {
+ char buf[PREFIX_STRLEN];
+
+ vty_out(vty, "%s: Nexthops: %u Updates: %u\n",
+ prefix2str(&nht->p, buf, sizeof(buf)),
+ nht->nhop_num,
+ nht->updates);
+ }
+}
diff --git a/sharpd/sharp_nht.h b/sharpd/sharp_nht.h
new file mode 100644
index 0000000000..0b00774a81
--- /dev/null
+++ b/sharpd/sharp_nht.h
@@ -0,0 +1,38 @@
+/*
+ * SHARP - code to track nexthops
+ * Copyright (C) Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef __SHARP_NHT_H__
+#define __SHARP_NHT_H__
+
+struct sharp_nh_tracker {
+ /* What are we watching */
+ struct prefix p;
+
+ /* Number of valid nexthops */
+ uint32_t nhop_num;
+
+ uint32_t updates;
+};
+
+extern struct sharp_nh_tracker *sharp_nh_tracker_get(struct prefix *p);
+
+extern void sharp_nh_tracker_dump(struct vty *vty);
+#endif
diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c
index 86c8bfe1c2..0c02bd304d 100644
--- a/sharpd/sharp_vty.c
+++ b/sharpd/sharp_vty.c
@@ -30,30 +30,21 @@
#include "zclient.h"
#include "nexthop_group.h"
+#include "sharpd/sharp_globals.h"
#include "sharpd/sharp_zebra.h"
+#include "sharpd/sharp_nht.h"
#include "sharpd/sharp_vty.h"
#ifndef VTYSH_EXTRACT_PL
#include "sharpd/sharp_vty_clippy.c"
#endif
-extern uint32_t total_routes;
-extern uint32_t installed_routes;
-extern uint32_t removed_routes;
-
-uint8_t inst;
-struct prefix prefix;
-struct prefix orig_prefix;
-struct nexthop nhop;
-struct nexthop_group nhop_group;
-uint32_t rts;
-int32_t repeat;
-
DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd,
- "sharp watch nexthop X:X::X:X$nhop",
+ "sharp watch nexthop X:X::X:X$nhop [connected$connected]",
"Sharp routing Protocol\n"
"Watch for changes\n"
"Watch for nexthop changes\n"
- "The v6 nexthop to signal for watching\n")
+ "The v6 nexthop to signal for watching\n"
+ "Should the route be connected\n")
{
struct prefix p;
@@ -63,17 +54,19 @@ DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd,
memcpy(&p.u.prefix6, &nhop, 16);
p.family = AF_INET6;
- sharp_zebra_nexthop_watch(&p, true);
+ sharp_nh_tracker_get(&p);
+ sharp_zebra_nexthop_watch(&p, true, !!connected);
return CMD_SUCCESS;
}
DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd,
- "sharp watch nexthop A.B.C.D$nhop",
+ "sharp watch nexthop A.B.C.D$nhop [connected$connected]",
"Sharp routing Protocol\n"
"Watch for changes\n"
"Watch for nexthop changes\n"
- "The v4 nexthop to signal for watching\n")
+ "The v4 nexthop to signal for watching\n"
+ "Should the route be connected\n")
{
struct prefix p;
@@ -83,7 +76,41 @@ DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd,
p.u.prefix4 = nhop;
p.family = AF_INET;
- sharp_zebra_nexthop_watch(&p, true);
+ sharp_nh_tracker_get(&p);
+ sharp_zebra_nexthop_watch(&p, true, !!connected);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(sharp_nht_data_dump,
+ sharp_nht_data_dump_cmd,
+ "sharp data nexthop",
+ "Sharp routing Protocol\n"
+ "Nexthop information\n"
+ "Data Dump\n")
+{
+ sharp_nh_tracker_dump(vty);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (install_routes_data_dump,
+ install_routes_data_dump_cmd,
+ "sharp data route",
+ "Sharp routing Protocol\n"
+ "Data about what is going on\n"
+ "Route Install/Removal Information\n")
+{
+ char buf[PREFIX_STRLEN];
+ struct timeval r;
+
+ timersub(&sg.r.t_end, &sg.r.t_start, &r);
+ vty_out(vty, "Prefix: %s Total: %u %u %u Time: %ld.%ld\n",
+ prefix2str(&sg.r.orig_prefix, buf, sizeof(buf)),
+ sg.r.total_routes,
+ sg.r.installed_routes,
+ sg.r.removed_routes,
+ r.tv_sec, r.tv_usec);
return CMD_SUCCESS;
}
@@ -107,18 +134,21 @@ DEFPY (install_routes,
"Should we repeat this command\n"
"How many times to repeat this command\n")
{
- total_routes = routes;
- installed_routes = 0;
+ struct prefix prefix;
+ uint32_t rts;
+
+ sg.r.total_routes = routes;
+ sg.r.installed_routes = 0;
if (rpt >= 2)
- repeat = rpt * 2;
+ sg.r.repeat = rpt * 2;
else
- repeat = 0;
+ sg.r.repeat = 0;
memset(&prefix, 0, sizeof(prefix));
- memset(&orig_prefix, 0, sizeof(orig_prefix));
- memset(&nhop, 0, sizeof(nhop));
- memset(&nhop_group, 0, sizeof(nhop_group));
+ memset(&sg.r.orig_prefix, 0, sizeof(sg.r.orig_prefix));
+ memset(&sg.r.nhop, 0, sizeof(sg.r.nhop));
+ memset(&sg.r.nhop_group, 0, sizeof(sg.r.nhop_group));
if (start4.s_addr != 0) {
prefix.family = AF_INET;
@@ -129,7 +159,7 @@ DEFPY (install_routes,
prefix.prefixlen = 128;
prefix.u.prefix6 = start6;
}
- orig_prefix = prefix;
+ sg.r.orig_prefix = prefix;
if (nexthop_group) {
struct nexthop_group_cmd *nhgc = nhgc_find(nexthop_group);
@@ -140,22 +170,22 @@ DEFPY (install_routes,
return CMD_WARNING;
}
- nhop_group.nexthop = nhgc->nhg.nexthop;
+ sg.r.nhop_group.nexthop = nhgc->nhg.nexthop;
} else {
if (nexthop4.s_addr != INADDR_ANY) {
- nhop.gate.ipv4 = nexthop4;
- nhop.type = NEXTHOP_TYPE_IPV4;
+ sg.r.nhop.gate.ipv4 = nexthop4;
+ sg.r.nhop.type = NEXTHOP_TYPE_IPV4;
} else {
- nhop.gate.ipv6 = nexthop6;
- nhop.type = NEXTHOP_TYPE_IPV6;
+ sg.r.nhop.gate.ipv6 = nexthop6;
+ sg.r.nhop.type = NEXTHOP_TYPE_IPV6;
}
- nhop_group.nexthop = &nhop;
+ sg.r.nhop_group.nexthop = &sg.r.nhop;
}
- inst = instance;
+ sg.r.inst = instance;
rts = routes;
- sharp_install_routes_helper(&prefix, inst, &nhop_group, rts);
+ sharp_install_routes_helper(&prefix, sg.r.inst, &sg.r.nhop_group, rts);
return CMD_SUCCESS;
}
@@ -202,8 +232,11 @@ DEFPY (remove_routes,
"instance to use\n"
"Value of instance\n")
{
- total_routes = routes;
- removed_routes = 0;
+ struct prefix prefix;
+
+ sg.r.total_routes = routes;
+ sg.r.removed_routes = 0;
+ uint32_t rts;
memset(&prefix, 0, sizeof(prefix));
@@ -217,9 +250,9 @@ DEFPY (remove_routes,
prefix.u.prefix6 = start6;
}
- inst = instance;
+ sg.r.inst = instance;
rts = routes;
- sharp_remove_routes_helper(&prefix, inst, rts);
+ sharp_remove_routes_helper(&prefix, sg.r.inst, rts);
return CMD_SUCCESS;
}
@@ -238,9 +271,11 @@ DEFUN_NOSH (show_debugging_sharpd,
void sharp_vty_init(void)
{
+ install_element(ENABLE_NODE, &install_routes_data_dump_cmd);
install_element(ENABLE_NODE, &install_routes_cmd);
install_element(ENABLE_NODE, &remove_routes_cmd);
install_element(ENABLE_NODE, &vrf_label_cmd);
+ install_element(ENABLE_NODE, &sharp_nht_data_dump_cmd);
install_element(ENABLE_NODE, &watch_nexthop_v6_cmd);
install_element(ENABLE_NODE, &watch_nexthop_v4_cmd);
diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c
index c9f333e34b..30e616a057 100644
--- a/sharpd/sharp_zebra.c
+++ b/sharpd/sharp_zebra.c
@@ -36,6 +36,8 @@
#include "nexthop.h"
#include "nexthop_group.h"
+#include "sharp_globals.h"
+#include "sharp_nht.h"
#include "sharp_zebra.h"
/* Zebra structure to hold current status. */
@@ -129,16 +131,6 @@ static int interface_state_down(int command, struct zclient *zclient,
return 0;
}
-static struct timeval t_start;
-static struct timeval t_end;
-extern uint32_t total_routes;
-extern uint32_t installed_routes;
-extern uint32_t removed_routes;
-extern int32_t repeat;
-extern struct prefix orig_prefix;
-extern struct nexthop_group nhop_group;
-extern uint8_t inst;
-
void sharp_install_routes_helper(struct prefix *p, uint8_t instance,
struct nexthop_group *nhg,
uint32_t routes)
@@ -154,7 +146,7 @@ void sharp_install_routes_helper(struct prefix *p, uint8_t instance,
} else
temp = ntohl(p->u.val32[3]);
- monotime(&t_start);
+ monotime(&sg.r.t_start);
for (i = 0; i < routes; i++) {
route_add(p, (uint8_t)instance, nhg);
if (v4)
@@ -178,7 +170,7 @@ void sharp_remove_routes_helper(struct prefix *p, uint8_t instance,
} else
temp = ntohl(p->u.val32[3]);
- monotime(&t_start);
+ monotime(&sg.r.t_start);
for (i = 0; i < routes; i++) {
route_delete(p, (uint8_t)instance);
if (v4)
@@ -190,21 +182,21 @@ void sharp_remove_routes_helper(struct prefix *p, uint8_t instance,
static void handle_repeated(bool installed)
{
- struct prefix p = orig_prefix;
- repeat--;
+ struct prefix p = sg.r.orig_prefix;
+ sg.r.repeat--;
- if (repeat <= 0)
+ if (sg.r.repeat <= 0)
return;
if (installed) {
- removed_routes = 0;
- sharp_remove_routes_helper(&p, inst, total_routes);
+ sg.r.removed_routes = 0;
+ sharp_remove_routes_helper(&p, sg.r.inst, sg.r.total_routes);
}
- if (!installed) {
- installed_routes = 0;
- sharp_install_routes_helper(&p, inst, &nhop_group,
- total_routes);
+ if (installed) {
+ sg.r.installed_routes = 0;
+ sharp_install_routes_helper(&p, sg.r.inst, &sg.r.nhop_group,
+ sg.r.total_routes);
}
}
@@ -221,10 +213,10 @@ static int route_notify_owner(int command, struct zclient *zclient,
switch (note) {
case ZAPI_ROUTE_INSTALLED:
- installed_routes++;
- if (total_routes == installed_routes) {
- monotime(&t_end);
- timersub(&t_end, &t_start, &r);
+ sg.r.installed_routes++;
+ if (sg.r.total_routes == sg.r.installed_routes) {
+ monotime(&sg.r.t_end);
+ timersub(&sg.r.t_end, &sg.r.t_start, &r);
zlog_debug("Installed All Items %ld.%ld", r.tv_sec,
r.tv_usec);
handle_repeated(true);
@@ -237,10 +229,10 @@ static int route_notify_owner(int command, struct zclient *zclient,
zlog_debug("Better Admin Distance won over us");
break;
case ZAPI_ROUTE_REMOVED:
- removed_routes++;
- if (total_routes == removed_routes) {
- monotime(&t_end);
- timersub(&t_end, &t_start, &r);
+ sg.r.removed_routes++;
+ if (sg.r.total_routes == sg.r.removed_routes) {
+ monotime(&sg.r.t_end);
+ timersub(&sg.r.t_end, &sg.r.t_start, &r);
zlog_debug("Removed all Items %ld.%ld", r.tv_sec,
r.tv_usec);
handle_repeated(false);
@@ -328,14 +320,14 @@ void route_delete(struct prefix *p, uint8_t instance)
return;
}
-void sharp_zebra_nexthop_watch(struct prefix *p, bool watch)
+void sharp_zebra_nexthop_watch(struct prefix *p, bool watch, bool connected)
{
int command = ZEBRA_NEXTHOP_REGISTER;
if (!watch)
command = ZEBRA_NEXTHOP_UNREGISTER;
- if (zclient_send_rnh(zclient, command, p, true, VRF_DEFAULT) < 0)
+ if (zclient_send_rnh(zclient, command, p, connected, VRF_DEFAULT) < 0)
zlog_warn("%s: Failure to send nexthop to zebra",
__PRETTY_FUNCTION__);
}
@@ -343,6 +335,7 @@ void sharp_zebra_nexthop_watch(struct prefix *p, bool watch)
static int sharp_nexthop_update(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
+ struct sharp_nh_tracker *nht;
struct zapi_route nhr;
char buf[PREFIX_STRLEN];
int i;
@@ -355,6 +348,11 @@ static int sharp_nexthop_update(int command, struct zclient *zclient,
zlog_debug("Received update for %s",
prefix2str(&nhr.prefix, buf, sizeof(buf)));
+
+ nht = sharp_nh_tracker_get(&nhr.prefix);
+ nht->nhop_num = nhr.nexthop_num;
+ nht->updates++;
+
for (i = 0; i < nhr.nexthop_num; i++) {
struct zapi_nexthop *znh = &nhr.nexthops[i];
diff --git a/sharpd/sharp_zebra.h b/sharpd/sharp_zebra.h
index 7326056cae..7e6ac7670b 100644
--- a/sharpd/sharp_zebra.h
+++ b/sharpd/sharp_zebra.h
@@ -28,7 +28,8 @@ extern void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label);
extern void route_add(struct prefix *p, uint8_t instance,
struct nexthop_group *nhg);
extern void route_delete(struct prefix *p, uint8_t instance);
-extern void sharp_zebra_nexthop_watch(struct prefix *p, bool watch);
+extern void sharp_zebra_nexthop_watch(struct prefix *p, bool watch,
+ bool connected);
extern void sharp_install_routes_helper(struct prefix *p, uint8_t instance,
struct nexthop_group *nhg,
diff --git a/sharpd/subdir.am b/sharpd/subdir.am
index c00d90ea0a..4a9028f6fe 100644
--- a/sharpd/subdir.am
+++ b/sharpd/subdir.am
@@ -11,12 +11,15 @@ man8 += $(MANBUILD)/sharpd.8
endif
sharpd_libsharp_a_SOURCES = \
+ sharpd/sharp_nht.c \
sharpd/sharp_zebra.c \
sharpd/sharp_vty.c \
# end
noinst_HEADERS += \
+ sharpd/sharp_nht.h \
sharpd/sharp_vty.h \
+ sharpd/sharp_globals.h \
sharpd/sharp_zebra.h \
# end
diff --git a/tests/Makefile.in b/tests/Makefile.in
new file mode 100644
index 0000000000..29d903e70a
--- /dev/null
+++ b/tests/Makefile.in
@@ -0,0 +1,1338 @@
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# Automake fragment intended to be shared by Makefile.am files in the
+# tree.
+#
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+check_PROGRAMS = lib/test_buffer$(EXEEXT) lib/test_checksum$(EXEEXT) \
+ lib/test_heavy_thread$(EXEEXT) lib/test_heavy_wq$(EXEEXT) \
+ lib/test_heavy$(EXEEXT) lib/test_memory$(EXEEXT) \
+ lib/test_nexthop_iter$(EXEEXT) lib/test_privs$(EXEEXT) \
+ lib/test_ringbuf$(EXEEXT) lib/test_srcdest_table$(EXEEXT) \
+ lib/test_segv$(EXEEXT) lib/test_sig$(EXEEXT) \
+ lib/test_stream$(EXEEXT) lib/test_table$(EXEEXT) \
+ lib/test_timer_correctness$(EXEEXT) \
+ lib/test_timer_performance$(EXEEXT) lib/test_ttable$(EXEEXT) \
+ lib/cli/test_cli$(EXEEXT) lib/cli/test_commands$(EXEEXT) \
+ $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
+ $(am__EXEEXT_4)
+@ZEROMQ_TRUE@am__append_1 = \
+@ZEROMQ_TRUE@ lib/test_zmq \
+@ZEROMQ_TRUE@ # end
+
+subdir = tests
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_compare_version.m4 \
+ $(top_srcdir)/m4/ax_pthread.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/pkg.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+@BGPD_TRUE@am__EXEEXT_1 = bgpd/test_aspath$(EXEEXT) \
+@BGPD_TRUE@ bgpd/test_capability$(EXEEXT) \
+@BGPD_TRUE@ bgpd/test_packet$(EXEEXT) \
+@BGPD_TRUE@ bgpd/test_ecommunity$(EXEEXT) \
+@BGPD_TRUE@ bgpd/test_mp_attr$(EXEEXT) bgpd/test_mpath$(EXEEXT)
+@ISISD_TRUE@@SOLARIS_FALSE@am__EXEEXT_2 = \
+@ISISD_TRUE@@SOLARIS_FALSE@ isisd/test_fuzz_isis_tlv$(EXEEXT) \
+@ISISD_TRUE@@SOLARIS_FALSE@ isisd/test_isis_vertex_queue$(EXEEXT)
+@OSPF6D_TRUE@am__EXEEXT_3 = ospf6d/test_lsdb$(EXEEXT)
+@ZEROMQ_TRUE@am__EXEEXT_4 = lib/test_zmq$(EXEEXT)
+am__dirstamp = $(am__leading_dot)dirstamp
+am_bgpd_test_aspath_OBJECTS = bgpd/test_aspath.$(OBJEXT)
+bgpd_test_aspath_OBJECTS = $(am_bgpd_test_aspath_OBJECTS)
+@ENABLE_BGP_VNC_TRUE@am__DEPENDENCIES_1 = \
+@ENABLE_BGP_VNC_TRUE@ @top_builddir@/$(LIBRFP)/librfp.a
+am__DEPENDENCIES_2 = ../lib/libfrr.la
+am__DEPENDENCIES_3 = ../bgpd/libbgp.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_2)
+bgpd_test_aspath_DEPENDENCIES = $(am__DEPENDENCIES_3)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+am_bgpd_test_capability_OBJECTS = bgpd/test_capability.$(OBJEXT)
+bgpd_test_capability_OBJECTS = $(am_bgpd_test_capability_OBJECTS)
+bgpd_test_capability_DEPENDENCIES = $(am__DEPENDENCIES_3)
+am_bgpd_test_ecommunity_OBJECTS = bgpd/test_ecommunity.$(OBJEXT)
+bgpd_test_ecommunity_OBJECTS = $(am_bgpd_test_ecommunity_OBJECTS)
+bgpd_test_ecommunity_DEPENDENCIES = $(am__DEPENDENCIES_3)
+am_bgpd_test_mp_attr_OBJECTS = bgpd/test_mp_attr.$(OBJEXT)
+bgpd_test_mp_attr_OBJECTS = $(am_bgpd_test_mp_attr_OBJECTS)
+bgpd_test_mp_attr_DEPENDENCIES = $(am__DEPENDENCIES_3)
+am_bgpd_test_mpath_OBJECTS = bgpd/test_mpath.$(OBJEXT)
+bgpd_test_mpath_OBJECTS = $(am_bgpd_test_mpath_OBJECTS)
+bgpd_test_mpath_DEPENDENCIES = $(am__DEPENDENCIES_3)
+am_bgpd_test_packet_OBJECTS = bgpd/test_packet.$(OBJEXT)
+bgpd_test_packet_OBJECTS = $(am_bgpd_test_packet_OBJECTS)
+bgpd_test_packet_DEPENDENCIES = $(am__DEPENDENCIES_3)
+am_isisd_test_fuzz_isis_tlv_OBJECTS = \
+ isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.$(OBJEXT)
+isisd_test_fuzz_isis_tlv_OBJECTS = \
+ $(am_isisd_test_fuzz_isis_tlv_OBJECTS)
+am__DEPENDENCIES_4 = ../isisd/libisis.a $(am__DEPENDENCIES_2)
+isisd_test_fuzz_isis_tlv_DEPENDENCIES = $(am__DEPENDENCIES_4)
+am_isisd_test_isis_vertex_queue_OBJECTS = \
+ isisd/test_isis_vertex_queue.$(OBJEXT)
+isisd_test_isis_vertex_queue_OBJECTS = \
+ $(am_isisd_test_isis_vertex_queue_OBJECTS)
+isisd_test_isis_vertex_queue_DEPENDENCIES = $(am__DEPENDENCIES_4)
+am_lib_cli_test_cli_OBJECTS = lib/cli/test_cli.$(OBJEXT) \
+ lib/cli/common_cli.$(OBJEXT)
+lib_cli_test_cli_OBJECTS = $(am_lib_cli_test_cli_OBJECTS)
+lib_cli_test_cli_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_cli_test_commands_OBJECTS = \
+ lib/cli/test_commands_defun.$(OBJEXT) \
+ lib/cli/test_commands.$(OBJEXT) helpers/c/prng.$(OBJEXT)
+lib_cli_test_commands_OBJECTS = $(am_lib_cli_test_commands_OBJECTS)
+lib_cli_test_commands_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_buffer_OBJECTS = lib/test_buffer.$(OBJEXT)
+lib_test_buffer_OBJECTS = $(am_lib_test_buffer_OBJECTS)
+lib_test_buffer_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_checksum_OBJECTS = lib/test_checksum.$(OBJEXT)
+lib_test_checksum_OBJECTS = $(am_lib_test_checksum_OBJECTS)
+lib_test_checksum_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_heavy_OBJECTS = lib/test_heavy.$(OBJEXT) \
+ helpers/c/main.$(OBJEXT)
+lib_test_heavy_OBJECTS = $(am_lib_test_heavy_OBJECTS)
+lib_test_heavy_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_heavy_thread_OBJECTS = lib/test_heavy_thread.$(OBJEXT) \
+ helpers/c/main.$(OBJEXT)
+lib_test_heavy_thread_OBJECTS = $(am_lib_test_heavy_thread_OBJECTS)
+lib_test_heavy_thread_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_heavy_wq_OBJECTS = lib/test_heavy_wq.$(OBJEXT) \
+ helpers/c/main.$(OBJEXT)
+lib_test_heavy_wq_OBJECTS = $(am_lib_test_heavy_wq_OBJECTS)
+lib_test_heavy_wq_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_memory_OBJECTS = lib/test_memory.$(OBJEXT)
+lib_test_memory_OBJECTS = $(am_lib_test_memory_OBJECTS)
+lib_test_memory_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_nexthop_iter_OBJECTS = lib/test_nexthop_iter.$(OBJEXT) \
+ helpers/c/prng.$(OBJEXT)
+lib_test_nexthop_iter_OBJECTS = $(am_lib_test_nexthop_iter_OBJECTS)
+lib_test_nexthop_iter_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_privs_OBJECTS = lib/test_privs.$(OBJEXT)
+lib_test_privs_OBJECTS = $(am_lib_test_privs_OBJECTS)
+lib_test_privs_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_ringbuf_OBJECTS = lib/test_ringbuf.$(OBJEXT)
+lib_test_ringbuf_OBJECTS = $(am_lib_test_ringbuf_OBJECTS)
+lib_test_ringbuf_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_segv_OBJECTS = lib/test_segv.$(OBJEXT)
+lib_test_segv_OBJECTS = $(am_lib_test_segv_OBJECTS)
+lib_test_segv_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_sig_OBJECTS = lib/test_sig.$(OBJEXT)
+lib_test_sig_OBJECTS = $(am_lib_test_sig_OBJECTS)
+lib_test_sig_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_srcdest_table_OBJECTS = lib/test_srcdest_table.$(OBJEXT) \
+ helpers/c/prng.$(OBJEXT)
+lib_test_srcdest_table_OBJECTS = $(am_lib_test_srcdest_table_OBJECTS)
+lib_test_srcdest_table_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_stream_OBJECTS = lib/test_stream.$(OBJEXT)
+lib_test_stream_OBJECTS = $(am_lib_test_stream_OBJECTS)
+lib_test_stream_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_table_OBJECTS = lib/test_table.$(OBJEXT)
+lib_test_table_OBJECTS = $(am_lib_test_table_OBJECTS)
+lib_test_table_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_timer_correctness_OBJECTS = \
+ lib/test_timer_correctness.$(OBJEXT) helpers/c/prng.$(OBJEXT)
+lib_test_timer_correctness_OBJECTS = \
+ $(am_lib_test_timer_correctness_OBJECTS)
+lib_test_timer_correctness_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_timer_performance_OBJECTS = \
+ lib/test_timer_performance.$(OBJEXT) helpers/c/prng.$(OBJEXT)
+lib_test_timer_performance_OBJECTS = \
+ $(am_lib_test_timer_performance_OBJECTS)
+lib_test_timer_performance_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_ttable_OBJECTS = lib/test_ttable.$(OBJEXT)
+lib_test_ttable_OBJECTS = $(am_lib_test_ttable_OBJECTS)
+lib_test_ttable_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_zmq_OBJECTS = lib/lib_test_zmq-test_zmq.$(OBJEXT)
+lib_test_zmq_OBJECTS = $(am_lib_test_zmq_OBJECTS)
+am__DEPENDENCIES_5 =
+lib_test_zmq_DEPENDENCIES = ../lib/libfrrzmq.la $(am__DEPENDENCIES_2) \
+ $(am__DEPENDENCIES_5)
+lib_test_zmq_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(lib_test_zmq_CFLAGS) \
+ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+am_ospf6d_test_lsdb_OBJECTS = ospf6d/test_lsdb.$(OBJEXT) \
+ lib/cli/common_cli.$(OBJEXT)
+ospf6d_test_lsdb_OBJECTS = $(am_ospf6d_test_lsdb_OBJECTS)
+am__DEPENDENCIES_6 = ../ospf6d/libospf6.a $(am__DEPENDENCIES_2)
+ospf6d_test_lsdb_DEPENDENCIES = $(am__DEPENDENCIES_6)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(bgpd_test_aspath_SOURCES) $(bgpd_test_capability_SOURCES) \
+ $(bgpd_test_ecommunity_SOURCES) $(bgpd_test_mp_attr_SOURCES) \
+ $(bgpd_test_mpath_SOURCES) $(bgpd_test_packet_SOURCES) \
+ $(isisd_test_fuzz_isis_tlv_SOURCES) \
+ $(isisd_test_isis_vertex_queue_SOURCES) \
+ $(lib_cli_test_cli_SOURCES) $(lib_cli_test_commands_SOURCES) \
+ $(lib_test_buffer_SOURCES) $(lib_test_checksum_SOURCES) \
+ $(lib_test_heavy_SOURCES) $(lib_test_heavy_thread_SOURCES) \
+ $(lib_test_heavy_wq_SOURCES) $(lib_test_memory_SOURCES) \
+ $(lib_test_nexthop_iter_SOURCES) $(lib_test_privs_SOURCES) \
+ $(lib_test_ringbuf_SOURCES) $(lib_test_segv_SOURCES) \
+ $(lib_test_sig_SOURCES) $(lib_test_srcdest_table_SOURCES) \
+ $(lib_test_stream_SOURCES) $(lib_test_table_SOURCES) \
+ $(lib_test_timer_correctness_SOURCES) \
+ $(lib_test_timer_performance_SOURCES) \
+ $(lib_test_ttable_SOURCES) $(lib_test_zmq_SOURCES) \
+ $(ospf6d_test_lsdb_SOURCES)
+DIST_SOURCES = $(bgpd_test_aspath_SOURCES) \
+ $(bgpd_test_capability_SOURCES) \
+ $(bgpd_test_ecommunity_SOURCES) $(bgpd_test_mp_attr_SOURCES) \
+ $(bgpd_test_mpath_SOURCES) $(bgpd_test_packet_SOURCES) \
+ $(isisd_test_fuzz_isis_tlv_SOURCES) \
+ $(isisd_test_isis_vertex_queue_SOURCES) \
+ $(lib_cli_test_cli_SOURCES) $(lib_cli_test_commands_SOURCES) \
+ $(lib_test_buffer_SOURCES) $(lib_test_checksum_SOURCES) \
+ $(lib_test_heavy_SOURCES) $(lib_test_heavy_thread_SOURCES) \
+ $(lib_test_heavy_wq_SOURCES) $(lib_test_memory_SOURCES) \
+ $(lib_test_nexthop_iter_SOURCES) $(lib_test_privs_SOURCES) \
+ $(lib_test_ringbuf_SOURCES) $(lib_test_segv_SOURCES) \
+ $(lib_test_sig_SOURCES) $(lib_test_srcdest_table_SOURCES) \
+ $(lib_test_stream_SOURCES) $(lib_test_table_SOURCES) \
+ $(lib_test_timer_correctness_SOURCES) \
+ $(lib_test_timer_performance_SOURCES) \
+ $(lib_test_ttable_SOURCES) $(lib_test_zmq_SOURCES) \
+ $(ospf6d_test_lsdb_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/../common.am $(srcdir)/Makefile.in \
+ $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BGPD = @BGPD@
+BISON_CLOSEBRACE = @BISON_CLOSEBRACE@
+BISON_OPENBRACE = @BISON_OPENBRACE@
+BISON_VERBOSE = @BISON_VERBOSE@
+CARES_CFLAGS = @CARES_CFLAGS@
+CARES_LIBS = @CARES_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFG_MODULE = @CFG_MODULE@
+CFG_SBIN = @CFG_SBIN@
+CFG_STATE = @CFG_STATE@
+CFG_SYSCONF = @CFG_SYSCONF@
+CFLAGS = @CFLAGS@
+CONFDATE = @CONFDATE@
+CONFIG_ARGS = @CONFIG_ARGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CURSES = @CURSES@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\"
+DEPDIR = @DEPDIR@
+DFLT_NAME = @DFLT_NAME@
+DLLTOOL = @DLLTOOL@
+DOC = @DOC@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@
+HOSTTOOLS = @HOSTTOOLS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCAP = @LIBCAP@
+LIBM = @LIBM@
+LIBOBJS = @LIBOBJS@
+LIBPAM = @LIBPAM@
+LIBREADLINE = @LIBREADLINE@
+LIBRFP = @LIBRFP@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NETSNMP_CONFIG = @NETSNMP_CONFIG@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_EXTRAVERSION = @PACKAGE_EXTRAVERSION@
+PACKAGE_FULLNAME = @PACKAGE_FULLNAME@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROTOBUF_C_CFLAGS = @PROTOBUF_C_CFLAGS@
+PROTOBUF_C_LIBS = @PROTOBUF_C_LIBS@
+PROTOC_C = @PROTOC_C@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+PYTHONCONFIG = @PYTHONCONFIG@
+PYTHON_CFLAGS = @PYTHON_CFLAGS@
+PYTHON_LIBS = @PYTHON_LIBS@
+RANLIB = @RANLIB@
+RFPINC = @RFPINC@
+RFPTEST = @RFPTEST@
+RTRLIB_CFLAGS = @RTRLIB_CFLAGS@
+RTRLIB_LIBS = @RTRLIB_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SNMP_CFLAGS = @SNMP_CFLAGS@
+SNMP_LIBS = @SNMP_LIBS@
+SOLARIS = @SOLARIS@
+STRIP = @STRIP@
+VERSION = @VERSION@
+VNC_RFP_PATH = @VNC_RFP_PATH@
+VTYSH = @VTYSH@
+WERROR = @WERROR@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZEROMQ_CFLAGS = @ZEROMQ_CFLAGS@
+ZEROMQ_LIBS = @ZEROMQ_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_PYTHONCONFIG = @ac_ct_PYTHONCONFIG@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+enable_group = @enable_group@
+enable_user = @enable_user@
+enable_vty_group = @enable_vty_group@
+exampledir = @exampledir@
+exec_prefix = @exec_prefix@
+frr_statedir = @frr_statedir@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgsrcrcdir = @pkgsrcrcdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_V_CLIPPY = $(am__v_CLIPPY_$(V))
+am__v_CLIPPY_ = $(am__v_CLIPPY_$(AM_DEFAULT_VERBOSITY))
+am__v_CLIPPY_0 = @echo " CLIPPY " $@;
+am__v_CLIPPY_1 =
+CLIPPY_DEPS = $(HOSTTOOLS)lib/clippy $(top_srcdir)/python/clidef.py
+SUFFIXES = _clippy.c .proto .pb-c.c .pb-c.h .pb.h
+
+# Uncomment to use an non-system version of libprotobuf-c.
+#
+# Q_PROTOBUF_C_CLIENT_INCLUDES = -I$(top_srcdir)/third-party/protobuf-c/src
+# Q_PROTOBUF_C_CLIENT_LDOPTS = $(top_builddir)/third-party/protobuf-c/src/libprotobuf-c.la
+@HAVE_PROTOBUF_TRUE@Q_PROTOBUF_C_CLIENT_INCLUDES =
+@HAVE_PROTOBUF_TRUE@Q_PROTOBUF_C_CLIENT_LDOPTS = -lprotobuf-c
+@HAVE_PROTOBUF_TRUE@Q_PROTOC = protoc
+@HAVE_PROTOBUF_TRUE@Q_PROTOC_C = protoc-c
+@HAVE_PROTOBUF_TRUE@AM_V_PROTOC_C = $(am__v_PROTOC_C_$(V))
+@HAVE_PROTOBUF_TRUE@am__v_PROTOC_C_ = $(am__v_PROTOC_C_$(AM_DEFAULT_VERBOSITY))
+@HAVE_PROTOBUF_TRUE@am__v_PROTOC_C_0 = @echo " PROTOC_C" $@;
+@HAVE_PROTOBUF_TRUE@am__v_PROTOC_C_1 =
+
+#
+# Information about how to link to various libraries.
+#
+@HAVE_PROTOBUF_TRUE@Q_FRR_PB_CLIENT_LDOPTS = $(top_srcdir)/qpb/libfrr_pb.la $(Q_PROTOBUF_C_CLIENT_LDOPTS)
+@HAVE_PROTOBUF_TRUE@Q_FPM_PB_CLIENT_LDOPTS = $(top_srcdir)/fpm/libfrrfpm_pb.la $(Q_FRR_PB_CLIENT_LDOPTS)
+AUTOMAKE_OPTIONS = subdir-objects
+AM_CPPFLAGS = \
+ -I.. \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/lib \
+ -I$(top_builddir)/lib \
+ -I$(top_srcdir)/tests/helpers/c \
+ -I$(top_builddir)/tests/helpers/c \
+ -O
+
+@BGPD_FALSE@TESTS_BGPD =
+@BGPD_TRUE@TESTS_BGPD = \
+@BGPD_TRUE@ bgpd/test_aspath \
+@BGPD_TRUE@ bgpd/test_capability \
+@BGPD_TRUE@ bgpd/test_packet \
+@BGPD_TRUE@ bgpd/test_ecommunity \
+@BGPD_TRUE@ bgpd/test_mp_attr \
+@BGPD_TRUE@ bgpd/test_mpath
+
+@ISISD_FALSE@TESTS_ISISD =
+@ISISD_TRUE@@SOLARIS_FALSE@TESTS_ISISD = \
+@ISISD_TRUE@@SOLARIS_FALSE@ isisd/test_fuzz_isis_tlv \
+@ISISD_TRUE@@SOLARIS_FALSE@ isisd/test_isis_vertex_queue \
+@ISISD_TRUE@@SOLARIS_FALSE@ # end
+
+@ISISD_TRUE@@SOLARIS_TRUE@TESTS_ISISD =
+@OSPF6D_FALSE@TESTS_OSPF6D =
+@OSPF6D_TRUE@TESTS_OSPF6D = \
+@OSPF6D_TRUE@ ospf6d/test_lsdb \
+@OSPF6D_TRUE@ # end
+
+@ENABLE_BGP_VNC_FALSE@BGP_VNC_RFP_LIB =
+@ENABLE_BGP_VNC_TRUE@BGP_VNC_RFP_LIB = @top_builddir@/$(LIBRFP)/librfp.a
+noinst_HEADERS = \
+ ./helpers/c/prng.h \
+ ./helpers/c/tests.h \
+ ./lib/cli/common_cli.h
+
+lib_test_buffer_SOURCES = lib/test_buffer.c
+lib_test_checksum_SOURCES = lib/test_checksum.c
+lib_test_heavy_thread_SOURCES = lib/test_heavy_thread.c helpers/c/main.c
+lib_test_heavy_wq_SOURCES = lib/test_heavy_wq.c helpers/c/main.c
+lib_test_heavy_SOURCES = lib/test_heavy.c helpers/c/main.c
+lib_test_memory_SOURCES = lib/test_memory.c
+lib_test_nexthop_iter_SOURCES = lib/test_nexthop_iter.c helpers/c/prng.c
+lib_test_privs_SOURCES = lib/test_privs.c
+lib_test_srcdest_table_SOURCES = lib/test_srcdest_table.c \
+ helpers/c/prng.c
+
+lib_test_ringbuf_SOURCES = lib/test_ringbuf.c
+lib_test_segv_SOURCES = lib/test_segv.c
+lib_test_sig_SOURCES = lib/test_sig.c
+lib_test_stream_SOURCES = lib/test_stream.c
+lib_test_table_SOURCES = lib/test_table.c
+lib_test_timer_correctness_SOURCES = lib/test_timer_correctness.c \
+ helpers/c/prng.c
+
+lib_test_timer_performance_SOURCES = lib/test_timer_performance.c \
+ helpers/c/prng.c
+
+lib_test_ttable_SOURCES = lib/test_ttable.c
+lib_test_zmq_SOURCES = lib/test_zmq.c
+lib_test_zmq_CFLAGS = $(AM_CFLAGS) $(ZEROMQ_CFLAGS)
+lib_cli_test_cli_SOURCES = lib/cli/test_cli.c lib/cli/common_cli.c
+lib_cli_test_commands_SOURCES = lib/cli/test_commands_defun.c \
+ lib/cli/test_commands.c \
+ helpers/c/prng.c
+
+bgpd_test_aspath_SOURCES = bgpd/test_aspath.c
+bgpd_test_capability_SOURCES = bgpd/test_capability.c
+bgpd_test_packet_SOURCES = bgpd/test_packet.c
+bgpd_test_ecommunity_SOURCES = bgpd/test_ecommunity.c
+bgpd_test_mp_attr_SOURCES = bgpd/test_mp_attr.c
+bgpd_test_mpath_SOURCES = bgpd/test_mpath.c
+isisd_test_fuzz_isis_tlv_SOURCES = isisd/test_fuzz_isis_tlv.c
+isisd_test_fuzz_isis_tlv_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_builddir)/tests/isisd
+isisd_test_isis_vertex_queue_SOURCES = isisd/test_isis_vertex_queue.c
+ospf6d_test_lsdb_SOURCES = ospf6d/test_lsdb.c lib/cli/common_cli.c
+ALL_TESTS_LDADD = ../lib/libfrr.la @LIBCAP@
+BGP_TEST_LDADD = ../bgpd/libbgp.a $(BGP_VNC_RFP_LIB) $(ALL_TESTS_LDADD) -lm
+ISISD_TEST_LDADD = ../isisd/libisis.a $(ALL_TESTS_LDADD)
+OSPF6_TEST_LDADD = ../ospf6d/libospf6.a $(ALL_TESTS_LDADD)
+lib_test_buffer_LDADD = $(ALL_TESTS_LDADD)
+lib_test_checksum_LDADD = $(ALL_TESTS_LDADD)
+lib_test_heavy_thread_LDADD = $(ALL_TESTS_LDADD) -lm
+lib_test_heavy_wq_LDADD = $(ALL_TESTS_LDADD) -lm
+lib_test_heavy_LDADD = $(ALL_TESTS_LDADD) -lm
+lib_test_memory_LDADD = $(ALL_TESTS_LDADD)
+lib_test_nexthop_iter_LDADD = $(ALL_TESTS_LDADD)
+lib_test_privs_LDADD = $(ALL_TESTS_LDADD)
+lib_test_ringbuf_LDADD = $(ALL_TESTS_LDADD)
+lib_test_srcdest_table_LDADD = $(ALL_TESTS_LDADD)
+lib_test_segv_LDADD = $(ALL_TESTS_LDADD)
+lib_test_sig_LDADD = $(ALL_TESTS_LDADD)
+lib_test_stream_LDADD = $(ALL_TESTS_LDADD)
+lib_test_table_LDADD = $(ALL_TESTS_LDADD) -lm
+lib_test_timer_correctness_LDADD = $(ALL_TESTS_LDADD)
+lib_test_timer_performance_LDADD = $(ALL_TESTS_LDADD)
+lib_test_ttable_LDADD = $(ALL_TESTS_LDADD)
+lib_test_zmq_LDADD = ../lib/libfrrzmq.la $(ALL_TESTS_LDADD) $(ZEROMQ_LIBS)
+lib_cli_test_cli_LDADD = $(ALL_TESTS_LDADD)
+lib_cli_test_commands_LDADD = $(ALL_TESTS_LDADD)
+bgpd_test_aspath_LDADD = $(BGP_TEST_LDADD)
+bgpd_test_capability_LDADD = $(BGP_TEST_LDADD)
+bgpd_test_packet_LDADD = $(BGP_TEST_LDADD)
+bgpd_test_ecommunity_LDADD = $(BGP_TEST_LDADD)
+bgpd_test_mp_attr_LDADD = $(BGP_TEST_LDADD)
+bgpd_test_mpath_LDADD = $(BGP_TEST_LDADD)
+isisd_test_fuzz_isis_tlv_LDADD = $(ISISD_TEST_LDADD)
+isisd_test_isis_vertex_queue_LDADD = $(ISISD_TEST_LDADD)
+ospf6d_test_lsdb_LDADD = $(OSPF6_TEST_LDADD)
+EXTRA_DIST = \
+ runtests.py \
+ bgpd/test_aspath.py \
+ bgpd/test_capability.py \
+ bgpd/test_ecommunity.py \
+ bgpd/test_mp_attr.py \
+ bgpd/test_mpath.py \
+ helpers/python/frrsix.py \
+ helpers/python/frrtest.py \
+ isisd/test_fuzz_isis_tlv.py \
+ isisd/test_fuzz_isis_tlv_tests.h.gz \
+ isisd/test_isis_vertex_queue.py \
+ lib/cli/test_commands.in \
+ lib/cli/test_commands.py \
+ lib/cli/test_commands.refout \
+ lib/cli/test_cli.in \
+ lib/cli/test_cli.py \
+ lib/cli/test_cli.refout \
+ lib/test_nexthop_iter.py \
+ lib/test_ringbuf.py \
+ lib/test_srcdest_table.py \
+ lib/test_stream.py \
+ lib/test_stream.refout \
+ lib/test_table.py \
+ lib/test_timer_correctness.py \
+ lib/test_ttable.py \
+ lib/test_ttable.refout \
+ ospf6d/test_lsdb.py \
+ ospf6d/test_lsdb.in \
+ ospf6d/test_lsdb.refout \
+ # end
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: _clippy.c .proto .pb-c.c .pb-c.h .pb.h .c .l .lo .o .obj .y
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(srcdir)/../common.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tests/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu tests/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+$(srcdir)/../common.am $(am__empty):
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkPROGRAMS:
+ @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+bgpd/$(am__dirstamp):
+ @$(MKDIR_P) bgpd
+ @: > bgpd/$(am__dirstamp)
+bgpd/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) bgpd/$(DEPDIR)
+ @: > bgpd/$(DEPDIR)/$(am__dirstamp)
+bgpd/test_aspath.$(OBJEXT): bgpd/$(am__dirstamp) \
+ bgpd/$(DEPDIR)/$(am__dirstamp)
+
+bgpd/test_aspath$(EXEEXT): $(bgpd_test_aspath_OBJECTS) $(bgpd_test_aspath_DEPENDENCIES) $(EXTRA_bgpd_test_aspath_DEPENDENCIES) bgpd/$(am__dirstamp)
+ @rm -f bgpd/test_aspath$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(bgpd_test_aspath_OBJECTS) $(bgpd_test_aspath_LDADD) $(LIBS)
+bgpd/test_capability.$(OBJEXT): bgpd/$(am__dirstamp) \
+ bgpd/$(DEPDIR)/$(am__dirstamp)
+
+bgpd/test_capability$(EXEEXT): $(bgpd_test_capability_OBJECTS) $(bgpd_test_capability_DEPENDENCIES) $(EXTRA_bgpd_test_capability_DEPENDENCIES) bgpd/$(am__dirstamp)
+ @rm -f bgpd/test_capability$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(bgpd_test_capability_OBJECTS) $(bgpd_test_capability_LDADD) $(LIBS)
+bgpd/test_ecommunity.$(OBJEXT): bgpd/$(am__dirstamp) \
+ bgpd/$(DEPDIR)/$(am__dirstamp)
+
+bgpd/test_ecommunity$(EXEEXT): $(bgpd_test_ecommunity_OBJECTS) $(bgpd_test_ecommunity_DEPENDENCIES) $(EXTRA_bgpd_test_ecommunity_DEPENDENCIES) bgpd/$(am__dirstamp)
+ @rm -f bgpd/test_ecommunity$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(bgpd_test_ecommunity_OBJECTS) $(bgpd_test_ecommunity_LDADD) $(LIBS)
+bgpd/test_mp_attr.$(OBJEXT): bgpd/$(am__dirstamp) \
+ bgpd/$(DEPDIR)/$(am__dirstamp)
+
+bgpd/test_mp_attr$(EXEEXT): $(bgpd_test_mp_attr_OBJECTS) $(bgpd_test_mp_attr_DEPENDENCIES) $(EXTRA_bgpd_test_mp_attr_DEPENDENCIES) bgpd/$(am__dirstamp)
+ @rm -f bgpd/test_mp_attr$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(bgpd_test_mp_attr_OBJECTS) $(bgpd_test_mp_attr_LDADD) $(LIBS)
+bgpd/test_mpath.$(OBJEXT): bgpd/$(am__dirstamp) \
+ bgpd/$(DEPDIR)/$(am__dirstamp)
+
+bgpd/test_mpath$(EXEEXT): $(bgpd_test_mpath_OBJECTS) $(bgpd_test_mpath_DEPENDENCIES) $(EXTRA_bgpd_test_mpath_DEPENDENCIES) bgpd/$(am__dirstamp)
+ @rm -f bgpd/test_mpath$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(bgpd_test_mpath_OBJECTS) $(bgpd_test_mpath_LDADD) $(LIBS)
+bgpd/test_packet.$(OBJEXT): bgpd/$(am__dirstamp) \
+ bgpd/$(DEPDIR)/$(am__dirstamp)
+
+bgpd/test_packet$(EXEEXT): $(bgpd_test_packet_OBJECTS) $(bgpd_test_packet_DEPENDENCIES) $(EXTRA_bgpd_test_packet_DEPENDENCIES) bgpd/$(am__dirstamp)
+ @rm -f bgpd/test_packet$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(bgpd_test_packet_OBJECTS) $(bgpd_test_packet_LDADD) $(LIBS)
+isisd/$(am__dirstamp):
+ @$(MKDIR_P) isisd
+ @: > isisd/$(am__dirstamp)
+isisd/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) isisd/$(DEPDIR)
+ @: > isisd/$(DEPDIR)/$(am__dirstamp)
+isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.$(OBJEXT): \
+ isisd/$(am__dirstamp) isisd/$(DEPDIR)/$(am__dirstamp)
+
+isisd/test_fuzz_isis_tlv$(EXEEXT): $(isisd_test_fuzz_isis_tlv_OBJECTS) $(isisd_test_fuzz_isis_tlv_DEPENDENCIES) $(EXTRA_isisd_test_fuzz_isis_tlv_DEPENDENCIES) isisd/$(am__dirstamp)
+ @rm -f isisd/test_fuzz_isis_tlv$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(isisd_test_fuzz_isis_tlv_OBJECTS) $(isisd_test_fuzz_isis_tlv_LDADD) $(LIBS)
+isisd/test_isis_vertex_queue.$(OBJEXT): isisd/$(am__dirstamp) \
+ isisd/$(DEPDIR)/$(am__dirstamp)
+
+isisd/test_isis_vertex_queue$(EXEEXT): $(isisd_test_isis_vertex_queue_OBJECTS) $(isisd_test_isis_vertex_queue_DEPENDENCIES) $(EXTRA_isisd_test_isis_vertex_queue_DEPENDENCIES) isisd/$(am__dirstamp)
+ @rm -f isisd/test_isis_vertex_queue$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(isisd_test_isis_vertex_queue_OBJECTS) $(isisd_test_isis_vertex_queue_LDADD) $(LIBS)
+lib/cli/$(am__dirstamp):
+ @$(MKDIR_P) lib/cli
+ @: > lib/cli/$(am__dirstamp)
+lib/cli/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) lib/cli/$(DEPDIR)
+ @: > lib/cli/$(DEPDIR)/$(am__dirstamp)
+lib/cli/test_cli.$(OBJEXT): lib/cli/$(am__dirstamp) \
+ lib/cli/$(DEPDIR)/$(am__dirstamp)
+lib/cli/common_cli.$(OBJEXT): lib/cli/$(am__dirstamp) \
+ lib/cli/$(DEPDIR)/$(am__dirstamp)
+
+lib/cli/test_cli$(EXEEXT): $(lib_cli_test_cli_OBJECTS) $(lib_cli_test_cli_DEPENDENCIES) $(EXTRA_lib_cli_test_cli_DEPENDENCIES) lib/cli/$(am__dirstamp)
+ @rm -f lib/cli/test_cli$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_cli_test_cli_OBJECTS) $(lib_cli_test_cli_LDADD) $(LIBS)
+lib/cli/test_commands_defun.$(OBJEXT): lib/cli/$(am__dirstamp) \
+ lib/cli/$(DEPDIR)/$(am__dirstamp)
+lib/cli/test_commands.$(OBJEXT): lib/cli/$(am__dirstamp) \
+ lib/cli/$(DEPDIR)/$(am__dirstamp)
+helpers/c/$(am__dirstamp):
+ @$(MKDIR_P) helpers/c
+ @: > helpers/c/$(am__dirstamp)
+helpers/c/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) helpers/c/$(DEPDIR)
+ @: > helpers/c/$(DEPDIR)/$(am__dirstamp)
+helpers/c/prng.$(OBJEXT): helpers/c/$(am__dirstamp) \
+ helpers/c/$(DEPDIR)/$(am__dirstamp)
+
+lib/cli/test_commands$(EXEEXT): $(lib_cli_test_commands_OBJECTS) $(lib_cli_test_commands_DEPENDENCIES) $(EXTRA_lib_cli_test_commands_DEPENDENCIES) lib/cli/$(am__dirstamp)
+ @rm -f lib/cli/test_commands$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_cli_test_commands_OBJECTS) $(lib_cli_test_commands_LDADD) $(LIBS)
+lib/$(am__dirstamp):
+ @$(MKDIR_P) lib
+ @: > lib/$(am__dirstamp)
+lib/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) lib/$(DEPDIR)
+ @: > lib/$(DEPDIR)/$(am__dirstamp)
+lib/test_buffer.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_buffer$(EXEEXT): $(lib_test_buffer_OBJECTS) $(lib_test_buffer_DEPENDENCIES) $(EXTRA_lib_test_buffer_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_buffer$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_buffer_OBJECTS) $(lib_test_buffer_LDADD) $(LIBS)
+lib/test_checksum.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_checksum$(EXEEXT): $(lib_test_checksum_OBJECTS) $(lib_test_checksum_DEPENDENCIES) $(EXTRA_lib_test_checksum_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_checksum$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_checksum_OBJECTS) $(lib_test_checksum_LDADD) $(LIBS)
+lib/test_heavy.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+helpers/c/main.$(OBJEXT): helpers/c/$(am__dirstamp) \
+ helpers/c/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_heavy$(EXEEXT): $(lib_test_heavy_OBJECTS) $(lib_test_heavy_DEPENDENCIES) $(EXTRA_lib_test_heavy_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_heavy$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_heavy_OBJECTS) $(lib_test_heavy_LDADD) $(LIBS)
+lib/test_heavy_thread.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_heavy_thread$(EXEEXT): $(lib_test_heavy_thread_OBJECTS) $(lib_test_heavy_thread_DEPENDENCIES) $(EXTRA_lib_test_heavy_thread_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_heavy_thread$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_heavy_thread_OBJECTS) $(lib_test_heavy_thread_LDADD) $(LIBS)
+lib/test_heavy_wq.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_heavy_wq$(EXEEXT): $(lib_test_heavy_wq_OBJECTS) $(lib_test_heavy_wq_DEPENDENCIES) $(EXTRA_lib_test_heavy_wq_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_heavy_wq$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_heavy_wq_OBJECTS) $(lib_test_heavy_wq_LDADD) $(LIBS)
+lib/test_memory.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_memory$(EXEEXT): $(lib_test_memory_OBJECTS) $(lib_test_memory_DEPENDENCIES) $(EXTRA_lib_test_memory_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_memory$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_memory_OBJECTS) $(lib_test_memory_LDADD) $(LIBS)
+lib/test_nexthop_iter.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_nexthop_iter$(EXEEXT): $(lib_test_nexthop_iter_OBJECTS) $(lib_test_nexthop_iter_DEPENDENCIES) $(EXTRA_lib_test_nexthop_iter_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_nexthop_iter$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_nexthop_iter_OBJECTS) $(lib_test_nexthop_iter_LDADD) $(LIBS)
+lib/test_privs.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_privs$(EXEEXT): $(lib_test_privs_OBJECTS) $(lib_test_privs_DEPENDENCIES) $(EXTRA_lib_test_privs_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_privs$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_privs_OBJECTS) $(lib_test_privs_LDADD) $(LIBS)
+lib/test_ringbuf.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_ringbuf$(EXEEXT): $(lib_test_ringbuf_OBJECTS) $(lib_test_ringbuf_DEPENDENCIES) $(EXTRA_lib_test_ringbuf_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_ringbuf$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_ringbuf_OBJECTS) $(lib_test_ringbuf_LDADD) $(LIBS)
+lib/test_segv.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_segv$(EXEEXT): $(lib_test_segv_OBJECTS) $(lib_test_segv_DEPENDENCIES) $(EXTRA_lib_test_segv_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_segv$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_segv_OBJECTS) $(lib_test_segv_LDADD) $(LIBS)
+lib/test_sig.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_sig$(EXEEXT): $(lib_test_sig_OBJECTS) $(lib_test_sig_DEPENDENCIES) $(EXTRA_lib_test_sig_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_sig$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_sig_OBJECTS) $(lib_test_sig_LDADD) $(LIBS)
+lib/test_srcdest_table.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_srcdest_table$(EXEEXT): $(lib_test_srcdest_table_OBJECTS) $(lib_test_srcdest_table_DEPENDENCIES) $(EXTRA_lib_test_srcdest_table_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_srcdest_table$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_srcdest_table_OBJECTS) $(lib_test_srcdest_table_LDADD) $(LIBS)
+lib/test_stream.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_stream$(EXEEXT): $(lib_test_stream_OBJECTS) $(lib_test_stream_DEPENDENCIES) $(EXTRA_lib_test_stream_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_stream$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_stream_OBJECTS) $(lib_test_stream_LDADD) $(LIBS)
+lib/test_table.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_table$(EXEEXT): $(lib_test_table_OBJECTS) $(lib_test_table_DEPENDENCIES) $(EXTRA_lib_test_table_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_table$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_table_OBJECTS) $(lib_test_table_LDADD) $(LIBS)
+lib/test_timer_correctness.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_timer_correctness$(EXEEXT): $(lib_test_timer_correctness_OBJECTS) $(lib_test_timer_correctness_DEPENDENCIES) $(EXTRA_lib_test_timer_correctness_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_timer_correctness$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_timer_correctness_OBJECTS) $(lib_test_timer_correctness_LDADD) $(LIBS)
+lib/test_timer_performance.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_timer_performance$(EXEEXT): $(lib_test_timer_performance_OBJECTS) $(lib_test_timer_performance_DEPENDENCIES) $(EXTRA_lib_test_timer_performance_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_timer_performance$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_timer_performance_OBJECTS) $(lib_test_timer_performance_LDADD) $(LIBS)
+lib/test_ttable.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_ttable$(EXEEXT): $(lib_test_ttable_OBJECTS) $(lib_test_ttable_DEPENDENCIES) $(EXTRA_lib_test_ttable_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_ttable$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_ttable_OBJECTS) $(lib_test_ttable_LDADD) $(LIBS)
+lib/lib_test_zmq-test_zmq.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_zmq$(EXEEXT): $(lib_test_zmq_OBJECTS) $(lib_test_zmq_DEPENDENCIES) $(EXTRA_lib_test_zmq_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_zmq$(EXEEXT)
+ $(AM_V_CCLD)$(lib_test_zmq_LINK) $(lib_test_zmq_OBJECTS) $(lib_test_zmq_LDADD) $(LIBS)
+ospf6d/$(am__dirstamp):
+ @$(MKDIR_P) ospf6d
+ @: > ospf6d/$(am__dirstamp)
+ospf6d/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) ospf6d/$(DEPDIR)
+ @: > ospf6d/$(DEPDIR)/$(am__dirstamp)
+ospf6d/test_lsdb.$(OBJEXT): ospf6d/$(am__dirstamp) \
+ ospf6d/$(DEPDIR)/$(am__dirstamp)
+
+ospf6d/test_lsdb$(EXEEXT): $(ospf6d_test_lsdb_OBJECTS) $(ospf6d_test_lsdb_DEPENDENCIES) $(EXTRA_ospf6d_test_lsdb_DEPENDENCIES) ospf6d/$(am__dirstamp)
+ @rm -f ospf6d/test_lsdb$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(ospf6d_test_lsdb_OBJECTS) $(ospf6d_test_lsdb_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+ -rm -f bgpd/*.$(OBJEXT)
+ -rm -f helpers/c/*.$(OBJEXT)
+ -rm -f isisd/*.$(OBJEXT)
+ -rm -f lib/*.$(OBJEXT)
+ -rm -f lib/cli/*.$(OBJEXT)
+ -rm -f ospf6d/*.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@bgpd/$(DEPDIR)/test_aspath.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@bgpd/$(DEPDIR)/test_capability.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@bgpd/$(DEPDIR)/test_ecommunity.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@bgpd/$(DEPDIR)/test_mp_attr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@bgpd/$(DEPDIR)/test_mpath.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@bgpd/$(DEPDIR)/test_packet.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@helpers/c/$(DEPDIR)/main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@helpers/c/$(DEPDIR)/prng.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@isisd/$(DEPDIR)/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@isisd/$(DEPDIR)/test_isis_vertex_queue.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/lib_test_zmq-test_zmq.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_buffer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_checksum.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_heavy.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_heavy_thread.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_heavy_wq.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_memory.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_nexthop_iter.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_privs.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_ringbuf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_segv.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_sig.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_srcdest_table.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_stream.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_table.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_timer_correctness.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_timer_performance.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_ttable.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/cli/$(DEPDIR)/common_cli.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/cli/$(DEPDIR)/test_cli.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/cli/$(DEPDIR)/test_commands.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/cli/$(DEPDIR)/test_commands_defun.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@ospf6d/$(DEPDIR)/test_lsdb.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.o: isisd/test_fuzz_isis_tlv.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(isisd_test_fuzz_isis_tlv_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.o -MD -MP -MF isisd/$(DEPDIR)/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.Tpo -c -o isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.o `test -f 'isisd/test_fuzz_isis_tlv.c' || echo '$(srcdir)/'`isisd/test_fuzz_isis_tlv.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) isisd/$(DEPDIR)/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.Tpo isisd/$(DEPDIR)/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='isisd/test_fuzz_isis_tlv.c' object='isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(isisd_test_fuzz_isis_tlv_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.o `test -f 'isisd/test_fuzz_isis_tlv.c' || echo '$(srcdir)/'`isisd/test_fuzz_isis_tlv.c
+
+isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.obj: isisd/test_fuzz_isis_tlv.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(isisd_test_fuzz_isis_tlv_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.obj -MD -MP -MF isisd/$(DEPDIR)/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.Tpo -c -o isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.obj `if test -f 'isisd/test_fuzz_isis_tlv.c'; then $(CYGPATH_W) 'isisd/test_fuzz_isis_tlv.c'; else $(CYGPATH_W) '$(srcdir)/isisd/test_fuzz_isis_tlv.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) isisd/$(DEPDIR)/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.Tpo isisd/$(DEPDIR)/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='isisd/test_fuzz_isis_tlv.c' object='isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(isisd_test_fuzz_isis_tlv_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.obj `if test -f 'isisd/test_fuzz_isis_tlv.c'; then $(CYGPATH_W) 'isisd/test_fuzz_isis_tlv.c'; else $(CYGPATH_W) '$(srcdir)/isisd/test_fuzz_isis_tlv.c'; fi`
+
+lib/lib_test_zmq-test_zmq.o: lib/test_zmq.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_test_zmq_CFLAGS) $(CFLAGS) -MT lib/lib_test_zmq-test_zmq.o -MD -MP -MF lib/$(DEPDIR)/lib_test_zmq-test_zmq.Tpo -c -o lib/lib_test_zmq-test_zmq.o `test -f 'lib/test_zmq.c' || echo '$(srcdir)/'`lib/test_zmq.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) lib/$(DEPDIR)/lib_test_zmq-test_zmq.Tpo lib/$(DEPDIR)/lib_test_zmq-test_zmq.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lib/test_zmq.c' object='lib/lib_test_zmq-test_zmq.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_test_zmq_CFLAGS) $(CFLAGS) -c -o lib/lib_test_zmq-test_zmq.o `test -f 'lib/test_zmq.c' || echo '$(srcdir)/'`lib/test_zmq.c
+
+lib/lib_test_zmq-test_zmq.obj: lib/test_zmq.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_test_zmq_CFLAGS) $(CFLAGS) -MT lib/lib_test_zmq-test_zmq.obj -MD -MP -MF lib/$(DEPDIR)/lib_test_zmq-test_zmq.Tpo -c -o lib/lib_test_zmq-test_zmq.obj `if test -f 'lib/test_zmq.c'; then $(CYGPATH_W) 'lib/test_zmq.c'; else $(CYGPATH_W) '$(srcdir)/lib/test_zmq.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) lib/$(DEPDIR)/lib_test_zmq-test_zmq.Tpo lib/$(DEPDIR)/lib_test_zmq-test_zmq.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lib/test_zmq.c' object='lib/lib_test_zmq-test_zmq.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_test_zmq_CFLAGS) $(CFLAGS) -c -o lib/lib_test_zmq-test_zmq.obj `if test -f 'lib/test_zmq.c'; then $(CYGPATH_W) 'lib/test_zmq.c'; else $(CYGPATH_W) '$(srcdir)/lib/test_zmq.c'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+ -rm -rf bgpd/.libs bgpd/_libs
+ -rm -rf isisd/.libs isisd/_libs
+ -rm -rf lib/.libs lib/_libs
+ -rm -rf lib/cli/.libs lib/cli/_libs
+ -rm -rf ospf6d/.libs ospf6d/_libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+check: check-am
+all-am: Makefile $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+ -rm -f bgpd/$(DEPDIR)/$(am__dirstamp)
+ -rm -f bgpd/$(am__dirstamp)
+ -rm -f helpers/c/$(DEPDIR)/$(am__dirstamp)
+ -rm -f helpers/c/$(am__dirstamp)
+ -rm -f isisd/$(DEPDIR)/$(am__dirstamp)
+ -rm -f isisd/$(am__dirstamp)
+ -rm -f lib/$(DEPDIR)/$(am__dirstamp)
+ -rm -f lib/$(am__dirstamp)
+ -rm -f lib/cli/$(DEPDIR)/$(am__dirstamp)
+ -rm -f lib/cli/$(am__dirstamp)
+ -rm -f ospf6d/$(DEPDIR)/$(am__dirstamp)
+ -rm -f ospf6d/$(am__dirstamp)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf bgpd/$(DEPDIR) helpers/c/$(DEPDIR) isisd/$(DEPDIR) lib/$(DEPDIR) lib/cli/$(DEPDIR) ospf6d/$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf bgpd/$(DEPDIR) helpers/c/$(DEPDIR) isisd/$(DEPDIR) lib/$(DEPDIR) lib/cli/$(DEPDIR) ospf6d/$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \
+ clean-checkPROGRAMS clean-generic clean-libtool cscopelist-am \
+ ctags ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+.c_clippy.c:
+ @{ test -x $(top_builddir)/$(HOSTTOOLS)lib/clippy || $(MAKE) -C $(top_builddir)/$(HOSTTOOLS) lib/clippy; }
+ $(AM_V_CLIPPY)$(top_builddir)/$(HOSTTOOLS)lib/clippy $(top_srcdir)/python/clidef.py -o $@ $<
+
+.l.c:
+ $(AM_V_LEX)$(am__skiplex) $(LEXCOMPILE) $<
+.y.c:
+ $(AM_V_YACC)$(am__skipyacc) $(YACCCOMPILE) $<
+
+# Rules
+@HAVE_PROTOBUF_TRUE@.proto.pb.h:
+@HAVE_PROTOBUF_TRUE@ $(Q_PROTOC) -I$(top_srcdir) --cpp_out=$(top_srcdir) $(top_srcdir)/$^
+
+@HAVE_PROTOBUF_TRUE@.proto.pb-c.c:
+@HAVE_PROTOBUF_TRUE@ $(AM_V_PROTOC_C)$(Q_PROTOC_C) -I$(top_srcdir) --c_out=$(top_srcdir) $(top_srcdir)/$^
+@HAVE_PROTOBUF_TRUE@.pb-c.c.pb-c.h:
+@HAVE_PROTOBUF_TRUE@ @/bin/true
+
+PYTHON ?= python
+
+lib/cli/test_cli.o: lib/cli/test_cli_clippy.c
+ospf6d/test_lsdb.o: ospf6d/test_lsdb_clippy.c
+
+../vtysh/vtysh_cmd.c:
+ $(MAKE) -C ../vtysh vtysh_cmd.c
+
+lib/cli/test_commands_defun.c: ../vtysh/vtysh_cmd.c
+ sed \
+ -e 's/"vtysh\.h"/"tests.h"/' \
+ -e 's/vtysh_init_cmd/test_init_cmd/' \
+ -e 's/VTYSH_[A-Z][A-Z_0-9]*/0/g' \
+ < ../vtysh/vtysh_cmd.c \
+ > "$@"
+
+isisd/test_fuzz_isis_tlv_tests.h: $(top_srcdir)/tests/isisd/test_fuzz_isis_tlv_tests.h.gz
+ gzip -d < $(top_srcdir)/tests/isisd/test_fuzz_isis_tlv_tests.h.gz > "$@"
+isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.$(OBJEXT): \
+ isisd/test_fuzz_isis_tlv_tests.h
+
+.PHONY: tests.xml
+tests.xml: $(check_PROGRAMS)
+ $(PYTHON) $(srcdir)/runtests.py --junitxml=$@ -v $(srcdir)
+check: tests.xml
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tests/topotests/GUIDELINES.md b/tests/topotests/GUIDELINES.md
deleted file mode 100644
index 4bd373796c..0000000000
--- a/tests/topotests/GUIDELINES.md
+++ /dev/null
@@ -1,571 +0,0 @@
-# Guidelines
-
-This document describes how to use the topotests testing framework.
-
-
-## Executing Tests
-
-To run the whole suite of tests the following commands must be executed at the
-top level directory of topotest:
-
-```shell
-$ # Change to the top level directory of topotests.
-$ cd path/to/topotests
-$ # Tests must be run as root, since Mininet requires it.
-$ sudo pytest
-```
-
-In order to run a specific test, you can use the following command:
-
-```shell
-$ # running a specific topology
-$ sudo pytest ospf-topo1/
-$ # or inside the test folder
-$ cd ospf-topo1
-$ sudo pytest # to run all tests inside the directory
-$ sudo pytest test_ospf_topo1.py # to run a specific test
-$ # or outside the test folder
-$ cd ..
-$ sudo pytest ospf-topo1/test_ospf_topo1.py # to run a specific one
-```
-
-The output of the tested daemons will be available at the temporary folder of
-your machine:
-
-```shell
-$ ls /tmp/topotest/ospf-topo1.test_ospf-topo1/r1
-...
-zebra.err # zebra stderr output
-zebra.log # zebra log file
-zebra.out # zebra stdout output
-...
-```
-
-You can also run memory leak tests to get reports:
-
-```shell
-$ # Set the environment variable to apply to a specific test...
-$ sudo env TOPOTESTS_CHECK_MEMLEAK="/tmp/memleak_report_" pytest ospf-topo1/test_ospf_topo1.py
-$ # ...or apply to all tests adding this line to the configuration file
-$ echo 'memleak_path = /tmp/memleak_report_' >> pytest.ini
-$ # You can also use your editor
-$ $EDITOR pytest.ini
-$ # After running tests you should see your files:
-$ ls /tmp/memleak_report_*
-memleak_report_test_ospf_topo1.txt
-```
-
-
-## Writing a New Test
-
-This section will guide you in all recommended steps to produce a standard
-topology test.
-
-This is the recommended test writing routine:
-
-* Write a topology (Graphviz recommended)
-* Obtain configuration files
-* Write the test itself
-* Create a Pull Request
-
-
-### Topotest File Hierarchy
-
-Before starting to write any tests one must know the file hierarchy. The
-repository hierarchy looks like this:
-
-```shell
-$ cd path/to/topotest
-$ find ./*
-...
-./README.md # repository read me
-./GUIDELINES.md # this file
-./conftest.py # test hooks - pytest related functions
-./example-test # example test folder
-./example-test/__init__.py # python package marker - must always exist.
-./example-test/test_template.jpg # generated topology picture - see next section
-./example-test/test_template.dot # Graphviz dot file
-./example-test/test_template.py # the topology plus the test
-...
-./ospf-topo1 # the ospf topology test
-./ospf-topo1/r1 # router 1 configuration files
-./ospf-topo1/r1/zebra.conf # zebra configuration file
-./ospf-topo1/r1/ospfd.conf # ospf configuration file
-./ospf-topo1/r1/ospfroute.txt # 'show ip ospf' output reference file
-# removed other for shortness sake
-...
-./lib # shared test/topology functions
-./lib/topogen.py # topogen implementation
-./lib/topotest.py # topotest implementation
-```
-
-Guidelines for creating/editing topotest:
-
-* New topologies that don't fit the existing directories should create its own
-* Always remember to add the `__init__.py` to new folders, this makes auto
- complete engines and pylint happy
-* Router (Quagga/FRR) specific code should go on topotest.py
-* Generic/repeated router actions should have an abstraction in
- topogen.TopoRouter.
-* Generic/repeated non-router code should go to topotest.py
-* pytest related code should go to conftest.py (e.g. specialized asserts)
-
-
-### Defining the Topology
-
-The first step to write a new test is to define the topology. This step can be
-done in many ways, but the recommended is to use Graphviz to generate a drawing
-of the Topology. It allows us to see the topology graphically and to see the
-names of equipments, links and addresses.
-
-Here is an example of Graphviz dot file that generates the
-[template topology](example-test/test_template.dot) (the inlined code might get
-outdated, please see the linked file):
-
-```dot
-graph template {
- label="template";
-
- # Routers
- r1 [
- shape=doubleoctagon,
- label="r1",
- fillcolor="#f08080",
- style=filled,
- ];
- r2 [
- shape=doubleoctagon,
- label="r2",
- fillcolor="#f08080",
- style=filled,
- ];
-
- # Switches
- s1 [
- shape=oval,
- label="s1\n192.168.0.0/24",
- fillcolor="#d0e0d0",
- style=filled,
- ];
- s2 [
- shape=oval,
- label="s2\n192.168.1.0/24",
- fillcolor="#d0e0d0",
- style=filled,
- ];
-
- # Connections
- r1 -- s1 [label="eth0\n.1"];
-
- r1 -- s2 [label="eth1\n.100"];
- r2 -- s2 [label="eth0\n.1"];
-}
-```
-
-Here is the produced graph:
-
-![template topology graph](example-test/test_template.jpg)
-
-
-### Generating / Obtaining Configuration Files
-
-In order to get the configuration files or command output for each router, we
-need to run the topology and execute commands in vtysh. The quickest way to
-achieve that is writing the topology building code and running the topology.
-
-To bootstrap your test topology, do the following steps:
-
-* Copy the template test
-
-```shell
-$ mkdir new-topo/
-$ touch new-topo/__init__.py
-$ cp example-test/test_template.py new-topo/test_new_topo.py
-```
-
-* Modify the template according to your dot file
-
-Here is the template topology described in the previous section in python code:
-
-```py
-class TemplateTopo(Topo):
- "Test topology builder"
- def build(self, *_args, **_opts):
- "Build function"
- tgen = get_topogen(self)
-
- # 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
-
-Topogen allows us to run the topology without running any tests, you can do that
-using the following example commands:
-
-```shell
-$ # Running your bootstraped topology
-$ sudo pytest -s --topology-only new-topo/test_new_topo.py
-$ # Running the test_template.py topology
-$ sudo pytest -s --topology-only example-test/test_template.py
-$ # Running the ospf_topo1.py topology
-$ sudo pytest -s --topology-only ospf-topo1/test_ospf_topo1.py
-```
-
-Parameters explanation:
-
-* `-s`: actives input/output capture. This is required by mininet in order to show
- the interactive shell.
-* `--topology-only`: don't run any tests, just build the topology.
-
-After executing the commands above, you should get the following terminal
-output:
-
-```shell
-=== test session starts ===
-platform linux2 -- Python 2.7.12, pytest-3.1.2, py-1.4.34, pluggy-0.4.0
-rootdir: /media/sf_src/topotests, inifile: pytest.ini
-collected 3 items
-
-ospf-topo1/test_ospf_topo1.py *** Starting controller
-
-*** Starting 6 switches
-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.
-
-Here are some commands example:
-
-```shell
-mininet> r1 ping 10.0.3.1
-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=2 ttl=64 time=0.083 ms
-64 bytes from 10.0.3.1: icmp_seq=3 ttl=64 time=0.088 ms
-^C
---- 10.0.3.1 ping statistics ---
-3 packets transmitted, 3 received, 0% packet loss, time 1998ms
-rtt min/avg/max/mdev = 0.083/0.249/0.576/0.231 ms
-
-
-
-mininet> r1 ping 10.0.3.3
-PING 10.0.3.3 (10.0.3.3) 56(84) bytes of data.
-64 bytes from 10.0.3.3: icmp_seq=1 ttl=64 time=2.87 ms
-64 bytes from 10.0.3.3: icmp_seq=2 ttl=64 time=0.080 ms
-64 bytes from 10.0.3.3: icmp_seq=3 ttl=64 time=0.091 ms
-^C
---- 10.0.3.3 ping statistics ---
-3 packets transmitted, 3 received, 0% packet loss, time 2003ms
-rtt min/avg/max/mdev = 0.080/1.014/2.872/1.313 ms
-
-
-
-mininet> r3 vtysh
-
-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
-configuration files (per-daemon) using the following commands:
-
-```shell
-mininet> r3 vtysh -d ospfd
-
-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
-no service integrated-vtysh-config
-!
-log file ospfd.log
-!
-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#
-```
-
-
-### Writing Tests
-
-Test topologies should always be bootstrapped from the
-[example-test/test_template.py](example-test/test_template.py),
-because it contains 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:
-
-```py
-# For all registered routers, load the zebra configuration file
-for rname, router in router_list.iteritems():
- router.load_config(
- TopoRouter.RD_ZEBRA,
- os.path.join(CWD, '{}/zebra.conf'.format(rname))
- )
- # os.path.join() joins the CWD string with arguments adding the necessary
- # slashes ('/'). Arguments must not begin with '/'.
-```
-
-* The topology class that inherits from Mininet Topo class
-
-```py
-class TemplateTopo(Topo):
- def build(self, *_args, **_opts):
- tgen = get_topogen(self)
- # topology build code
-```
-
-* pytest `setup_module()` and `teardown_module()` to start the topology
-
-```py
-def setup_module(_m):
- tgen = Topogen(TemplateTopo)
- tgen.start_topology('debug')
-
-def teardown_module(_m):
- tgen = get_topogen()
- tgen.stop_topology()
-```
-
-* `__main__` initialization code (to support running the script directly)
-
-```py
-if __name__ == '__main__':
- sys.exit(pytest.main(["-s"]))
-```
-
-Requirements:
-
-* Test code should always be declared inside functions that begin with the
- `test_` prefix. Functions beginning with different prefixes will not be run by
- pytest.
-* Configuration files and long output commands should go into separated files
- inside folders named after the equipment.
-* Tests must be able to run without any interaction. To make sure your test
- conforms with this, run it without the `-s` parameter.
-
-Tips:
-
-* Keep results in stack variables, so people inspecting code with `pdb` can
- easily print their values.
-
- Don't do this:
-
- ```py
- assert foobar(router1, router2)
- ```
-
- Do this instead:
-
- ```py
- result = foobar(router1, router2)
- assert result
- ```
-
-* Use `assert` messages to indicate where the test failed.
-
- Example:
-
- ```py
- for router in router_list:
- # ...
- assert condition, 'Router "{}" condition failed'.format(router.name)
- ```
-
-
-### Debugging Execution
-
-The most effective ways to inspect topology tests are:
-
-* Run pytest with `--pdb` option. This option will cause a pdb shell to appear
- when an assertion fails
-
- Example: `pytest -s --pdb ospf-topo1/test_ospf_topo1.py`
-
-* Set a breakpoint in the test code with `pdb`
-
- Example:
-
-```py
-# Add the pdb import at the beginning of the file
-import pdb
-# ...
-
-# Add a breakpoint where you think the problem is
-def test_bla():
- # ...
- pdb.set_trace()
- # ...
-```
-
-The [Python Debugger](https://docs.python.org/2.7/library/pdb.html) (pdb) shell
-allows us to run many useful operations like:
-
-* Setting breaking point on file/function/conditions (e.g. `break`, `condition`)
-* Inspecting variables (e.g. `p` (print), `pp` (pretty print))
-* Running python code
-
-TIP: The TopoGear (equipment abstraction class) implements the `__str__` method
-that allows the user to inspect equipment information.
-
-Example of pdb usage:
-
-```shell
-> /media/sf_src/topotests/ospf-topo1/test_ospf_topo1.py(121)test_ospf_convergence()
--> for rnum in range(1, 5):
-(Pdb) help
-Documented commands (type help <topic>):
-========================================
-EOF bt cont enable jump pp run unt
-a c continue exit l q s until
-alias cl d h list quit step up
-args clear debug help n r tbreak w
-b commands disable ignore next restart u whatis
-break condition down j p return unalias where
-
-Miscellaneous help topics:
-==========================
-exec pdb
-
-Undocumented commands:
-======================
-retval rv
-
-(Pdb) list
-116 title2="Expected output")
-117
-118 def test_ospf_convergence():
-119 "Test OSPF daemon convergence"
-120 pdb.set_trace()
-121 -> for rnum in range(1, 5):
-122 router = 'r{}'.format(rnum)
-123
-124 # Load expected results from the command
-125 reffile = os.path.join(CWD, '{}/ospfroute.txt'.format(router))
-126 expected = open(reffile).read()
-(Pdb) step
-> /media/sf_src/topotests/ospf-topo1/test_ospf_topo1.py(122)test_ospf_convergence()
--> router = 'r{}'.format(rnum)
-(Pdb) step
-> /media/sf_src/topotests/ospf-topo1/test_ospf_topo1.py(125)test_ospf_convergence()
--> reffile = os.path.join(CWD, '{}/ospfroute.txt'.format(router))
-(Pdb) print rnum
-1
-(Pdb) print router
-r1
-(Pdb) tgen = get_topogen()
-(Pdb) pp tgen.gears[router]
-<lib.topogen.TopoRouter object at 0x7f74e06c9850>
-(Pdb) pp str(tgen.gears[router])
-'TopoGear<name="r1",links=["r1-eth0"<->"s1-eth0","r1-eth1"<->"s3-eth0"]> TopoRouter<>'
-(Pdb) l 125
-120 pdb.set_trace()
-121 for rnum in range(1, 5):
-122 router = 'r{}'.format(rnum)
-123
-124 # Load expected results from the command
-125 -> reffile = os.path.join(CWD, '{}/ospfroute.txt'.format(router))
-126 expected = open(reffile).read()
-127
-128 # Run test function until we get an result. Wait at most 60 seconds.
-129 test_func = partial(compare_show_ip_ospf, router, expected)
-130 result, diff = topotest.run_and_expect(test_func, '',
-(Pdb) router1 = tgen.gears[router]
-(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'
-(Pdb) tgen.mininet_cli()
-*** Starting CLI:
-mininet>
-```
-
-To enable more debug messages in other Topogen subsystems (like Mininet), more
-logging messages can be displayed by modifying the test configuration file
-`pytest.ini`:
-
-```ini
-[topogen]
-# Change the default verbosity line from 'info'...
-#verbosity = info
-# ...to 'debug'
-verbosity = debug
-```
diff --git a/tests/topotests/README.md b/tests/topotests/README.md
index a495675ee9..d9d849b39f 100644
--- a/tests/topotests/README.md
+++ b/tests/topotests/README.md
@@ -1,199 +1 @@
-# FRRouting Topology Tests with Mininet
-
-## Running tests with docker
-
-There is a docker image which allows to run topotests. Instructions can be
-found [here](docker/README.md).
-
-## Guidelines
-
-Instructions for use, write or debug topologies can be found in the
-[guidelines](GUIDELINES.md). To learn/remember common code snippets see
-[here](SNIPPETS.md).
-
-Before creating a new topology, make sure that there isn't one already
-that does what you need. If nothing is similar, then you may create a
-new topology, preferably, using the newest
-[template](example-test/test_template.py).
-
-## Installation of Mininet for running tests
-Only tested with Ubuntu 16.04 and Ubuntu 18.04 (which uses Mininet 2.2.x)
-
-Instructions are the same for all setups (ie ExaBGP is only used for BGP
-tests)
-
-### Installing Mininet Infrastructure:
-
-1. apt-get install mininet
-2. apt-get install python-pip
-3. apt-get install iproute
-4. pip install ipaddr
-5. pip install pytest
-6. pip install exabgp==3.4.17
- (Newer 4.0 version of exabgp is not yet supported)
-7. useradd -d /var/run/exabgp/ -s /bin/false exabgp
-
-### Enable Coredumps
-Optional, will give better output
-
-1. apt-get install gdb
-2. disable apport (which move core files)
-
- Set `enabled=0` in `/etc/default/apport`
-
-3. Update security limits
-
- Add/change `/etc/security/limits.conf` to
-
- #<domain> <type> <item> <value>
- * soft core unlimited
- root soft core unlimited
- * hard core unlimited
- root hard core unlimited
-
-4. reboot (for options to take effect)
-
-## FRRouting (FRR) Installation
-FRR needs to be installed separatly. It is assume to be configured
-like the standard Ubuntu Packages:
-
-- Binaries in /usr/lib/frr
-- State Directory /var/run/frr
-- Running under user frr, group frr
-- vtygroup: frrvty
-- config directory: /etc/frr
-- For FRR Packages, install the dbg package as well for coredump decoding
-
-No FRR config needs to be done and no FRR daemons should be run ahead
-of the test. They are all started as part of the test
-
-#### Manual FRRouting (FRR) build
-
-If you prefer to manually build FRR, then use the following suggested config:
-
- ./configure \
- --prefix=/usr \
- --localstatedir=/var/run/frr \
- --sbindir=/usr/lib/frr \
- --sysconfdir=/etc/frr \
- --enable-vtysh \
- --enable-pimd \
- --enable-multipath=64 \
- --enable-user=frr \
- --enable-group=frr \
- --enable-vty-group=frrvty \
- --with-pkg-extra-version=-my-manual-build
-
-And create frr User and frrvty group as follows:
-
- addgroup --system --gid 92 frr
- addgroup --system --gid 85 frrvty
- adduser --system --ingroup frr --home /var/run/frr/ \
- --gecos "FRRouting suite" --shell /bin/false frr
- usermod -G frrvty frr
-
-## Executing Tests
-
-#### Execute all tests with output to console
-
- py.test -s -v --tb=no
-
-All test_* scripts in subdirectories are detected and executed (unless
-disabled in `pytest.ini` file)
-
-`--tb=no` disables the python traceback which might be irrelevant unless the
-test script itself is debugged
-
-#### Execute single test
-
- cd test_to_be_run
- ./test_to_be_run.py
-
-For further options, refer to pytest documentation
-
-Test will set exit code which can be used with `git bisect`
-
-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
-
-#### (Optional) StdErr log from daemos after exit
-
-To enable the reporting of any messages seen on StdErr after the
-daemons exit, the following env variable can be set.
-
- export TOPOTESTS_CHECK_STDERR=Yes
-
-(The value doesn't matter at this time. The check is if the env variable
-exists or not)
-There is no pass/fail on this reporting. The Output will be reported to
-the console
-
- export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_"
-
-This will enable the check and output to console and the writing of
-the information to files with the given prefix (followed by testname),
-ie `/home/mydir/memcheck_test_bgp_multiview_topo1.txt` in case of a
-memory leak.
-
-#### (Optional) Collect Memory Leak Information
-
-FreeRangeRouting processes have the capabilities to report remaining memory
-allocations upon exit. To enable the reporting of the memory, define an
-enviroment variable `TOPOTESTS_CHECK_MEMLEAK` with the file prefix, ie
-
- export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_"
-
-This will enable the check and output to console and the writing of
-the information to files with the given prefix (followed by testname),
-ie `/home/mydir/memcheck_test_bgp_multiview_topo1.txt` in case of a
-memory leak.
-
-#### (Optional) Run topotests with GCC AddressSanitizer enabled
-
-Topotests can be run with the GCC AddressSanitizer. It requires GCC 4.8 or
-newer. (Ubuntu 16.04 as suggested here is fine with GCC 5 as default)
-For more information on AddressSanitizer, see
-https://github.com/google/sanitizers/wiki/AddressSanitizer
-
-The checks are done automatically in the library call of `checkRouterRunning`
-(ie at beginning of tests when there is a check for all daemons running).
-No changes or extra configuration for topotests is required beside compiling
-the suite with AddressSanitizer enabled.
-
-If a daemon crashed, then the errorlog is checked for AddressSanitizer
-output. If found, then this is added with context (calling test) to
-`/tmp/AddressSanitizer.txt` in markdown compatible format.
-
-Compiling for GCC AddressSanitizer requires to use gcc as a linker as well
-(instead of ld). Here is a suggest way to compile frr with AddressSanitizer
-for `stable/3.0` branch:
-
- git clone https://github.com/FRRouting/frr.git
- cd frr
- git checkout stable/3.0
- ./bootstrap.sh
- export CC=gcc
- export CFLAGS="-O1 -g -fsanitize=address -fno-omit-frame-pointer"
- export LD=gcc
- export LDFLAGS="-g -fsanitize=address -ldl"
- ./configure --enable-shared=no \
- --prefix=/usr/lib/frr --sysconfdir=/etc/frr \
- --localstatedir=/var/run/frr \
- --sbindir=/usr/lib/frr --bindir=/usr/lib/frr \
- --enable-exampledir=/usr/lib/frr/examples \
- --with-moduledir=/usr/lib/frr/modules \
- --enable-multipath=0 --enable-rtadv \
- --enable-tcp-zebra --enable-fpm --enable-pimd
- make
- sudo make install
- # Create symlink for vtysh, so topotest finds it in /usr/lib/frr
- sudo ln -s /usr/lib/frr/vtysh /usr/bin/
-
-and create `frr` user and `frrvty` group as shown above
-
-## License
-
-All the configs and scripts are licensed under a ISC-style license. See
-Python scripts for details.
+Documentation is located in /doc/developer/topotests.rst
diff --git a/tests/topotests/SNIPPETS.md b/tests/topotests/SNIPPETS.md
deleted file mode 100644
index 6c16c44af6..0000000000
--- a/tests/topotests/SNIPPETS.md
+++ /dev/null
@@ -1,275 +0,0 @@
-# Snippets
-
-This document will describe common snippets of code that are frequently
-needed to perform some test checks.
-
-
-## Checking for router / test failures
-
-The following check uses the topogen API to check for software failure
-(e.g. zebra died) and/or for errors manually set by `Topogen.set_error()`.
-
-```py
-# Get the topology reference
-tgen = get_topogen()
-
-# Check for errors in the topology
-if tgen.routers_have_failure():
- # Skip the test with the topology errors as reason
- pytest.skip(tgen.errors)
-```
-
-
-## Checking FRR routers version
-
-This code snippet is usually run after the topology setup to make sure
-all routers instantiated in the topology have the correct software
-version.
-
-```py
-# Get the topology reference
-tgen = get_topogen()
-
-# Get the router list
-router_list = tgen.routers()
-
-# Run the check for all routers
-for router in router_list.values():
- if router.has_version('<', '3'):
- # Set topology error, so the next tests are skipped
- tgen.set_error('unsupported version')
-```
-
-A sample of this snippet in a test can be found
-[here](ldp-vpls-topo1/test_ldp_vpls_topo1.py).
-
-
-## Interacting with equipments
-
-You might want to interact with the topology equipments during the tests
-and there are different ways to do so.
-
-Notes:
-
-1.
-> When using the Topogen API, all the equipments code derive from
-> `Topogear` ([lib/topogen.py](lib/topogen.py)). If you feel brave you
-> can look by yourself how the abstractions that will be mentioned here
-> works.
-
-2.
-> When not using the `Topogen` API there is only one way to interact
-> with the equipments, which is by calling the `mininet` API functions
-> directly to spawn commands.
-
-
-### Interacting with the Linux sandbox
-
-*Without `Topogen`*
-
-```py
-global net
-output = net['r1'].cmd('echo "foobar"')
-print 'output is: {}'.format(output)
-```
-
----
-
-*With `Topogen`*
-
-```py
-tgen = get_topogen()
-output = tgen.gears['r1'].run('echo "foobar"')
-print 'output is: {}'.format(output)
-```
-
-
-### Interacting with VTYSH
-
-*Without `Topogen`*
-
-```py
-global net
-output = net['r1'].cmd('vtysh "show ip route" 2>/dev/null')
-print 'output is: {}'.format(output)
-```
-
----
-
-*With `Topogen`*
-
-```py
-tgen = get_topogen()
-output = tgen.gears['r1'].vtysh_cmd("show ip route")
-print 'output is: {}'.format(output)
-```
-
-`Topogen` also supports sending multiple lines of command:
-
-```py
-tgen = get_topogen()
-output = tgen.gears['r1'].vtysh_cmd("""
-configure terminal
-router bgp 10
- bgp router-id 10.0.255.1
- neighbor 1.2.3.4 remote-as 10
- !
-router bgp 11
- bgp router-id 10.0.255.2
- !
-""")
-print 'output is: {}'.format(output)
-```
-
-You might also want to run multiple commands and get only the commands
-that failed:
-
-```py
-tgen = get_topogen()
-output = tgen.gears['r1'].vtysh_multicmd("""
-configure terminal
-router bgp 10
- bgp router-id 10.0.255.1
- neighbor 1.2.3.4 remote-as 10
- !
-router bgp 11
- bgp router-id 10.0.255.2
- !
-""", pretty_output=false)
-print 'output is: {}'.format(output)
-```
-
-Translating vtysh JSON output into Python structures:
-```py
-tgen = get_topogen()
-json_output = tgen.gears['r1'].vtysh_cmd("show ip route json", isjson=True)
-output = json.dumps(json_output, indent=4)
-print 'output is: {}'.format(output)
-
-# You can also access the data structure as normal. For example:
-# protocol = json_output['1.1.1.1/32']['protocol']
-# assert protocol == "ospf", "wrong protocol"
-```
-
-*NOTE:* `vtysh_(multi)cmd` is only available for router type of
-equipments.
-
-
-### Invoking `mininet` CLI
-
-*Without `Topogen`*
-
-```py
-CLI(net)
-```
-
----
-
-*With `Topogen`*
-```py
-tgen = get_topogen()
-tgen.mininet_cli()
-```
-
-
-## Reading files
-
-Loading a normal text file content in the current directory:
-
-```py
-# If you are using Topogen
-# CURDIR = CWD
-#
-# Otherwise find the directory manually:
-CURDIR = os.path.dirname(os.path.realpath(__file__))
-
-file_name = '{}/r1/show_ip_route.txt'.format(CURDIR)
-file_content = open(file_name).read()
-```
-
-Loading JSON from a file:
-
-```py
-import json
-
-file_name = '{}/r1/show_ip_route.json'.format(CURDIR)
-file_content = json.loads(open(file_name).read())
-```
-
-
-## Comparing JSON output
-
-After obtaining JSON output formated with Python data structures, you
-may use it to assert a minimalist schema:
-
-```py
-tgen = get_topogen()
-json_output = tgen.gears['r1'].vtysh_cmd("show ip route json", isjson=True)
-
-expect = {
- '1.1.1.1/32': {
- 'protocol': 'ospf'
- }
-}
-
-assertmsg = "route 1.1.1.1/32 was not learned through OSPF"
-assert json_cmp(json_output, expect) is None, assertmsg
-```
-
-`json_cmp` function description (it might be outdated, you can find the
-latest description in the source code at [lib/topotest.py](lib/topotest.py)):
-
-```text
- JSON compare function. Receives two parameters:
- * `d1`: json value
- * `d2`: json subset which we expect
-
- Returns `None` when all keys that `d1` has matches `d2`,
- otherwise a string containing what failed.
-
- Note: key absence can be tested by adding a key with value `None`.
-```
-
-
-## Pausing execution
-
-Preferably, choose the `sleep` function that `topotest` provides, as it
-prints a notice during the test execution to help debug topology test
-execution time.
-
-```py
-# Using the topotest sleep
-from lib import topotest
-
-topotest.sleep(10, 'waiting 10 seconds for bla')
-# or just tell it the time:
-# topotest.sleep(10)
-# It will print 'Sleeping for 10 seconds'.
-
-# Or you can also use the Python sleep, but it won't show anything
-from time import sleep
-sleep(5)
-```
-
-
-## `ip route` Linux command as JSON
-
-`topotest` has two helpers implemented that parses the output of
-`ip route` commands to JSON. It might simplify your comparison needs by
-only needing to provide a Python dictionary.
-
-```py
-from lib import topotest
-
-tgen = get_topogen()
-routes = topotest.ip4_route(tgen.gears['r1'])
-expected = {
- '10.0.1.0/24': {},
- '10.0.2.0/24': {
- 'dev': 'r1-eth0'
- }
-}
-
-assertmsg = "failed to find 10.0.1.0/24 and/or 10.0.2.0/24"
-assert json_cmp(routes, expected) is None, assertmsg
-```
diff --git a/zebra/rt.h b/zebra/rt.h
index 6d12d8ea2e..4080b0ccb2 100644
--- a/zebra/rt.h
+++ b/zebra/rt.h
@@ -32,7 +32,7 @@
#include "zebra/zebra_dplane.h"
/*
- * Update or delete a route or LSP from the kernel,
+ * Update or delete a route, LSP, or pseudowire from the kernel,
* using info from a dataplane context.
*/
extern enum zebra_dplane_result kernel_route_update(
@@ -41,6 +41,8 @@ extern enum zebra_dplane_result kernel_route_update(
extern enum zebra_dplane_result kernel_lsp_update(
struct zebra_dplane_ctx *ctx);
+enum zebra_dplane_result kernel_pw_update(struct zebra_dplane_ctx *ctx);
+
extern int kernel_address_add_ipv4(struct interface *, struct connected *);
extern int kernel_address_delete_ipv4(struct interface *, struct connected *);
extern int kernel_address_add_ipv6(struct interface *, struct connected *);
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index 15fcde2bbc..928169a862 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -102,6 +102,23 @@ struct dplane_route_info {
};
/*
+ * Pseudowire info for the dataplane
+ */
+struct dplane_pw_info {
+ char ifname[IF_NAMESIZE];
+ ifindex_t ifindex;
+ int type;
+ int af;
+ int status;
+ uint32_t flags;
+ union g_addr nexthop;
+ mpls_label_t local_label;
+ mpls_label_t remote_label;
+
+ union pw_protocol_fields fields;
+};
+
+/*
* The context block used to exchange info about route updates across
* the boundary between the zebra main context (and pthread) and the
* dataplane layer (and pthread).
@@ -136,6 +153,7 @@ struct zebra_dplane_ctx {
union {
struct dplane_route_info rinfo;
zebra_lsp_t lsp;
+ struct dplane_pw_info pw;
} u;
/* Namespace info, used especially for netlink kernel communication */
@@ -237,10 +255,11 @@ static struct zebra_dplane_globals {
_Atomic uint32_t dg_other_errors;
_Atomic uint32_t dg_lsps_in;
- _Atomic uint32_t dg_lsps_queued;
- _Atomic uint32_t dg_lsps_queued_max;
_Atomic uint32_t dg_lsp_errors;
+ _Atomic uint32_t dg_pws_in;
+ _Atomic uint32_t dg_pw_errors;
+
_Atomic uint32_t dg_update_yields;
/* Dataplane pthread */
@@ -276,6 +295,8 @@ static void dplane_info_from_zns(struct zebra_dplane_info *ns_info,
struct zebra_ns *zns);
static enum zebra_dplane_result lsp_update_internal(zebra_lsp_t *lsp,
enum dplane_op_e op);
+static enum zebra_dplane_result pw_update_internal(struct zebra_pw *pw,
+ enum dplane_op_e op);
/*
* Public APIs
@@ -363,6 +384,8 @@ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
break;
}
+ case DPLANE_OP_PW_INSTALL:
+ case DPLANE_OP_PW_UNINSTALL:
case DPLANE_OP_NONE:
break;
}
@@ -490,6 +513,13 @@ const char *dplane_op2str(enum dplane_op_e op)
ret = "LSP_DELETE";
break;
+ case DPLANE_OP_PW_INSTALL:
+ ret = "PW_INSTALL";
+ break;
+ case DPLANE_OP_PW_UNINSTALL:
+ ret = "PW_UNINSTALL";
+ break;
+
};
return ret;
@@ -735,6 +765,71 @@ uint32_t dplane_ctx_get_lsp_num_ecmp(const struct zebra_dplane_ctx *ctx)
return ctx->u.lsp.num_ecmp;
}
+const char *dplane_ctx_get_pw_ifname(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.pw.ifname;
+}
+
+mpls_label_t dplane_ctx_get_pw_local_label(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.pw.local_label;
+}
+
+mpls_label_t dplane_ctx_get_pw_remote_label(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.pw.remote_label;
+}
+
+int dplane_ctx_get_pw_type(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.pw.type;
+}
+
+int dplane_ctx_get_pw_af(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.pw.af;
+}
+
+uint32_t dplane_ctx_get_pw_flags(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.pw.flags;
+}
+
+int dplane_ctx_get_pw_status(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.pw.status;
+}
+
+const union g_addr *dplane_ctx_get_pw_nexthop(
+ const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return &(ctx->u.pw.nexthop);
+}
+
+const union pw_protocol_fields *dplane_ctx_get_pw_proto(
+ const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return &(ctx->u.pw.fields);
+}
+
/*
* End of dplane context accessors
*/
@@ -938,6 +1033,47 @@ static int dplane_ctx_lsp_init(struct zebra_dplane_ctx *ctx,
}
/*
+ * Capture information for an LSP update in a dplane context.
+ */
+static int dplane_ctx_pw_init(struct zebra_dplane_ctx *ctx,
+ enum dplane_op_e op,
+ struct zebra_pw *pw)
+{
+ int ret = AOK;
+
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
+ zlog_debug("init dplane ctx %s: pw '%s', loc %u, rem %u",
+ dplane_op2str(op), pw->ifname, pw->local_label,
+ pw->remote_label);
+
+ ctx->zd_op = op;
+ ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
+
+ /* Capture namespace info: no netlink support as of 12/18,
+ * but just in case...
+ */
+ dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT), false);
+
+ memset(&ctx->u.pw, 0, sizeof(ctx->u.pw));
+
+ /* This name appears to be c-string, so we use string copy. */
+ strlcpy(ctx->u.pw.ifname, pw->ifname, sizeof(ctx->u.pw.ifname));
+ ctx->zd_vrf_id = pw->vrf_id;
+ ctx->u.pw.ifindex = pw->ifindex;
+ ctx->u.pw.type = pw->type;
+ ctx->u.pw.af = pw->af;
+ ctx->u.pw.local_label = pw->local_label;
+ ctx->u.pw.remote_label = pw->remote_label;
+ ctx->u.pw.flags = pw->flags;
+
+ ctx->u.pw.nexthop = pw->nexthop;
+
+ ctx->u.pw.fields = pw->data;
+
+ return ret;
+}
+
+/*
* Enqueue a new route update,
* and ensure an event is active for the dataplane pthread.
*/
@@ -1141,6 +1277,22 @@ enum zebra_dplane_result dplane_lsp_delete(zebra_lsp_t *lsp)
}
/*
+ * Enqueue pseudowire install for the dataplane.
+ */
+enum zebra_dplane_result dplane_pw_install(struct zebra_pw *pw)
+{
+ return pw_update_internal(pw, DPLANE_OP_PW_INSTALL);
+}
+
+/*
+ * Enqueue pseudowire un-install for the dataplane.
+ */
+enum zebra_dplane_result dplane_pw_uninstall(struct zebra_pw *pw)
+{
+ return pw_update_internal(pw, DPLANE_OP_PW_UNINSTALL);
+}
+
+/*
* Common internal LSP update utility
*/
static enum zebra_dplane_result lsp_update_internal(zebra_lsp_t *lsp,
@@ -1181,6 +1333,45 @@ done:
}
/*
+ * Internal, common handler for pseudowire updates.
+ */
+static enum zebra_dplane_result pw_update_internal(struct zebra_pw *pw,
+ enum dplane_op_e op)
+{
+ enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
+ int ret;
+ struct zebra_dplane_ctx *ctx = NULL;
+
+ ctx = dplane_ctx_alloc();
+ if (ctx == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = dplane_ctx_pw_init(ctx, op, pw);
+ if (ret != AOK)
+ goto done;
+
+ ret = dplane_route_enqueue(ctx);
+
+done:
+ /* Update counter */
+ atomic_fetch_add_explicit(&zdplane_info.dg_pws_in, 1,
+ memory_order_relaxed);
+
+ if (ret == AOK)
+ result = ZEBRA_DPLANE_REQUEST_QUEUED;
+ else {
+ atomic_fetch_add_explicit(&zdplane_info.dg_pw_errors, 1,
+ memory_order_relaxed);
+ if (ctx)
+ dplane_ctx_free(&ctx);
+ }
+
+ return result;
+}
+
+/*
* Handler for 'show dplane'
*/
int dplane_show_helper(struct vty *vty, bool detailed)
@@ -1512,6 +1703,32 @@ kernel_dplane_lsp_update(struct zebra_dplane_ctx *ctx)
}
/*
+ * Handler for kernel pseudowire updates
+ */
+static enum zebra_dplane_result
+kernel_dplane_pw_update(struct zebra_dplane_ctx *ctx)
+{
+ enum zebra_dplane_result res;
+
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
+ zlog_debug("Dplane pw %s: op %s af %d loc: %u rem: %u",
+ dplane_ctx_get_pw_ifname(ctx),
+ dplane_op2str(ctx->zd_op),
+ dplane_ctx_get_pw_af(ctx),
+ dplane_ctx_get_pw_local_label(ctx),
+ dplane_ctx_get_pw_remote_label(ctx));
+
+ res = kernel_pw_update(ctx);
+
+ if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
+ atomic_fetch_add_explicit(
+ &zdplane_info.dg_pw_errors, 1,
+ memory_order_relaxed);
+
+ return res;
+}
+
+/*
* Handler for kernel route updates
*/
static enum zebra_dplane_result
@@ -1577,6 +1794,11 @@ static int kernel_dplane_process_func(struct zebra_dplane_provider *prov)
res = kernel_dplane_lsp_update(ctx);
break;
+ case DPLANE_OP_PW_INSTALL:
+ case DPLANE_OP_PW_UNINSTALL:
+ res = kernel_dplane_pw_update(ctx);
+ break;
+
default:
atomic_fetch_add_explicit(
&zdplane_info.dg_other_errors, 1,
diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h
index 562a8499a2..81226961e8 100644
--- a/zebra/zebra_dplane.h
+++ b/zebra/zebra_dplane.h
@@ -105,7 +105,11 @@ enum dplane_op_e {
/* LSP update */
DPLANE_OP_LSP_INSTALL,
DPLANE_OP_LSP_UPDATE,
- DPLANE_OP_LSP_DELETE
+ DPLANE_OP_LSP_DELETE,
+
+ /* Pseudowire update */
+ DPLANE_OP_PW_INSTALL,
+ DPLANE_OP_PW_UNINSTALL,
};
/*
@@ -203,6 +207,19 @@ zebra_nhlfe_t *dplane_ctx_get_nhlfe(struct zebra_dplane_ctx *ctx);
zebra_nhlfe_t *dplane_ctx_get_best_nhlfe(struct zebra_dplane_ctx *ctx);
uint32_t dplane_ctx_get_lsp_num_ecmp(const struct zebra_dplane_ctx *ctx);
+/* Accessors for pseudowire information */
+const char *dplane_ctx_get_pw_ifname(const struct zebra_dplane_ctx *ctx);
+mpls_label_t dplane_ctx_get_pw_local_label(const struct zebra_dplane_ctx *ctx);
+mpls_label_t dplane_ctx_get_pw_remote_label(const struct zebra_dplane_ctx *ctx);
+int dplane_ctx_get_pw_type(const struct zebra_dplane_ctx *ctx);
+int dplane_ctx_get_pw_af(const struct zebra_dplane_ctx *ctx);
+uint32_t dplane_ctx_get_pw_flags(const struct zebra_dplane_ctx *ctx);
+int dplane_ctx_get_pw_status(const struct zebra_dplane_ctx *ctx);
+const union g_addr *dplane_ctx_get_pw_nexthop(
+ const struct zebra_dplane_ctx *ctx);
+const union pw_protocol_fields *dplane_ctx_get_pw_proto(
+ const struct zebra_dplane_ctx *ctx);
+
/* Namespace info - esp. for netlink communication */
const struct zebra_dplane_info *dplane_ctx_get_ns(
const struct zebra_dplane_ctx *ctx);
@@ -232,6 +249,12 @@ enum zebra_dplane_result dplane_lsp_add(zebra_lsp_t *lsp);
enum zebra_dplane_result dplane_lsp_update(zebra_lsp_t *lsp);
enum zebra_dplane_result dplane_lsp_delete(zebra_lsp_t *lsp);
+/*
+ * Enqueue pseudowire operations for the dataplane.
+ */
+enum zebra_dplane_result dplane_pw_install(struct zebra_pw *pw);
+enum zebra_dplane_result dplane_pw_uninstall(struct zebra_pw *pw);
+
/* Retrieve the limit on the number of pending, unprocessed updates. */
uint32_t dplane_get_in_queue_limit(void);
diff --git a/zebra/zebra_mpls_netlink.c b/zebra/zebra_mpls_netlink.c
index d8b5ef4ce1..a9233530dc 100644
--- a/zebra/zebra_mpls_netlink.c
+++ b/zebra/zebra_mpls_netlink.c
@@ -61,6 +61,16 @@ done:
ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE);
}
+/*
+ * Pseudowire update api - not supported by netlink as of 12/18,
+ * but note that the default has been to report 'success' for pw updates
+ * on unsupported platforms.
+ */
+enum zebra_dplane_result kernel_pw_update(struct zebra_dplane_ctx *ctx)
+{
+ return ZEBRA_DPLANE_REQUEST_SUCCESS;
+}
+
int mpls_kernel_init(void)
{
struct stat st;
diff --git a/zebra/zebra_mpls_null.c b/zebra/zebra_mpls_null.c
index 409432c4fb..2cc3f3b69d 100644
--- a/zebra/zebra_mpls_null.c
+++ b/zebra/zebra_mpls_null.c
@@ -29,6 +29,15 @@ int mpls_kernel_init(void)
return -1;
};
+/*
+ * Pseudowire update api - note that the default has been
+ * to report 'success' for pw updates on unsupported platforms.
+ */
+enum zebra_dplane_result kernel_pw_update(struct zebra_dplane_ctx *ctx)
+{
+ return ZEBRA_DPLANE_REQUEST_SUCCESS;
+}
+
enum zebra_dplane_result kernel_lsp_update(struct zebra_dplane_ctx *ctx)
{
return ZEBRA_DPLANE_REQUEST_FAILURE;
diff --git a/zebra/zebra_mpls_openbsd.c b/zebra/zebra_mpls_openbsd.c
index da76c6ebf9..72c8f73522 100644
--- a/zebra/zebra_mpls_openbsd.c
+++ b/zebra/zebra_mpls_openbsd.c
@@ -314,16 +314,17 @@ enum zebra_dplane_result kernel_lsp_update(struct zebra_dplane_ctx *ctx)
ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE);
}
-static int kmpw_install(struct zebra_pw *pw)
+static enum zebra_dplane_result kmpw_install(struct zebra_dplane_ctx *ctx)
{
struct ifreq ifr;
struct ifmpwreq imr;
struct sockaddr_storage ss;
struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss;
struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&ss;
+ const union g_addr *gaddr;
memset(&imr, 0, sizeof(imr));
- switch (pw->type) {
+ switch (dplane_ctx_get_pw_type(ctx)) {
case PW_TYPE_ETHERNET:
imr.imr_type = IMR_TYPE_ETHERNET;
break;
@@ -332,67 +333,91 @@ static int kmpw_install(struct zebra_pw *pw)
break;
default:
zlog_debug("%s: unhandled pseudowire type (%#X)", __func__,
- pw->type);
- return -1;
+ dplane_ctx_get_pw_type(ctx));
+ return ZEBRA_DPLANE_REQUEST_FAILURE;
}
- if (pw->flags & F_PSEUDOWIRE_CWORD)
+ if (dplane_ctx_get_pw_flags(ctx) & F_PSEUDOWIRE_CWORD)
imr.imr_flags |= IMR_FLAG_CONTROLWORD;
/* pseudowire nexthop */
memset(&ss, 0, sizeof(ss));
- switch (pw->af) {
+ gaddr = dplane_ctx_get_pw_nexthop(ctx);
+ switch (dplane_ctx_get_pw_af(ctx)) {
case AF_INET:
sa_in->sin_family = AF_INET;
sa_in->sin_len = sizeof(struct sockaddr_in);
- sa_in->sin_addr = pw->nexthop.ipv4;
+ sa_in->sin_addr = gaddr->ipv4;
break;
case AF_INET6:
sa_in6->sin6_family = AF_INET6;
sa_in6->sin6_len = sizeof(struct sockaddr_in6);
- sa_in6->sin6_addr = pw->nexthop.ipv6;
+ sa_in6->sin6_addr = gaddr->ipv6;
break;
default:
zlog_debug("%s: unhandled pseudowire address-family (%u)",
- __func__, pw->af);
- return -1;
+ __func__, dplane_ctx_get_pw_af(ctx));
+ return ZEBRA_DPLANE_REQUEST_FAILURE;
}
memcpy(&imr.imr_nexthop, (struct sockaddr *)&ss,
sizeof(imr.imr_nexthop));
/* pseudowire local/remote labels */
- imr.imr_lshim.shim_label = pw->local_label;
- imr.imr_rshim.shim_label = pw->remote_label;
+ imr.imr_lshim.shim_label = dplane_ctx_get_pw_local_label(ctx);
+ imr.imr_rshim.shim_label = dplane_ctx_get_pw_remote_label(ctx);
/* ioctl */
memset(&ifr, 0, sizeof(ifr));
- strlcpy(ifr.ifr_name, pw->ifname, sizeof(ifr.ifr_name));
+ strlcpy(ifr.ifr_name, dplane_ctx_get_pw_ifname(ctx),
+ sizeof(ifr.ifr_name));
ifr.ifr_data = (caddr_t)&imr;
if (ioctl(kr_state.ioctl_fd, SIOCSETMPWCFG, &ifr) == -1) {
flog_err_sys(EC_LIB_SYSTEM_CALL, "ioctl SIOCSETMPWCFG: %s",
safe_strerror(errno));
- return -1;
+ return ZEBRA_DPLANE_REQUEST_FAILURE;
}
- return 0;
+ return ZEBRA_DPLANE_REQUEST_SUCCESS;
}
-static int kmpw_uninstall(struct zebra_pw *pw)
+static enum zebra_dplane_result kmpw_uninstall(struct zebra_dplane_ctx *ctx)
{
struct ifreq ifr;
struct ifmpwreq imr;
memset(&ifr, 0, sizeof(ifr));
memset(&imr, 0, sizeof(imr));
- strlcpy(ifr.ifr_name, pw->ifname, sizeof(ifr.ifr_name));
+ strlcpy(ifr.ifr_name, dplane_ctx_get_pw_ifname(ctx),
+ sizeof(ifr.ifr_name));
ifr.ifr_data = (caddr_t)&imr;
if (ioctl(kr_state.ioctl_fd, SIOCSETMPWCFG, &ifr) == -1) {
flog_err_sys(EC_LIB_SYSTEM_CALL, "ioctl SIOCSETMPWCFG: %s",
safe_strerror(errno));
- return -1;
+ return ZEBRA_DPLANE_REQUEST_FAILURE;
}
- return 0;
+ return ZEBRA_DPLANE_REQUEST_SUCCESS;
+}
+
+/*
+ * Pseudowire update api for openbsd.
+ */
+enum zebra_dplane_result kernel_pw_update(struct zebra_dplane_ctx *ctx)
+{
+ enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
+
+ switch (dplane_ctx_get_op(ctx)) {
+ case DPLANE_OP_PW_INSTALL:
+ result = kmpw_install(ctx);
+ break;
+ case DPLANE_OP_PW_UNINSTALL:
+ result = kmpw_uninstall(ctx);
+ break;
+ default:
+ break;
+ };
+
+ return result;
}
#define MAX_RTSOCK_BUF 128 * 1024
@@ -431,10 +456,6 @@ int mpls_kernel_init(void)
kr_state.rtseq = 1;
- /* register hook to install/uninstall pseudowires */
- hook_register(pw_install, kmpw_install);
- hook_register(pw_uninstall, kmpw_uninstall);
-
return 0;
}
diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c
index 2d6ec4ec01..006c1da02b 100644
--- a/zebra/zebra_pw.c
+++ b/zebra/zebra_pw.c
@@ -96,9 +96,10 @@ void zebra_pw_del(struct zebra_vrf *zvrf, struct zebra_pw *pw)
zebra_deregister_rnh_pseudowire(pw->vrf_id, pw);
/* uninstall */
- if (pw->status == PW_STATUS_UP)
+ if (pw->status == PW_STATUS_UP) {
hook_call(pw_uninstall, pw);
- else if (pw->install_retry_timer)
+ dplane_pw_uninstall(pw);
+ } else if (pw->install_retry_timer)
THREAD_TIMER_OFF(pw->install_retry_timer);
/* unlink and release memory */
@@ -169,7 +170,8 @@ static void zebra_pw_install(struct zebra_pw *pw)
pw->vrf_id, pw->ifname,
zebra_route_string(pw->protocol));
- if (hook_call(pw_install, pw)) {
+ hook_call(pw_install, pw);
+ if (dplane_pw_install(pw) == ZEBRA_DPLANE_REQUEST_FAILURE) {
zebra_pw_install_failure(pw);
return;
}
@@ -190,6 +192,7 @@ static void zebra_pw_uninstall(struct zebra_pw *pw)
/* ignore any possible error */
hook_call(pw_uninstall, pw);
+ dplane_pw_uninstall(pw);
if (zebra_pw_enabled(pw))
zebra_pw_update_status(pw, PW_STATUS_DOWN);
diff --git a/zebra/zebra_pw.h b/zebra/zebra_pw.h
index e6e0a22c21..9692fb4d40 100644
--- a/zebra/zebra_pw.h
+++ b/zebra/zebra_pw.h
@@ -62,8 +62,8 @@ RB_PROTOTYPE(zebra_static_pw_head, zebra_pw, static_pw_entry, zebra_pw_compare);
DECLARE_HOOK(pw_install, (struct zebra_pw * pw), (pw))
DECLARE_HOOK(pw_uninstall, (struct zebra_pw * pw), (pw))
-struct zebra_pw *zebra_pw_add(struct zebra_vrf *, const char *, uint8_t,
- struct zserv *);
+struct zebra_pw *zebra_pw_add(struct zebra_vrf *zvrf, const char *ifname,
+ uint8_t protocol, struct zserv *client);
void zebra_pw_del(struct zebra_vrf *, struct zebra_pw *);
void zebra_pw_change(struct zebra_pw *, ifindex_t, int, int, union g_addr *,
uint32_t, uint32_t, uint8_t, union pw_protocol_fields *);
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index bccf9b6b14..dcc5a7acb0 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -3229,6 +3229,34 @@ void rib_close_table(struct route_table *table)
}
/*
+ * Handler for async dataplane results after a pseudowire installation
+ */
+static int handle_pw_result(struct zebra_dplane_ctx *ctx)
+{
+ int ret = 0;
+ struct zebra_pw *pw;
+ struct zebra_vrf *vrf;
+
+ /* The pseudowire code assumes success - we act on an error
+ * result for installation attempts here.
+ */
+ if (dplane_ctx_get_op(ctx) != DPLANE_OP_PW_INSTALL)
+ goto done;
+
+ if (dplane_ctx_get_status(ctx) != ZEBRA_DPLANE_REQUEST_SUCCESS) {
+ vrf = zebra_vrf_lookup_by_id(dplane_ctx_get_vrf(ctx));
+ pw = zebra_pw_find(vrf, dplane_ctx_get_pw_ifname(ctx));
+ if (pw)
+ zebra_pw_install_failure(pw);
+ }
+
+done:
+
+ return ret;
+}
+
+
+/*
* Handle results from the dataplane system. Dequeue update context
* structs, dispatch to appropriate internal handlers.
*/
@@ -3239,8 +3267,6 @@ static int rib_process_dplane_results(struct thread *thread)
/* Dequeue a list of completed updates with one lock/unlock cycle */
- /* TODO -- dequeue a list with one lock/unlock cycle? */
-
do {
TAILQ_INIT(&ctxlist);
@@ -3273,6 +3299,11 @@ static int rib_process_dplane_results(struct thread *thread)
zebra_mpls_lsp_dplane_result(ctx);
break;
+ case DPLANE_OP_PW_INSTALL:
+ case DPLANE_OP_PW_UNINSTALL:
+ handle_pw_result(ctx);
+ break;
+
default:
/* Don't expect this: just return the struct? */
dplane_ctx_fini(&ctx);