diff --git a/tests/pytest.ini b/tests/pytest.ini new file mode 100644 index 0000000000..3c436ed5dd --- /dev/null +++ b/tests/pytest.ini @@ -0,0 +1,2 @@ +[pytest] +norecursedirs = topotests diff --git a/tests/topotests/.gitignore b/tests/topotests/.gitignore new file mode 100644 index 0000000000..b1e3c3017c --- /dev/null +++ b/tests/topotests/.gitignore @@ -0,0 +1,4 @@ +.cache +__pycache__ +*.pyc +.pytest_cache diff --git a/tests/topotests/GUIDELINES.md b/tests/topotests/GUIDELINES.md new file mode 100644 index 0000000000..4bd373796c --- /dev/null +++ b/tests/topotests/GUIDELINES.md @@ -0,0 +1,571 @@ +# 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 ): +======================================== +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] + +(Pdb) pp str(tgen.gears[router]) +'TopoGear"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 new file mode 100644 index 0000000000..47668f4bba --- /dev/null +++ b/tests/topotests/README.md @@ -0,0 +1,195 @@ +# FRRouting Topology Tests with Mininet + +## 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 + + # + * 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. diff --git a/tests/topotests/SNIPPETS.md b/tests/topotests/SNIPPETS.md new file mode 100644 index 0000000000..6c16c44af6 --- /dev/null +++ b/tests/topotests/SNIPPETS.md @@ -0,0 +1,275 @@ +# 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/tests/topotests/all-protocol-startup/r1/bgpd.conf b/tests/topotests/all-protocol-startup/r1/bgpd.conf new file mode 100644 index 0000000000..4614287f27 --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/bgpd.conf @@ -0,0 +1,47 @@ +log file bgpd.log +! +! +router bgp 100 + bgp router-id 192.168.0.1 + bgp log-neighbor-changes + neighbor 192.168.7.10 remote-as 100 + neighbor 192.168.7.20 remote-as 200 + neighbor fc00:0:0:8::1000 remote-as 100 + neighbor fc00:0:0:8::2000 remote-as 200 + ! + address-family ipv4 unicast + network 192.168.0.0/24 + neighbor 192.168.7.10 route-map bgp-map in + neighbor 192.168.7.10 filter-list bgp-filter-v4 out + neighbor 192.168.7.20 route-map bgp-map in + neighbor 192.168.7.20 filter-list bgp-filter-v4 out + exit-address-family + ! + address-family ipv6 unicast + network fc00::/64 + neighbor fc00:0:0:8::1000 activate + neighbor fc00:0:0:8::1000 route-map bgp-map in + neighbor fc00:0:0:8::1000 filter-list bgp-filter-v6 out + neighbor fc00:0:0:8::2000 activate + neighbor fc00:0:0:8::2000 route-map bgp-map in + neighbor fc00:0:0:8::2000 filter-list bgp-filter-v6 out + exit-address-family +! +! +ip prefix-list bgp-filter-v4 description dummy-test-prefix-list +ip prefix-list bgp-filter-v4 seq 5 permit 192.168.0.0/24 +! +ipv6 prefix-list bgp-filter-v4 seq 5 permit fc00::/64 +ipv6 prefix-list bgp-filter-v6 description dummy-test-prefix-list-v6 +! +route-map bgp-map permit 10 + set community 100:100 additive + set local-preference 100 +! +route-map bgp-map permit 20 + set metric 10 + set local-preference 200 +! +line vty +! + diff --git a/tests/topotests/all-protocol-startup/r1/isisd.conf b/tests/topotests/all-protocol-startup/r1/isisd.conf new file mode 100644 index 0000000000..413f8d15a9 --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/isisd.conf @@ -0,0 +1,21 @@ +log file isisd.log +! +debug isis events +! +! +interface r1-eth5 + ip router isis test + isis circuit-type level-1 +! +interface r1-eth6 + ipv6 router isis test + isis circuit-type level-2-only +! +! +router isis test + net 00.0001.00b0.64bc.43a0.00 + metric-style wide + log-adjacency-changes +! +line vty +! diff --git a/tests/topotests/all-protocol-startup/r1/ldpd.conf b/tests/topotests/all-protocol-startup/r1/ldpd.conf new file mode 100644 index 0000000000..02332a4e75 --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/ldpd.conf @@ -0,0 +1,25 @@ +log file ldpd.log +! +debug mpls ldp event +debug mpls ldp zebra +! +! +mpls ldp + router-id 192.168.0.1 + ! + address-family ipv4 + discovery transport-address 192.168.9.1 + ! + interface r1-eth9 + ! + ! + address-family ipv6 + discovery transport-address fc00:0:0:9::1 + ! + interface r1-eth9 + ! + ! +! +! +line vty +! diff --git a/tests/topotests/all-protocol-startup/r1/ospf6d.conf b/tests/topotests/all-protocol-startup/r1/ospf6d.conf new file mode 100644 index 0000000000..941d3016c7 --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/ospf6d.conf @@ -0,0 +1,16 @@ +log file ospf6d.log +! +debug ospf6 lsa unknown +debug ospf6 zebra +debug ospf6 interface +debug ospf6 neighbor +! +interface r1-eth4 +! +router ospf6 + ospf6 router-id 192.168.0.1 + log-adjacency-changes + interface r1-eth4 area 0.0.0.0 +! +line vty +! diff --git a/tests/topotests/all-protocol-startup/r1/ospf6d.conf-pre-v4 b/tests/topotests/all-protocol-startup/r1/ospf6d.conf-pre-v4 new file mode 100644 index 0000000000..6d870f355f --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/ospf6d.conf-pre-v4 @@ -0,0 +1,16 @@ +log file ospf6d.log +! +debug ospf6 lsa unknown +debug ospf6 zebra +debug ospf6 interface +debug ospf6 neighbor +! +interface r1-eth4 +! +router ospf6 + router-id 192.168.0.1 + log-adjacency-changes + interface r1-eth4 area 0.0.0.0 +! +line vty +! diff --git a/tests/topotests/all-protocol-startup/r1/ospfd.conf b/tests/topotests/all-protocol-startup/r1/ospfd.conf new file mode 100644 index 0000000000..549f36fab4 --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/ospfd.conf @@ -0,0 +1,13 @@ +log file ospfd.log +! +debug ospf event +debug ospf zebra +! +router ospf + ospf router-id 192.168.0.1 + log-adjacency-changes + network 192.168.0.0/24 area 0.0.0.0 + network 192.168.3.0/24 area 0.0.0.0 +! +line vty +! diff --git a/tests/topotests/all-protocol-startup/r1/rip_status.ref b/tests/topotests/all-protocol-startup/r1/rip_status.ref new file mode 100644 index 0000000000..4a5255fe13 --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/rip_status.ref @@ -0,0 +1,15 @@ +Routing Protocol is "rip" + Sending updates every 30 seconds with +/-50%, next due in XX seconds + Timeout after 180 seconds, garbage collect after 120 seconds + Outgoing update filter list for all interface is not set + Incoming update filter list for all interface is not set + Default redistribution metric is 1 + Redistributing: + Default version control: send version 2, receive version 2 + Interface Send Recv Key-chain + r1-eth1 2 2 + Routing for Networks: + 192.168.1.0/26 + Routing Information Sources: + Gateway BadPackets BadRoutes Distance Last Update + Distance: (default is 120) diff --git a/tests/topotests/all-protocol-startup/r1/ripd.conf b/tests/topotests/all-protocol-startup/r1/ripd.conf new file mode 100644 index 0000000000..4b35630b36 --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/ripd.conf @@ -0,0 +1,12 @@ +log file ripd.log +! +debug rip events +debug rip zebra +! +router rip + version 2 + network 192.168.1.0/26 +! +line vty +! + diff --git a/tests/topotests/all-protocol-startup/r1/ripng_status.ref b/tests/topotests/all-protocol-startup/r1/ripng_status.ref new file mode 100644 index 0000000000..5d67c1467a --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/ripng_status.ref @@ -0,0 +1,14 @@ +Routing Protocol is "RIPng" + Sending updates every 30 seconds with +/-50%, next due in XX seconds + Timeout after 180 seconds, garbage collect after 120 seconds + Outgoing update filter list for all interface is not set + Incoming update filter list for all interface is not set + Default redistribution metric is 1 + Redistributing: + Default version control: send version 1, receive version 1 + Interface Send Recv + r1-eth2 1 1 + Routing for Networks: + fc00:0:0:2::/64 + Routing Information Sources: + Gateway BadPackets BadRoutes Distance Last Update diff --git a/tests/topotests/all-protocol-startup/r1/ripngd.conf b/tests/topotests/all-protocol-startup/r1/ripngd.conf new file mode 100644 index 0000000000..199fe15ab9 --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/ripngd.conf @@ -0,0 +1,11 @@ +log file ripngd.log +! +debug ripng events +debug ripng zebra +! +router ripng + network fc00:0:0:2::/64 +! +line vty +! + diff --git a/tests/topotests/all-protocol-startup/r1/show_bgp_ipv4-post4.1.ref b/tests/topotests/all-protocol-startup/r1/show_bgp_ipv4-post4.1.ref new file mode 100644 index 0000000000..6cc23a465c --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/show_bgp_ipv4-post4.1.ref @@ -0,0 +1,8 @@ +BGP table version is 1, local router ID is 192.168.0.1, vrf id 0 +Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, + i internal, r RIB-failure, S Stale, R Removed +Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self +Origin codes: i - IGP, e - EGP, ? - incomplete + + Network Next Hop Metric LocPrf Weight Path +*> 192.168.0.0 0.0.0.0 0 32768 i diff --git a/tests/topotests/all-protocol-startup/r1/show_bgp_ipv4-post5.0.ref b/tests/topotests/all-protocol-startup/r1/show_bgp_ipv4-post5.0.ref new file mode 100644 index 0000000000..2f348a7b77 --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/show_bgp_ipv4-post5.0.ref @@ -0,0 +1,8 @@ +BGP table version is 1, local router ID is 192.168.0.1, vrf id 0 +Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, + i internal, r RIB-failure, S Stale, R Removed +Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self +Origin codes: i - IGP, e - EGP, ? - incomplete + + Network Next Hop Metric LocPrf Weight Path +*> 192.168.0.0/24 0.0.0.0 0 32768 i diff --git a/tests/topotests/all-protocol-startup/r1/show_bgp_ipv4.ref b/tests/topotests/all-protocol-startup/r1/show_bgp_ipv4.ref new file mode 100644 index 0000000000..3be6cd3d7b --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/show_bgp_ipv4.ref @@ -0,0 +1,7 @@ +BGP table version is 1, local router ID is 192.168.0.1 +Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, + i internal, r RIB-failure, S Stale, R Removed +Origin codes: i - IGP, e - EGP, ? - incomplete + + Network Next Hop Metric LocPrf Weight Path +*> 192.168.0.0 0.0.0.0 0 32768 i diff --git a/tests/topotests/all-protocol-startup/r1/show_bgp_ipv6-post4.1.ref b/tests/topotests/all-protocol-startup/r1/show_bgp_ipv6-post4.1.ref new file mode 100644 index 0000000000..8bb5da72be --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/show_bgp_ipv6-post4.1.ref @@ -0,0 +1,8 @@ +BGP table version is 1, local router ID is 192.168.0.1, vrf id 0 +Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, + i internal, r RIB-failure, S Stale, R Removed +Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self +Origin codes: i - IGP, e - EGP, ? - incomplete + + Network Next Hop Metric LocPrf Weight Path +*> fc00::/64 :: 0 32768 i diff --git a/tests/topotests/all-protocol-startup/r1/show_bgp_ipv6.ref b/tests/topotests/all-protocol-startup/r1/show_bgp_ipv6.ref new file mode 100644 index 0000000000..fffee63c6b --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/show_bgp_ipv6.ref @@ -0,0 +1,7 @@ +BGP table version is 1, local router ID is 192.168.0.1 +Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, + i internal, r RIB-failure, S Stale, R Removed +Origin codes: i - IGP, e - EGP, ? - incomplete + + Network Next Hop Metric LocPrf Weight Path +*> fc00::/64 :: 0 32768 i diff --git a/tests/topotests/all-protocol-startup/r1/show_bgp_ipv6_summary.ref b/tests/topotests/all-protocol-startup/r1/show_bgp_ipv6_summary.ref new file mode 100644 index 0000000000..6777cd9fc3 --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/show_bgp_ipv6_summary.ref @@ -0,0 +1,8 @@ +BGP router identifier 192.168.0.1, local AS number 100 vrf-id 0 +BGP table version 1 +RIB entries 1, using XXXX bytes of memory +Peers 4, using XXXX KiB of memory + +Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd +fc00:0:0:8::1000 4 100 0 0 0 0 0 never Active +fc00:0:0:8::2000 4 200 0 0 0 0 0 never Active diff --git a/tests/topotests/all-protocol-startup/r1/show_ip_bgp_summary.ref b/tests/topotests/all-protocol-startup/r1/show_ip_bgp_summary.ref new file mode 100644 index 0000000000..4f0ac1c910 --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/show_ip_bgp_summary.ref @@ -0,0 +1,10 @@ +BGP router identifier 192.168.0.1, local AS number 100 vrf-id 0 +BGP table version 1 +RIB entries 1, using XXXX bytes of memory +Peers 4, using XXXX KiB of memory + +Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd +192.168.7.10 4 100 0 0 0 0 0 never Active +192.168.7.20 4 200 0 0 0 0 0 never Active +fc00:0:0:8::1000 4 100 0 0 0 0 0 never Active +fc00:0:0:8::2000 4 200 0 0 0 0 0 never Active diff --git a/tests/topotests/all-protocol-startup/r1/show_ip_ospf_interface.ref b/tests/topotests/all-protocol-startup/r1/show_ip_ospf_interface.ref new file mode 100644 index 0000000000..c29ed3db61 --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/show_ip_ospf_interface.ref @@ -0,0 +1,22 @@ +r1-eth0 is up + ifindex 2, MTU 1500 bytes, BW XX Mbit + Internet Address 192.168.0.1/24, Broadcast 192.168.0.255, Area 0.0.0.0 + MTU mismatch detection: enabled + Router ID 192.168.0.1, Network Type BROADCAST, Cost: 10 + Transmit Delay is 1 sec, State DR, Priority 1 + No backup designated router on this network + Multicast group memberships: OSPFAllRouters OSPFDesignatedRouters + Timer intervals configured, Hello 10s, Dead 40s, Wait 40s, Retransmit 5 + Hello due in XX.XXXs + Neighbor Count is 0, Adjacent neighbor count is 0 +r1-eth3 is up + ifindex 5, MTU 1500 bytes, BW XX Mbit + Internet Address 192.168.3.1/26, Broadcast 192.168.3.63, Area 0.0.0.0 + MTU mismatch detection: enabled + Router ID 192.168.0.1, Network Type BROADCAST, Cost: 10 + Transmit Delay is 1 sec, State DR, Priority 1 + No backup designated router on this network + Multicast group memberships: OSPFAllRouters OSPFDesignatedRouters + Timer intervals configured, Hello 10s, Dead 40s, Wait 40s, Retransmit 5 + Hello due in XX.XXXs + Neighbor Count is 0, Adjacent neighbor count is 0 diff --git a/tests/topotests/all-protocol-startup/r1/show_ipv6_ospf6_interface b/tests/topotests/all-protocol-startup/r1/show_ipv6_ospf6_interface new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/topotests/all-protocol-startup/r1/show_ipv6_ospf6_interface.ref b/tests/topotests/all-protocol-startup/r1/show_ipv6_ospf6_interface.ref new file mode 100644 index 0000000000..6fbf40bbb8 --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/show_ipv6_ospf6_interface.ref @@ -0,0 +1,46 @@ +lo is up, type LOOPBACK + Interface ID: 1 + OSPF not enabled on this interface +r1-eth0 is up, type BROADCAST + Interface ID: 2 + OSPF not enabled on this interface +r1-eth1 is up, type BROADCAST + Interface ID: 3 + OSPF not enabled on this interface +r1-eth2 is up, type BROADCAST + Interface ID: 4 + OSPF not enabled on this interface +r1-eth3 is up, type BROADCAST + Interface ID: 5 + OSPF not enabled on this interface +r1-eth4 is up, type BROADCAST + Interface ID: 6 + Internet Address: + inet : 192.168.4.1/26 + inet6: fc00:0:0:4::1/64 + inet6: fe80::XXXX:XXXX:XXXX:XXXX/64 + Instance ID 0, Interface MTU 1500 (autodetect: 1500) + MTU mismatch detection: enabled + Area ID 0.0.0.0, Cost 10 + State DR, Transmit Delay 1 sec, Priority 1 + Timer intervals configured: + Hello 10, Dead 40, Retransmit 5 + DR: 192.168.0.1 BDR: 0.0.0.0 + Number of I/F scoped LSAs is 1 + 0 Pending LSAs for LSUpdate in Time 00:00:00 [thread off] + 0 Pending LSAs for LSAck in Time 00:00:00 [thread off] +r1-eth5 is up, type BROADCAST + Interface ID: 7 + OSPF not enabled on this interface +r1-eth6 is up, type BROADCAST + Interface ID: 8 + OSPF not enabled on this interface +r1-eth7 is up, type BROADCAST + Interface ID: 9 + OSPF not enabled on this interface +r1-eth8 is up, type BROADCAST + Interface ID: 10 + OSPF not enabled on this interface +r1-eth9 is up, type BROADCAST + Interface ID: 11 + OSPF not enabled on this interface diff --git a/tests/topotests/all-protocol-startup/r1/show_isis_interface_detail.ref b/tests/topotests/all-protocol-startup/r1/show_isis_interface_detail.ref new file mode 100644 index 0000000000..0534b64d33 --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/show_isis_interface_detail.ref @@ -0,0 +1,28 @@ +Area test: + Interface: r1-eth5, State: Up, Active, Circuit Id: 0xXX + Type: lan, Level: L1, SNPA: XXXX.XXXX.XXXX + Level-1 Information: + Metric: 10, Active neighbors: 0 + Hello interval: 3, Holddown count: 10 (pad) + CNSP interval: 10, PSNP interval: 2 + LAN Priority: 64, is not DIS + IP Prefix(es): + 192.168.5.1/26 + IPv6 Link-Locals: + fe80::XXXX:XXXX:XXXX:XXXX/64 + IPv6 Prefixes: + fc00:0:0:5::1/64 + + Interface: r1-eth6, State: Up, Active, Circuit Id: 0xXX + Type: lan, Level: L2, SNPA: XXXX.XXXX.XXXX + Level-2 Information: + Metric: 10, Active neighbors: 0 + Hello interval: 3, Holddown count: 10 (pad) + CNSP interval: 10, PSNP interval: 2 + LAN Priority: 64, is not DIS + IP Prefix(es): + 192.168.6.1/26 + IPv6 Link-Locals: + fe80::XXXX:XXXX:XXXX:XXXX/64 + IPv6 Prefixes: + fc00:0:0:6::1/64 diff --git a/tests/topotests/all-protocol-startup/r1/show_mpls_ldp_interface.ref b/tests/topotests/all-protocol-startup/r1/show_mpls_ldp_interface.ref new file mode 100644 index 0000000000..c6bb01c34b --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/show_mpls_ldp_interface.ref @@ -0,0 +1,3 @@ +AF Interface State Uptime Hello Timers ac +ipv4 r1-eth9 ACTIVE xx:xx:xx 5/15 0 +ipv6 r1-eth9 ACTIVE xx:xx:xx 5/15 0 diff --git a/tests/topotests/all-protocol-startup/r1/zebra.conf b/tests/topotests/all-protocol-startup/r1/zebra.conf new file mode 100644 index 0000000000..164104da7e --- /dev/null +++ b/tests/topotests/all-protocol-startup/r1/zebra.conf @@ -0,0 +1,72 @@ +log file zebra.log +! +hostname r1 +! +interface r1-eth0 + description to sw0 - no routing protocol + ip address 192.168.0.1/24 + ipv6 address fc00:0:0:0::1/64 +! +interface r1-eth1 + description to sw1 - RIP interface + ip address 192.168.1.1/26 + ipv6 address fc00:0:0:1::1/64 + no link-detect +! +interface r1-eth2 + description to sw2 - RIPng interface + ip address 192.168.2.1/26 + ipv6 address fc00:0:0:2::1/64 + no link-detect +! +interface r1-eth3 + description to sw3 - OSPFv2 interface + ip address 192.168.3.1/26 + ipv6 address fc00:0:0:3::1/64 + no link-detect +! +interface r1-eth4 + description to sw4 - OSPFv3 interface + ip address 192.168.4.1/26 + ipv6 address fc00:0:0:4::1/64 + no link-detect +! +interface r1-eth5 + description to sw5 - ISIS IPv4 interface + ip address 192.168.5.1/26 + ipv6 address fc00:0:0:5::1/64 + no link-detect +! +interface r1-eth6 + description to sw6 - ISIS IPv6 interface + ip address 192.168.6.1/26 + ipv6 address fc00:0:0:6::1/64 + no link-detect +! +interface r1-eth7 + description to sw7 - BGP IPv4 interface + ip address 192.168.7.1/26 + ipv6 address fc00:0:0:7::1/64 + no link-detect +! +interface r1-eth8 + description to sw8 - BGP IPv6 interface + ip address 192.168.8.1/26 + ipv6 address fc00:0:0:8::1/64 + no link-detect +! +interface r1-eth9 + description to sw9 - LDP interface + ip address 192.168.9.1/26 + ipv6 address fc00:0:0:9::1/64 + + no link-detect +! +! +ip forwarding +ipv6 forwarding +! +! +line vty +! + diff --git a/tests/topotests/all-protocol-startup/test_all_protocol_startup.dot b/tests/topotests/all-protocol-startup/test_all_protocol_startup.dot new file mode 100644 index 0000000000..f39f8f87b8 --- /dev/null +++ b/tests/topotests/all-protocol-startup/test_all_protocol_startup.dot @@ -0,0 +1,61 @@ +## GraphViz file for test_all_protocol_startup +## +## Color coding: +######################### +## Main FRR: #f08080 red +## No protocol: #d0e0d0 gray +## RIP: #19e3d9 Cyan +## RIPng: #fcb314 dark yellow +## OSPFv2: #32b835 Green +## OSPFv3: #19e3d9 Cyan +## ISIS IPv4 #33ff99 light green +## ISIS IPv6 #9a81ec purple +## BGP IPv4 #eee3d3 beige +## BGP IPv6 #fdff00 yellow +## LDP IPv4 #fedbe2 light pink +##### Colors (see http://www.color-hex.com/) + +graph test_all_protocol_startup { + + // title + labelloc="t"; + label="Test Topologoy All Protocols Startup"; + + ###################### + # Routers + ###################### + + # Main FRR Router with all protocols + R1 [shape=doubleoctagon, label="R1 FRR\nMain Router", fillcolor="#f08080", style=filled]; + + ###################### + # Network Lists + ###################### + + SW0_STUB [label="SW0 (no protocol)\n192.168.1.0/24\nfc00:0:0:0::/64", fillcolor="#d0e0d0", style=filled]; + + SW1_RIP [label="SW1 RIP\n192.168.1.0/24\nfc00:0:0:1::/64", fillcolor="#19e3d9", style=filled]; + SW2_RIPNG [label="SW2 RIPng\n192.168.2.0/24\nfc00:0:0:2::/64", fillcolor="#fcb314", style=filled]; + SW3_OSPF [label="SW3 OSPFv2\n192.168.3.0/24\nfc00:0:0:3::/64", fillcolor="#32b835", style=filled]; + SW4_OSPFV3 [label="SW4 OSPFv3\n192.168.4.0/24\nfc00:0:0:4::/64", fillcolor="#19e3d9", style=filled]; + SW5_ISIS_V4 [label="SW5 ISIS IPv4\n192.168.5.0/24\nfc00:0:0:5::/64", fillcolor="#33ff99", style=filled]; + SW6_ISIS_V6 [label="SW6 ISIS IPv6\n192.168.6.0/24\nfc00:0:0:6::/64", fillcolor="#9a81ec", style=filled]; + SW7_BGP_V4 [label="SW7 BGP IPv4\n192.168.7.0/24\nfc00:0:0:7::/64", fillcolor="#eee3d3", style=filled]; + SW8_BGP_V6 [label="SW8 BGP IPv6\n192.168.8.0/24\nfc00:0:0:8::/64", fillcolor="#fdff00", style=filled]; + SW9_LDP [label="SW9 LDP\n192.168.9.0/24\nfc00:0:0:9::/64", fillcolor="#fedbe2", style=filled]; + + ###################### + # Network Connections + ###################### + R1 -- SW0_STUB [label = "eth0\n.1\n::1"]; + R1 -- SW1_RIP [label = "eth1\n.1\n::1"]; + R1 -- SW2_RIPNG [label = "eth2\n.1\n::1"]; + R1 -- SW3_OSPF [label = "eth3\n.1\n::1"]; + R1 -- SW4_OSPFV3 [label = "eth4\n.1\n::1"]; + R1 -- SW5_ISIS_V4 [label = "eth5\n.1\n::1"]; + R1 -- SW6_ISIS_V6 [label = "eth6\n.1\n::1"]; + R1 -- SW7_BGP_V4 [label = "eth7\n.1\n::1"]; + R1 -- SW8_BGP_V6 [label = "eth8\n.1\n::1"]; + R1 -- SW9_LDP [label = "eth9\n.1\n::1"]; + +} diff --git a/tests/topotests/all-protocol-startup/test_all_protocol_startup.pdf b/tests/topotests/all-protocol-startup/test_all_protocol_startup.pdf new file mode 100644 index 0000000000..23f69bcddf Binary files /dev/null and b/tests/topotests/all-protocol-startup/test_all_protocol_startup.pdf differ diff --git a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py new file mode 100755 index 0000000000..fb2100e03d --- /dev/null +++ b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py @@ -0,0 +1,951 @@ +#!/usr/bin/env python + +# +# test_all_protocol_startup.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2017 by +# Network Device Education Foundation, Inc. ("NetDEF") +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_all_protocol_startup.py: Test of all protocols at same time + +""" + +import os +import re +import sys +import pytest +import glob +from time import sleep + +from mininet.topo import Topo +from mininet.net import Mininet +from mininet.node import Node, OVSSwitch, Host +from mininet.log import setLogLevel, info +from mininet.cli import CLI +from mininet.link import Intf + +from functools import partial + +sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +from lib import topotest + +fatal_error = "" + + +##################################################### +## +## Network Topology Definition +## +##################################################### + +class NetworkTopo(Topo): + "All Protocol Startup Test" + + def build(self, **_opts): + + # Setup Routers + router = {} + # + # Setup Main Router + router[1] = topotest.addRouter(self, 'r1') + # + + # Setup Switches + switch = {} + # + for i in range(0, 10): + switch[i] = self.addSwitch('sw%s' % i, cls=topotest.LegacySwitch) + self.addLink(switch[i], router[1], intfName2='r1-eth%s' % i ) + + +##################################################### +## +## Tests starting +## +##################################################### + +def setup_module(module): + global topo, net + global fatal_error + + print("\n\n** %s: Setup Topology" % module.__name__) + print("******************************************\n") + + print("Cleanup old Mininet runs") + os.system('sudo mn -c > /dev/null 2>&1') + os.system('sudo rm /tmp/r* > /dev/null 2>&1') + + thisDir = os.path.dirname(os.path.realpath(__file__)) + topo = NetworkTopo() + + net = Mininet(controller=None, topo=topo) + net.start() + + if net['r1'].get_routertype() != 'frr': + fatal_error = "Test is only implemented for FRR" + sys.stderr.write('\n\nTest is only implemented for FRR - Skipping\n\n') + pytest.skip(fatal_error) + + # Starting Routers + # + # Main router + for i in range(1, 2): + net['r%s' % i].loadConf('zebra', '%s/r%s/zebra.conf' % (thisDir, i)) + net['r%s' % i].loadConf('ripd', '%s/r%s/ripd.conf' % (thisDir, i)) + net['r%s' % i].loadConf('ripngd', '%s/r%s/ripngd.conf' % (thisDir, i)) + net['r%s' % i].loadConf('ospfd', '%s/r%s/ospfd.conf' % (thisDir, i)) + if net['r1'].checkRouterVersion('<', '4.0'): + net['r%s' % i].loadConf('ospf6d', '%s/r%s/ospf6d.conf-pre-v4' % (thisDir, i)) + else: + net['r%s' % i].loadConf('ospf6d', '%s/r%s/ospf6d.conf' % (thisDir, i)) + net['r%s' % i].loadConf('isisd', '%s/r%s/isisd.conf' % (thisDir, i)) + net['r%s' % i].loadConf('bgpd', '%s/r%s/bgpd.conf' % (thisDir, i)) + if net['r%s' % i].daemon_available('ldpd'): + # Only test LDPd if it's installed and Kernel >= 4.5 + net['r%s' % i].loadConf('ldpd', '%s/r%s/ldpd.conf' % (thisDir, i)) + net['r%s' % i].startRouter() + + # For debugging after starting Quagga/FRR daemons, uncomment the next line + # CLI(net) + + +def teardown_module(module): + global net + + print("\n\n** %s: Shutdown Topology" % module.__name__) + print("******************************************\n") + + # End - Shutdown network + net.stop() + + +def test_router_running(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + print("\n\n** Check if FRR/Quagga is running on each Router node") + print("******************************************\n") + sleep(5) + + # Starting Routers + for i in range(1, 2): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_error_messages_vtysh(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + print("\n\n** Check for error messages on VTYSH") + print("******************************************\n") + + failures = 0 + for i in range(1, 2): + # + # First checking Standard Output + # + + # VTYSH output from router + vtystdout = net['r%s' % i].cmd('vtysh -c "show version" 2> /dev/null').rstrip() + + # Fix newlines (make them all the same) + vtystdout = ('\n'.join(vtystdout.splitlines()) + '\n').rstrip() + # Drop everything starting with "FRRouting X.xx" message + vtystdout = re.sub(r"FRRouting [0-9]+.*", "", vtystdout, flags=re.DOTALL) + + if (vtystdout == ''): + print("r%s StdOut ok" % i) + + assert vtystdout == '', "Vtysh StdOut Output check failed for router r%s" % i + + # + # Second checking Standard Error + # + + # VTYSH StdErr output from router + vtystderr = net['r%s' % i].cmd('vtysh -c "show version" > /dev/null').rstrip() + + # Fix newlines (make them all the same) + vtystderr = ('\n'.join(vtystderr.splitlines()) + '\n').rstrip() + # # Drop everything starting with "FRRouting X.xx" message + # vtystderr = re.sub(r"FRRouting [0-9]+.*", "", vtystderr, flags=re.DOTALL) + + if (vtystderr == ''): + print("r%s StdErr ok" % i) + + assert vtystderr == '', "Vtysh StdErr Output check failed for router r%s" % i + + # Make sure that all daemons are running + for i in range(1, 2): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_error_messages_daemons(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + print("\n\n** Check for error messages in daemons") + print("******************************************\n") + + error_logs = "" + + for i in range(1, 2): + log = net['r%s' % i].getStdErr('ripd') + if log: + error_logs += "r%s RIPd StdErr Output:\n" % i + error_logs += log + log = net['r%s' % i].getStdErr('ripngd') + if log: + error_logs += "r%s RIPngd StdErr Output:\n" % i + error_logs += log + log = net['r%s' % i].getStdErr('ospfd') + if log: + error_logs += "r%s OSPFd StdErr Output:\n" % i + error_logs += log + log = net['r%s' % i].getStdErr('ospf6d') + if log: + error_logs += "r%s OSPF6d StdErr Output:\n" % i + error_logs += log + log = net['r%s' % i].getStdErr('isisd') + # ISIS shows debugging enabled status on StdErr + # Remove these messages + log = re.sub(r"^IS-IS .* debugging is on.*", "", log).rstrip() + if log: + error_logs += "r%s ISISd StdErr Output:\n" % i + error_logs += log + log = net['r%s' % i].getStdErr('bgpd') + if log: + error_logs += "r%s BGPd StdErr Output:\n" % i + error_logs += log + if (net['r%s' % i].daemon_available('ldpd')): + log = net['r%s' % i].getStdErr('ldpd') + if log: + error_logs += "r%s LDPd StdErr Output:\n" % i + error_logs += log + log = net['r%s' % i].getStdErr('zebra') + if log: + error_logs += "r%s Zebra StdErr Output:\n" + error_logs += log + + if error_logs: + sys.stderr.write('Failed check for StdErr Output on daemons:\n%s\n' % error_logs) + + # Ignoring the issue if told to ignore (ie not yet fixed) + if (error_logs != ""): + if (os.environ.get('bamboo_TOPOTESTS_ISSUE_349') == "IGNORE"): + sys.stderr.write('Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/349\n') + pytest.skip('Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/349') + + assert error_logs == "", "Daemons report errors to StdErr" + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_converge_protocols(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + print("\n\n** Waiting for protocols convergence") + print("******************************************\n") + + # Not really implemented yet - just sleep 60 secs for now + sleep(60) + + # Make sure that all daemons are running + for i in range(1, 2): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + ## CLI(net) + + +def test_rip_status(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + print("\n\n** Verifying RIP status") + print("******************************************\n") + failures = 0 + for i in range(1, 2): + refTableFile = '%s/r%s/rip_status.ref' % (thisDir, i) + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show ip rip status" 2> /dev/null').rstrip() + # Drop time in next due + actual = re.sub(r"in [0-9]+ seconds", "in XX seconds", actual) + # Drop time in last update + actual = re.sub(r" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual) + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Generate Diff + diff = topotest.get_textdiff(actual, expected, + title1="actual IP RIP status", + title2="expected IP RIP status") + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + sys.stderr.write('r%s failed IP RIP status check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" % i) + + assert failures == 0, "IP RIP status failed for router r%s:\n%s" % (i, diff) + + # Make sure that all daemons are running + for i in range(1, 2): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_ripng_status(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + print("\n\n** Verifying RIPng status") + print("******************************************\n") + failures = 0 + for i in range(1, 2): + refTableFile = '%s/r%s/ripng_status.ref' % (thisDir, i) + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show ipv6 ripng status" 2> /dev/null').rstrip() + # Mask out Link-Local mac address portion. They are random... + actual = re.sub(r" fe80::[0-9a-f:]+", " fe80::XXXX:XXXX:XXXX:XXXX", actual) + # Drop time in next due + actual = re.sub(r"in [0-9]+ seconds", "in XX seconds", actual) + # Drop time in last update + actual = re.sub(r" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", actual) + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Generate Diff + diff = topotest.get_textdiff(actual, expected, + title1="actual IPv6 RIPng status", + title2="expected IPv6 RIPng status") + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + sys.stderr.write('r%s failed IPv6 RIPng status check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" % i) + + assert failures == 0, "IPv6 RIPng status failed for router r%s:\n%s" % (i, diff) + + # Make sure that all daemons are running + for i in range(1, 2): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_ospfv2_interfaces(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + print("\n\n** Verifying OSPFv2 interfaces") + print("******************************************\n") + failures = 0 + for i in range(1, 2): + refTableFile = '%s/r%s/show_ip_ospf_interface.ref' % (thisDir, i) + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show ip ospf interface" 2> /dev/null').rstrip() + # Mask out Bandwidth portion. They may change.. + actual = re.sub(r"BW [0-9]+ Mbit", "BW XX Mbit", actual) + # Drop time in next due + actual = re.sub(r"Hello due in [0-9\.]+s", "Hello due in XX.XXXs", actual) + # Fix 'MTU mismatch detection: enabled' vs 'MTU mismatch detection:enabled' - accept both + actual = re.sub(r"MTU mismatch detection:([a-z]+.*)", r"MTU mismatch detection: \1", actual) + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Generate Diff + diff = topotest.get_textdiff(actual, expected, + title1="actual SHOW IP OSPF INTERFACE", + title2="expected SHOW IP OSPF INTERFACE") + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + sys.stderr.write('r%s failed SHOW IP OSPF INTERFACE check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" % i) + + # Ignoring the issue if told to ignore (ie not yet fixed) + if (failures != 0): + if (os.environ.get('bamboo_TOPOTESTS_ISSUE_348') == "IGNORE"): + sys.stderr.write('Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/348\n') + pytest.skip('Known issue - IGNORING. See https://github.com/FRRouting/frr/issues/348') + + assert failures == 0, "SHOW IP OSPF INTERFACE failed for router r%s:\n%s" % (i, diff) + + # Make sure that all daemons are running + for i in range(1, 2): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_isis_interfaces(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + print("\n\n** Verifying ISIS interfaces") + print("******************************************\n") + failures = 0 + for i in range(1, 2): + refTableFile = '%s/r%s/show_isis_interface_detail.ref' % (thisDir, i) + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show isis interface detail" 2> /dev/null').rstrip() + # Mask out Link-Local mac address portion. They are random... + actual = re.sub(r"fe80::[0-9a-f:]+", "fe80::XXXX:XXXX:XXXX:XXXX", actual) + # Mask out SNPA mac address portion. They are random... + actual = re.sub(r"SNPA: [0-9a-f\.]+", "SNPA: XXXX.XXXX.XXXX", actual) + # Mask out Circuit ID number + actual = re.sub(r"Circuit Id: 0x[0-9]+", "Circuit Id: 0xXX", actual) + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Generate Diff + diff = topotest.get_textdiff(actual, expected, + title1="actual SHOW ISIS INTERFACE DETAIL", + title2="expected SHOW ISIS OSPF6 INTERFACE DETAIL") + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + sys.stderr.write('r%s failed SHOW ISIS INTERFACE DETAIL check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" % i) + + assert failures == 0, "SHOW ISIS INTERFACE DETAIL failed for router r%s:\n%s" % (i, diff) + + # Make sure that all daemons are running + for i in range(1, 2): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_bgp_summary(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + print("\n\n** Verifying BGP Summary") + print("******************************************\n") + failures = 0 + for i in range(1, 2): + refTableFile = '%s/r%s/show_ip_bgp_summary.ref' % (thisDir, i) + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show ip bgp summary" 2> /dev/null').rstrip() + # Mask out "using XXiXX bytes" portion. They are random... + actual = re.sub(r"using [0-9]+ bytes", "using XXXX bytes", actual) + # Mask out "using XiXXX KiB" portion. They are random... + actual = re.sub(r"using [0-9]+ KiB", "using XXXX KiB", actual) + # + # Remove extra summaries which exist with newer versions + # + # Remove summary lines (changed recently) + actual = re.sub(r'Total number.*', '', actual) + actual = re.sub(r'Displayed.*', '', actual) + # Remove IPv4 Unicast Summary (Title only) + actual = re.sub(r'IPv4 Unicast Summary:', '', actual) + # Remove IPv4 Multicast Summary (all of it) + actual = re.sub(r'IPv4 Multicast Summary:', '', actual) + actual = re.sub(r'No IPv4 Multicast neighbor is configured', '', actual) + # Remove IPv4 VPN Summary (all of it) + actual = re.sub(r'IPv4 VPN Summary:', '', actual) + actual = re.sub(r'No IPv4 VPN neighbor is configured', '', actual) + # Remove IPv4 Encap Summary (all of it) + actual = re.sub(r'IPv4 Encap Summary:', '', actual) + actual = re.sub(r'No IPv4 Encap neighbor is configured', '', actual) + # Remove Unknown Summary (all of it) + actual = re.sub(r'Unknown Summary:', '', actual) + actual = re.sub(r'No Unknown neighbor is configured', '', actual) + + actual = re.sub(r'IPv4 labeled-unicast Summary:', '', actual) + actual = re.sub(r'No IPv4 labeled-unicast neighbor is configured', '', actual) + + # Strip empty lines + actual = actual.lstrip() + actual = actual.rstrip() + # + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Generate Diff + diff = topotest.get_textdiff(actual, expected, + title1="actual SHOW IP BGP SUMMARY", + title2="expected SHOW IP BGP SUMMARY") + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + sys.stderr.write('r%s failed SHOW IP BGP SUMMARY check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" % i) + + assert failures == 0, "SHOW IP BGP SUMMARY failed for router r%s:\n%s" % (i, diff) + + # Make sure that all daemons are running + for i in range(1, 2): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_bgp_ipv6_summary(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + print("\n\n** Verifying BGP IPv6 Summary") + print("******************************************\n") + failures = 0 + for i in range(1, 2): + refTableFile = '%s/r%s/show_bgp_ipv6_summary.ref' % (thisDir, i) + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show bgp ipv6 summary" 2> /dev/null').rstrip() + # Mask out "using XXiXX bytes" portion. They are random... + actual = re.sub(r"using [0-9]+ bytes", "using XXXX bytes", actual) + # Mask out "using XiXXX KiB" portion. They are random... + actual = re.sub(r"using [0-9]+ KiB", "using XXXX KiB", actual) + # + # Remove extra summaries which exist with newer versions + # + # Remove summary lines (changed recently) + actual = re.sub(r'Total number.*', '', actual) + actual = re.sub(r'Displayed.*', '', actual) + # Remove IPv4 Unicast Summary (Title only) + actual = re.sub(r'IPv6 Unicast Summary:', '', actual) + # Remove IPv4 Multicast Summary (all of it) + actual = re.sub(r'IPv6 Multicast Summary:', '', actual) + actual = re.sub(r'No IPv6 Multicast neighbor is configured', '', actual) + # Remove IPv4 VPN Summary (all of it) + actual = re.sub(r'IPv6 VPN Summary:', '', actual) + actual = re.sub(r'No IPv6 VPN neighbor is configured', '', actual) + # Remove IPv4 Encap Summary (all of it) + actual = re.sub(r'IPv6 Encap Summary:', '', actual) + actual = re.sub(r'No IPv6 Encap neighbor is configured', '', actual) + # Remove Unknown Summary (all of it) + actual = re.sub(r'Unknown Summary:', '', actual) + actual = re.sub(r'No Unknown neighbor is configured', '', actual) + + # Remove Labeled Unicast Summary (all of it) + actual = re.sub(r'IPv6 labeled-unicast Summary:', '', actual) + actual = re.sub(r'No IPv6 labeled-unicast neighbor is configured', '', actual) + + # Strip empty lines + actual = actual.lstrip() + actual = actual.rstrip() + # + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Generate Diff + diff = topotest.get_textdiff(actual, expected, + title1="actual SHOW BGP IPv6 SUMMARY", + title2="expected SHOW BGP IPv6 SUMMARY") + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + sys.stderr.write('r%s failed SHOW BGP IPv6 SUMMARY check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" % i) + + assert failures == 0, "SHOW BGP IPv6 SUMMARY failed for router r%s:\n%s" % (i, diff) + + # Make sure that all daemons are running + for i in range(1, 2): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_bgp_ipv4(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + print("\n\n** Verifying BGP IPv4") + print("******************************************\n") + diffresult = {} + for i in range(1, 2): + success = 0 + for refTableFile in (glob.glob( + '%s/r%s/show_bgp_ipv4*.ref' % (thisDir, i))): + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show bgp ipv4" 2> /dev/null').rstrip() + # Remove summary line (changed recently) + actual = re.sub(r'Total number.*', '', actual) + actual = re.sub(r'Displayed.*', '', actual) + actual = actual.rstrip() + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Generate Diff + diff = topotest.get_textdiff(actual, expected, + title1="actual SHOW BGP IPv4", + title2="expected SHOW BGP IPv4") + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + diffresult[refTableFile] = diff + else: + success = 1 + print("template %s matched: r%s ok" % (refTableFile, i)) + break + + if not success: + resultstr = 'No template matched.\n' + for f in diffresult.iterkeys(): + resultstr += ( + 'template %s: r%s failed SHOW BGP IPv4 check:\n%s\n' + % (f, i, diffresult[f])) + raise AssertionError( + "SHOW BGP IPv4 failed for router r%s:\n%s" % (i, resultstr)) + + # Make sure that all daemons are running + for i in range(1, 2): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_bgp_ipv6(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + print("\n\n** Verifying BGP IPv6") + print("******************************************\n") + diffresult = {} + for i in range(1, 2): + success = 0 + for refTableFile in (glob.glob( + '%s/r%s/show_bgp_ipv6*.ref' % (thisDir, i))): + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show bgp ipv6" 2> /dev/null').rstrip() + # Remove summary line (changed recently) + actual = re.sub(r'Total number.*', '', actual) + actual = re.sub(r'Displayed.*', '', actual) + actual = actual.rstrip() + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Generate Diff + diff = topotest.get_textdiff(actual, expected, + title1="actual SHOW BGP IPv6", + title2="expected SHOW BGP IPv6") + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + diffresult[refTableFile] = diff + else: + success = 1 + print("template %s matched: r%s ok" % (refTableFile, i)) + + if not success: + resultstr = 'No template matched.\n' + for f in diffresult.iterkeys(): + resultstr += ( + 'template %s: r%s failed SHOW BGP IPv6 check:\n%s\n' + % (f, i, diffresult[f])) + raise AssertionError( + "SHOW BGP IPv6 failed for router r%s:\n%s" % (i, resultstr)) + + # Make sure that all daemons are running + for i in range(1, 2): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + + +def test_mpls_interfaces(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + # Skip if no LDP installed or old kernel + if (net['r1'].daemon_available('ldpd') == False): + pytest.skip("No MPLS or kernel < 4.5") + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + print("\n\n** Verifying MPLS Interfaces") + print("******************************************\n") + failures = 0 + for i in range(1, 2): + refTableFile = '%s/r%s/show_mpls_ldp_interface.ref' % (thisDir, i) + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show mpls ldp interface" 2> /dev/null').rstrip() + # Mask out Timer in Uptime + actual = re.sub(r" [0-9][0-9]:[0-9][0-9]:[0-9][0-9] ", " xx:xx:xx ", actual) + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Generate Diff + diff = topotest.get_textdiff(actual, expected, + title1="actual MPLS LDP interface status", + title2="expected MPLS LDP interface status") + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + sys.stderr.write('r%s failed MPLS LDP Interface status Check:\n%s\n' % (i, diff)) + failures += 1 + else: + print("r%s ok" % i) + + if failures>0: + fatal_error = "MPLS LDP Interface status failed" + + assert failures == 0, "MPLS LDP Interface status failed for router r%s:\n%s" % (i, diff) + + # Make sure that all daemons are running + for i in range(1, 2): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_shutdown_check_stderr(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + print("\n\n** Verifying unexpected STDERR output from daemons") + print("******************************************\n") + + if os.environ.get('TOPOTESTS_CHECK_STDERR') is None: + print("SKIPPED final check on StdErr output: Disabled (TOPOTESTS_CHECK_STDERR undefined)\n") + pytest.skip('Skipping test for Stderr output') + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + print("thisDir=" + thisDir) + + net['r1'].stopRouter() + + log = net['r1'].getStdErr('ripd') + if log: + print("\nRIPd StdErr Log:\n" + log) + log = net['r1'].getStdErr('ripngd') + if log: + print("\nRIPngd StdErr Log:\n" + log) + log = net['r1'].getStdErr('ospfd') + if log: + print("\nOSPFd StdErr Log:\n" + log) + log = net['r1'].getStdErr('ospf6d') + if log: + print("\nOSPF6d StdErr Log:\n" + log) + log = net['r1'].getStdErr('isisd') + if log: + print("\nISISd StdErr Log:\n" + log) + log = net['r1'].getStdErr('bgpd') + if log: + print("\nBGPd StdErr Log:\n" + log) + if (net['r1'].daemon_available('ldpd')): + log = net['r1'].getStdErr('ldpd') + if log: + print("\nLDPd StdErr Log:\n" + log) + log = net['r1'].getStdErr('zebra') + if log: + print("\nZebra StdErr Log:\n" + log) + + +def test_shutdown_check_memleak(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + if os.environ.get('TOPOTESTS_CHECK_MEMLEAK') is None: + print("SKIPPED final check on Memory leaks: Disabled (TOPOTESTS_CHECK_MEMLEAK undefined)\n") + pytest.skip('Skipping test for memory leaks') + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + for i in range(1, 2): + net['r%s' % i].stopRouter() + net['r%s' % i].report_memory_leaks(os.environ.get('TOPOTESTS_CHECK_MEMLEAK'), os.path.basename(__file__)) + + +if __name__ == '__main__': + + setLogLevel('info') + # To suppress tracebacks, either use the following pytest call or add "--tb=no" to cli + # retval = pytest.main(["-s", "--tb=no"]) + retval = pytest.main(["-s"]) + sys.exit(retval) diff --git a/tests/topotests/bfd-topo1/__init__.py b/tests/topotests/bfd-topo1/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/topotests/bfd-topo1/r1/bfdd.conf b/tests/topotests/bfd-topo1/r1/bfdd.conf new file mode 100644 index 0000000000..131b01f0d9 --- /dev/null +++ b/tests/topotests/bfd-topo1/r1/bfdd.conf @@ -0,0 +1,6 @@ +bfd + peer 192.168.0.2 + echo-mode + no shutdown + ! +! diff --git a/tests/topotests/bfd-topo1/r1/bgp_prefixes.json b/tests/topotests/bfd-topo1/r1/bgp_prefixes.json new file mode 100644 index 0000000000..4b2cc1ad62 --- /dev/null +++ b/tests/topotests/bfd-topo1/r1/bgp_prefixes.json @@ -0,0 +1,52 @@ +{ + "routes": { + "10.254.254.2/32": [ + { + "aspath": "102", + "prefix": "10.254.254.2", + "valid": true, + "peerId": "192.168.0.2", + "prefixLen": 32, + "nexthops": [ + { + "ip": "192.168.0.2", + "used": true, + "afi": "ipv4" + } + ] + } + ], + "10.254.254.3/32": [ + { + "aspath": "102 103", + "prefix": "10.254.254.3", + "valid": true, + "peerId": "192.168.0.2", + "prefixLen": 32, + "nexthops": [ + { + "ip": "192.168.0.2", + "used": true, + "afi": "ipv4" + } + ] + } + ], + "10.254.254.4/32": [ + { + "aspath": "102 104", + "prefix": "10.254.254.4", + "valid": true, + "peerId": "192.168.0.2", + "prefixLen": 32, + "nexthops": [ + { + "ip": "192.168.0.2", + "used": true, + "afi": "ipv4" + } + ] + } + ] + } +} diff --git a/tests/topotests/bfd-topo1/r1/bgp_summary.json b/tests/topotests/bfd-topo1/r1/bgp_summary.json new file mode 100644 index 0000000000..fa07d60df9 --- /dev/null +++ b/tests/topotests/bfd-topo1/r1/bgp_summary.json @@ -0,0 +1,11 @@ +{ + "ipv4Unicast": { + "as": 101, + "peers": { + "192.168.0.2": { + "remoteAs": 102, + "state": "Established" + } + } + } +} diff --git a/tests/topotests/bfd-topo1/r1/bgpd.conf b/tests/topotests/bfd-topo1/r1/bgpd.conf new file mode 100644 index 0000000000..78a5611844 --- /dev/null +++ b/tests/topotests/bfd-topo1/r1/bgpd.conf @@ -0,0 +1,7 @@ +router bgp 101 + neighbor 192.168.0.2 remote-as 102 + neighbor 192.168.0.2 bfd + address-family ipv4 unicast + network 10.254.254.1/32 + exit-address-family +! diff --git a/tests/topotests/bfd-topo1/r1/peers.json b/tests/topotests/bfd-topo1/r1/peers.json new file mode 100644 index 0000000000..f49768ff75 --- /dev/null +++ b/tests/topotests/bfd-topo1/r1/peers.json @@ -0,0 +1,8 @@ +[ + { + "remote-receive-interval": 1000, + "remote-transmit-interval": 500, + "peer": "192.168.0.2", + "status": "up" + } +] diff --git a/tests/topotests/bfd-topo1/r1/zebra.conf b/tests/topotests/bfd-topo1/r1/zebra.conf new file mode 100644 index 0000000000..a14cd7ac88 --- /dev/null +++ b/tests/topotests/bfd-topo1/r1/zebra.conf @@ -0,0 +1,3 @@ +interface r1-eth0 + ip address 192.168.0.1/24 +! diff --git a/tests/topotests/bfd-topo1/r2/bfdd.conf b/tests/topotests/bfd-topo1/r2/bfdd.conf new file mode 100644 index 0000000000..cb4357172b --- /dev/null +++ b/tests/topotests/bfd-topo1/r2/bfdd.conf @@ -0,0 +1,12 @@ +bfd + peer 192.168.0.1 + receive-interval 1000 + transmit-interval 500 + echo-mode + no shutdown + ! + peer 192.168.1.1 + echo-mode + no shutdown + ! +! diff --git a/tests/topotests/bfd-topo1/r2/bgp_prefixes.json b/tests/topotests/bfd-topo1/r2/bgp_prefixes.json new file mode 100644 index 0000000000..39f3c0a835 --- /dev/null +++ b/tests/topotests/bfd-topo1/r2/bgp_prefixes.json @@ -0,0 +1,52 @@ +{ + "routes": { + "10.254.254.1/32": [ + { + "aspath": "101", + "prefix": "10.254.254.1", + "valid": true, + "peerId": "192.168.0.1", + "prefixLen": 32, + "nexthops": [ + { + "ip": "192.168.0.1", + "used": true, + "afi": "ipv4" + } + ] + } + ], + "10.254.254.3/32": [ + { + "aspath": "103", + "prefix": "10.254.254.3", + "valid": true, + "peerId": "192.168.1.1", + "prefixLen": 32, + "nexthops": [ + { + "ip": "192.168.1.1", + "used": true, + "afi": "ipv4" + } + ] + } + ], + "10.254.254.4/32": [ + { + "aspath": "104", + "prefix": "10.254.254.4", + "valid": true, + "peerId": "192.168.2.1", + "prefixLen": 32, + "nexthops": [ + { + "ip": "192.168.2.1", + "used": true, + "afi": "ipv4" + } + ] + } + ] + } +} diff --git a/tests/topotests/bfd-topo1/r2/bgp_summary.json b/tests/topotests/bfd-topo1/r2/bgp_summary.json new file mode 100644 index 0000000000..c0ef11ac5f --- /dev/null +++ b/tests/topotests/bfd-topo1/r2/bgp_summary.json @@ -0,0 +1,19 @@ +{ + "ipv4Unicast": { + "as": 102, + "peers": { + "192.168.0.1": { + "remoteAs": 101, + "state": "Established" + }, + "192.168.1.1": { + "remoteAs": 103, + "state": "Established" + }, + "192.168.2.1": { + "remoteAs": 104, + "state": "Established" + } + } + } +} diff --git a/tests/topotests/bfd-topo1/r2/bgpd.conf b/tests/topotests/bfd-topo1/r2/bgpd.conf new file mode 100644 index 0000000000..af10cfaf40 --- /dev/null +++ b/tests/topotests/bfd-topo1/r2/bgpd.conf @@ -0,0 +1,11 @@ +router bgp 102 + neighbor 192.168.0.1 remote-as 101 + neighbor 192.168.0.1 bfd + neighbor 192.168.1.1 remote-as 103 + neighbor 192.168.1.1 bfd + neighbor 192.168.2.1 remote-as 104 + neighbor 192.168.2.1 bfd + address-family ipv4 unicast + network 10.254.254.2/32 + exit-address-family +! diff --git a/tests/topotests/bfd-topo1/r2/peers.json b/tests/topotests/bfd-topo1/r2/peers.json new file mode 100644 index 0000000000..5035d643c5 --- /dev/null +++ b/tests/topotests/bfd-topo1/r2/peers.json @@ -0,0 +1,17 @@ +[ + { + "peer": "192.168.0.1", + "status": "up" + }, + { + "remote-echo-interval": 100, + "peer": "192.168.1.1", + "status": "up" + }, + { + "remote-transmit-interval": 2000, + "remote-receive-interval": 2000, + "peer": "192.168.2.1", + "status": "up" + } +] diff --git a/tests/topotests/bfd-topo1/r2/zebra.conf b/tests/topotests/bfd-topo1/r2/zebra.conf new file mode 100644 index 0000000000..568abe751e --- /dev/null +++ b/tests/topotests/bfd-topo1/r2/zebra.conf @@ -0,0 +1,9 @@ +interface r2-eth0 + ip address 192.168.0.2/24 +! +interface r2-eth1 + ip address 192.168.1.2/24 +! +interface r2-eth2 + ip address 192.168.2.2/24 +! diff --git a/tests/topotests/bfd-topo1/r3/bfdd.conf b/tests/topotests/bfd-topo1/r3/bfdd.conf new file mode 100644 index 0000000000..a5d38c8162 --- /dev/null +++ b/tests/topotests/bfd-topo1/r3/bfdd.conf @@ -0,0 +1,7 @@ +bfd + peer 192.168.1.2 + echo-interval 100 + echo-mode + no shutdown + ! +! diff --git a/tests/topotests/bfd-topo1/r3/bgp_prefixes.json b/tests/topotests/bfd-topo1/r3/bgp_prefixes.json new file mode 100644 index 0000000000..c92d4e052a --- /dev/null +++ b/tests/topotests/bfd-topo1/r3/bgp_prefixes.json @@ -0,0 +1,52 @@ +{ + "routes": { + "10.254.254.1/32": [ + { + "aspath": "102 101", + "prefix": "10.254.254.1", + "valid": true, + "peerId": "192.168.1.2", + "prefixLen": 32, + "nexthops": [ + { + "ip": "192.168.1.2", + "used": true, + "afi": "ipv4" + } + ] + } + ], + "10.254.254.2/32": [ + { + "aspath": "102", + "prefix": "10.254.254.2", + "valid": true, + "peerId": "192.168.1.2", + "prefixLen": 32, + "nexthops": [ + { + "ip": "192.168.1.2", + "used": true, + "afi": "ipv4" + } + ] + } + ], + "10.254.254.4/32": [ + { + "aspath": "102 104", + "prefix": "10.254.254.4", + "valid": true, + "peerId": "192.168.1.2", + "prefixLen": 32, + "nexthops": [ + { + "ip": "192.168.1.2", + "used": true, + "afi": "ipv4" + } + ] + } + ] + } +} diff --git a/tests/topotests/bfd-topo1/r3/bgp_summary.json b/tests/topotests/bfd-topo1/r3/bgp_summary.json new file mode 100644 index 0000000000..d47833377b --- /dev/null +++ b/tests/topotests/bfd-topo1/r3/bgp_summary.json @@ -0,0 +1,11 @@ +{ + "ipv4Unicast": { + "as": 103, + "peers": { + "192.168.1.2": { + "remoteAs": 102, + "state": "Established" + } + } + } +} diff --git a/tests/topotests/bfd-topo1/r3/bgpd.conf b/tests/topotests/bfd-topo1/r3/bgpd.conf new file mode 100644 index 0000000000..041fd7a759 --- /dev/null +++ b/tests/topotests/bfd-topo1/r3/bgpd.conf @@ -0,0 +1,7 @@ +router bgp 103 + neighbor 192.168.1.2 remote-as 102 + neighbor 192.168.1.2 bfd + address-family ipv4 unicast + network 10.254.254.3/32 + exit-address-family +! diff --git a/tests/topotests/bfd-topo1/r3/peers.json b/tests/topotests/bfd-topo1/r3/peers.json new file mode 100644 index 0000000000..ef38008643 --- /dev/null +++ b/tests/topotests/bfd-topo1/r3/peers.json @@ -0,0 +1,6 @@ +[ + { + "peer": "192.168.1.2", + "status": "up" + } +] diff --git a/tests/topotests/bfd-topo1/r3/zebra.conf b/tests/topotests/bfd-topo1/r3/zebra.conf new file mode 100644 index 0000000000..b4fd80fa10 --- /dev/null +++ b/tests/topotests/bfd-topo1/r3/zebra.conf @@ -0,0 +1,3 @@ +interface r3-eth0 + ip address 192.168.1.1/24 +! diff --git a/tests/topotests/bfd-topo1/r4/bfdd.conf b/tests/topotests/bfd-topo1/r4/bfdd.conf new file mode 100644 index 0000000000..029dfba355 --- /dev/null +++ b/tests/topotests/bfd-topo1/r4/bfdd.conf @@ -0,0 +1,7 @@ +bfd + peer 192.168.2.2 + transmit-interval 2000 + receive-interval 2000 + no shutdown + ! +! diff --git a/tests/topotests/bfd-topo1/r4/bgp_prefixes.json b/tests/topotests/bfd-topo1/r4/bgp_prefixes.json new file mode 100644 index 0000000000..cc8510dd61 --- /dev/null +++ b/tests/topotests/bfd-topo1/r4/bgp_prefixes.json @@ -0,0 +1,52 @@ +{ + "routes": { + "10.254.254.1/32": [ + { + "aspath": "102 101", + "prefix": "10.254.254.1", + "valid": true, + "peerId": "192.168.2.2", + "prefixLen": 32, + "nexthops": [ + { + "ip": "192.168.2.2", + "used": true, + "afi": "ipv4" + } + ] + } + ], + "10.254.254.2/32": [ + { + "aspath": "102", + "prefix": "10.254.254.2", + "valid": true, + "peerId": "192.168.2.2", + "prefixLen": 32, + "nexthops": [ + { + "ip": "192.168.2.2", + "used": true, + "afi": "ipv4" + } + ] + } + ], + "10.254.254.3/32": [ + { + "aspath": "102 103", + "prefix": "10.254.254.3", + "valid": true, + "peerId": "192.168.2.2", + "prefixLen": 32, + "nexthops": [ + { + "ip": "192.168.2.2", + "used": true, + "afi": "ipv4" + } + ] + } + ] + } +} diff --git a/tests/topotests/bfd-topo1/r4/bgp_summary.json b/tests/topotests/bfd-topo1/r4/bgp_summary.json new file mode 100644 index 0000000000..7d81784b56 --- /dev/null +++ b/tests/topotests/bfd-topo1/r4/bgp_summary.json @@ -0,0 +1,11 @@ +{ + "ipv4Unicast": { + "as": 104, + "peers": { + "192.168.2.2": { + "remoteAs": 102, + "state": "Established" + } + } + } +} diff --git a/tests/topotests/bfd-topo1/r4/bgpd.conf b/tests/topotests/bfd-topo1/r4/bgpd.conf new file mode 100644 index 0000000000..9c504699ba --- /dev/null +++ b/tests/topotests/bfd-topo1/r4/bgpd.conf @@ -0,0 +1,7 @@ +router bgp 104 + neighbor 192.168.2.2 remote-as 102 + neighbor 192.168.2.2 bfd + address-family ipv4 unicast + network 10.254.254.4/32 + exit-address-family +! diff --git a/tests/topotests/bfd-topo1/r4/peers.json b/tests/topotests/bfd-topo1/r4/peers.json new file mode 100644 index 0000000000..37140089e1 --- /dev/null +++ b/tests/topotests/bfd-topo1/r4/peers.json @@ -0,0 +1,6 @@ +[ + { + "peer": "192.168.2.2", + "status": "up" + } +] diff --git a/tests/topotests/bfd-topo1/r4/zebra.conf b/tests/topotests/bfd-topo1/r4/zebra.conf new file mode 100644 index 0000000000..afdd44b1ab --- /dev/null +++ b/tests/topotests/bfd-topo1/r4/zebra.conf @@ -0,0 +1,3 @@ +interface r4-eth0 + ip address 192.168.2.1/24 +! diff --git a/tests/topotests/bfd-topo1/test_bfd_topo1.dot b/tests/topotests/bfd-topo1/test_bfd_topo1.dot new file mode 100644 index 0000000000..c84ace2780 --- /dev/null +++ b/tests/topotests/bfd-topo1/test_bfd_topo1.dot @@ -0,0 +1,73 @@ +## Color coding: +######################### +## Main FRR: #f08080 red +## Switches: #d0e0d0 gray +## RIP: #19e3d9 Cyan +## RIPng: #fcb314 dark yellow +## OSPFv2: #32b835 Green +## OSPFv3: #19e3d9 Cyan +## ISIS IPv4 #fcb314 dark yellow +## ISIS IPv6 #9a81ec purple +## BGP IPv4 #eee3d3 beige +## BGP IPv6 #fdff00 yellow +##### Colors (see http://www.color-hex.com/) + +graph template { + label="bfd-topo1"; + + # Routers + r1 [ + shape=doubleoctagon, + label="r1", + fillcolor="#f08080", + style=filled, + ]; + r2 [ + shape=doubleoctagon + label="r2", + fillcolor="#f08080", + style=filled, + ]; + r3 [ + shape=doubleoctagon + label="r3", + fillcolor="#f08080", + style=filled, + ]; + r4 [ + shape=doubleoctagon + label="r4", + fillcolor="#f08080", + style=filled, + ]; + + # Switches + sw1 [ + shape=oval, + label="sw1\n192.168.0.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + sw2 [ + shape=oval, + label="sw2\n192.168.1.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + sw3 [ + shape=oval, + label="sw3\n192.168.2.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + + # Connections + r1 -- sw1 [label="eth0\n.1"]; + r2 -- sw1 [label="eth0\n.2"]; + + r3 -- sw2 [label="eth0\n.1"]; + r2 -- sw2 [label="eth1\n.2"]; + + r4 -- sw3 [label="eth0\n.1"]; + r2 -- sw3 [label="eth2\n.2"]; +} diff --git a/tests/topotests/bfd-topo1/test_bfd_topo1.jpg b/tests/topotests/bfd-topo1/test_bfd_topo1.jpg new file mode 100644 index 0000000000..4d6d56e072 Binary files /dev/null and b/tests/topotests/bfd-topo1/test_bfd_topo1.jpg differ diff --git a/tests/topotests/bfd-topo1/test_bfd_topo1.py b/tests/topotests/bfd-topo1/test_bfd_topo1.py new file mode 100644 index 0000000000..91904c6aae --- /dev/null +++ b/tests/topotests/bfd-topo1/test_bfd_topo1.py @@ -0,0 +1,247 @@ +#!/usr/bin/env python + +# +# test_bfd_topo1.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2018 by +# Network Device Education Foundation, Inc. ("NetDEF") +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_bfd_topo1.py: Test the FRR/Quagga BFD daemon. +""" + +import os +import sys +import json +from functools import partial +import pytest + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, '../')) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. +from mininet.topo import Topo + +class BFDTopo(Topo): + "Test topology builder" + def build(self, *_args, **_opts): + "Build function" + tgen = get_topogen(self) + + # Create 4 routers + for routern in range(1, 5): + tgen.add_router('r{}'.format(routern)) + + switch = tgen.add_switch('s1') + switch.add_link(tgen.gears['r1']) + switch.add_link(tgen.gears['r2']) + + switch = tgen.add_switch('s2') + switch.add_link(tgen.gears['r2']) + switch.add_link(tgen.gears['r3']) + + switch = tgen.add_switch('s3') + switch.add_link(tgen.gears['r2']) + switch.add_link(tgen.gears['r4']) + + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(BFDTopo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + for rname, router in router_list.iteritems(): + router.load_config( + TopoRouter.RD_ZEBRA, + os.path.join(CWD, '{}/zebra.conf'.format(rname)) + ) + router.load_config( + TopoRouter.RD_BFD, + os.path.join(CWD, '{}/bfdd.conf'.format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, + os.path.join(CWD, '{}/bgpd.conf'.format(rname)) + ) + + # Initialize all routers. + tgen.start_router() + + # Verify that we are using the proper version and that the BFD + # daemon exists. + for router in router_list.values(): + # Check for Version + if router.has_version('<', '5.1'): + tgen.set_error('Unsupported FRR version') + break + + +def teardown_module(_mod): + "Teardown the pytest environment" + tgen = get_topogen() + tgen.stop_topology() + + +def test_bfd_connection(): + "Assert that the BFD peers can find themselves." + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info('waiting for bfd peers to go up') + + for router in tgen.routers().values(): + json_file = '{}/{}/peers.json'.format(CWD, router.name) + expected = json.loads(open(json_file).read()) + + test_func = partial(topotest.router_json_cmp, + router, 'show bfd peers json', expected) + _, result = topotest.run_and_expect(test_func, None, count=8, wait=0.5) + assertmsg = '"{}" JSON output mismatches'.format(router.name) + assert result is None, assertmsg + + +def test_bgp_convergence(): + "Assert that BGP is converging." + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info('waiting for bgp peers to go up') + + for router in tgen.routers().values(): + ref_file = '{}/{}/bgp_summary.json'.format(CWD, router.name) + expected = json.loads(open(ref_file).read()) + test_func = partial(topotest.router_json_cmp, + router, 'show ip bgp summary json', expected) + _, res = topotest.run_and_expect(test_func, None, count=20, wait=0.5) + assertmsg = '{}: bgp did not converge'.format(router.name) + assert res is None, assertmsg + + +def test_bgp_fast_convergence(): + "Assert that BGP is converging before setting a link down." + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info('waiting for bgp peers converge') + + for router in tgen.routers().values(): + ref_file = '{}/{}/bgp_prefixes.json'.format(CWD, router.name) + expected = json.loads(open(ref_file).read()) + test_func = partial(topotest.router_json_cmp, + router, 'show ip bgp json', expected) + _, res = topotest.run_and_expect(test_func, None, count=40, wait=0.5) + assertmsg = '{}: bgp did not converge'.format(router.name) + assert res is None, assertmsg + + +def test_bfd_fast_convergence(): + """ + Assert that BFD notices the link down after simulating network + failure. + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Disable r1-eth0 link. + tgen.gears['r1'].link_enable('r1-eth0', enabled=False) + + # Wait the minimum time we can before checking that BGP/BFD + # converged. + logger.info('waiting for BFD converge') + + # Check that BGP converged quickly. + for router in tgen.routers().values(): + json_file = '{}/{}/peers.json'.format(CWD, router.name) + expected = json.loads(open(json_file).read()) + + # Load the same file as previous test, but expect R1 to be down. + if router.name == 'r1': + for peer in expected: + if peer['peer'] == '192.168.0.2': + peer['status'] = 'down' + else: + for peer in expected: + if peer['peer'] == '192.168.0.1': + peer['status'] = 'down' + + test_func = partial(topotest.router_json_cmp, + router, 'show bfd peers json', expected) + _, res = topotest.run_and_expect(test_func, None, count=20, wait=0.5) + assertmsg = '"{}" JSON output mismatches'.format(router.name) + assert res is None, assertmsg + + +def test_bgp_fast_reconvergence(): + "Assert that BGP is converging after setting a link down." + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info('waiting for BGP re convergence') + + # Check that BGP converged quickly. + for router in tgen.routers().values(): + ref_file = '{}/{}/bgp_prefixes.json'.format(CWD, router.name) + expected = json.loads(open(ref_file).read()) + + # Load the same file as previous test, but set networks to None + # to test absence. + if router.name == 'r1': + expected['routes']['10.254.254.2/32'] = None + expected['routes']['10.254.254.3/32'] = None + expected['routes']['10.254.254.4/32'] = None + else: + expected['routes']['10.254.254.1/32'] = None + + test_func = partial(topotest.router_json_cmp, + router, 'show ip bgp json', expected) + _, res = topotest.run_and_expect( + test_func, + None, + count=3, + wait=1 + ) + assertmsg = '{}: bgp did not converge'.format(router.name) + assert res is None, assertmsg + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip('Memory leak test/report is disabled') + + tgen.report_memory_leaks() + + +if __name__ == '__main__': + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp-ecmp-topo1/__init__.py b/tests/topotests/bgp-ecmp-topo1/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/topotests/bgp-ecmp-topo1/bgp-ecmp-topo1.dot b/tests/topotests/bgp-ecmp-topo1/bgp-ecmp-topo1.dot new file mode 100644 index 0000000000..90295e199d --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/bgp-ecmp-topo1.dot @@ -0,0 +1,206 @@ +## Color coding: +######################### +## Main FRR: #f08080 red +## Switches: #d0e0d0 gray +## RIP: #19e3d9 Cyan +## RIPng: #fcb314 dark yellow +## OSPFv2: #32b835 Green +## OSPFv3: #19e3d9 Cyan +## ISIS IPv4 #fcb314 dark yellow +## ISIS IPv6 #9a81ec purple +## BGP IPv4 #eee3d3 beige +## BGP IPv6 #fdff00 yellow +##### Colors (see http://www.color-hex.com/) + +graph ospf_ecmp_iBGP_topo1 { + label="bgp ecmp topo1 - eBGP with different AS numbers"; + labelloc="t"; + + # Routers + r1 [ + label="r1\nrtr-id 10.0.255.1/32", + shape=doubleoctagon, + fillcolor="#f08080", + style=filled, + ]; + + # 4 Switches for eBGP Peers + s1 [ + label="s1\n10.0.1.0/24", + shape=oval, + fillcolor="#d0e0d0", + style=filled, + ]; + s2 [ + label="s2\n10.0.2.0/24", + shape=oval, + fillcolor="#d0e0d0", + style=filled, + ]; + s3 [ + label="s3\n10.0.3.0/24", + shape=oval, + fillcolor="#d0e0d0", + style=filled, + ]; + s4 [ + label="s4\n10.0.4.0/24", + shape=oval, + fillcolor="#d0e0d0", + style=filled, + ]; + + # 20 ExaBGP Peers AS 101...120 + peer1 [ + label="eBGP peer1\nAS99\nrtr-id 10.0.1.101/32", + shape=rectangle, + fillcolor="#eee3d3", + style=filled, + ]; + peer2 [ + label="eBGP peer2\nAS99\nrtr-id 10.0.1.102/32", + shape=rectangle, + fillcolor="#eee3d3", + style=filled, + ]; + peer3 [ + label="eBGP peer3\nAS99\nrtr-id 10.0.1.103/32", + shape=rectangle, + fillcolor="#eee3d3", + style=filled, + ]; + peer4 [ + label="eBGP peer4\nAS99\nrtr-id 10.0.1.104/32", + shape=rectangle, + fillcolor="#eee3d3", + style=filled, + ]; + peer5 [ + label="eBGP peer5\nAS99\nrtr-id 10.0.1.105/32", + shape=rectangle, + fillcolor="#eee3d3", + style=filled, + ]; + peer6 [ + label="eBGP peer6\nAS99\nrtr-id 10.0.2.106/32", + shape=rectangle, + fillcolor="#eee3d3", + style=filled, + ]; + peer7 [ + label="eBGP peer7\nAS99\nrtr-id 10.0.2.107/32", + shape=rectangle, + fillcolor="#eee3d3", + style=filled, + ]; + peer8 [ + label="eBGP peer8\nAS99\nrtr-id 10.0.2.108/32", + shape=rectangle, + fillcolor="#eee3d3", + style=filled, + ]; + peer9 [ + label="eBGP peer9\nAS99\nrtr-id 10.0.2.109/32", + shape=rectangle, + fillcolor="#eee3d3", + style=filled, + ]; + peer10 [ + label="eBGP peer10\nAS99\nrtr-id 10.0.2.110/32", + shape=rectangle, + fillcolor="#eee3d3", + style=filled, + ]; + peer11 [ + label="eBGP peer11\nAS111\nrtr-id 10.0.3.111/32", + shape=rectangle, + fillcolor="#eee3d3", + style=filled, + ]; + peer12 [ + label="eBGP peer12\nAS112\nrtr-id 10.0.3.112/32", + shape=rectangle, + fillcolor="#eee3d3", + style=filled, + ]; + peer13 [ + label="eBGP peer13\nAS113\nrtr-id 10.0.3.113/32", + shape=rectangle, + fillcolor="#eee3d3", + style=filled, + ]; + peer14 [ + label="eBGP peer14\nAS114\nrtr-id 10.0.3.114/32", + shape=rectangle, + fillcolor="#eee3d3", + style=filled, + ]; + peer15 [ + label="eBGP peer15\nAS115\nrtr-id 10.0.3.115/32", + shape=rectangle, + fillcolor="#eee3d3", + style=filled, + ]; + peer16 [ + label="eBGP peer16\nAS116\nrtr-id 10.0.4.116/32", + shape=rectangle, + fillcolor="#eee3d3", + style=filled, + ]; + peer17 [ + label="eBGP peer17\nAS117\nrtr-id 10.0.4.117/32", + shape=rectangle, + fillcolor="#eee3d3", + style=filled, + ]; + peer18 [ + label="eBGP peer18\nAS118\nrtr-id 10.0.4.118/32", + shape=rectangle, + fillcolor="#eee3d3", + style=filled, + ]; + peer19 [ + label="eBGP peer19\nAS119\nrtr-id 10.0.4.119/32", + shape=rectangle, + fillcolor="#eee3d3", + style=filled, + ]; + peer20 [ + label="eBGP peer20\nAS120\nrtr-id 10.0.4.120/32", + shape=rectangle, + fillcolor="#eee3d3", + style=filled, + ]; + + # Connections + r1 -- s1 [label="eth0\n.1"]; + r1 -- s2 [label="eth1\n.1"]; + r1 -- s3 [label="eth2\n.1"]; + r1 -- s4 [label="eth3\n.1"]; + + peer1 -- s1 [label="eth0\n.101"]; + peer2 -- s1 [label="eth0\n.102"]; + peer3 -- s1 [label="eth0\n.103"]; + peer4 -- s1 [label="eth0\n.104"]; + peer5 -- s1 [label="eth0\n.105"]; + peer6 -- s2 [label="eth0\n.106"]; + peer7 -- s2 [label="eth0\n.107"]; + peer8 -- s2 [label="eth0\n.108"]; + peer9 -- s2 [label="eth0\n.109"]; + peer10 -- s2 [label="eth0\n.110"]; + peer11 -- s3 [label="eth0\n.111"]; + peer12 -- s3 [label="eth0\n.112"]; + peer13 -- s3 [label="eth0\n.113"]; + peer14 -- s3 [label="eth0\n.114"]; + peer15 -- s3 [label="eth0\n.115"]; + peer16 -- s4 [label="eth0\n.116"]; + peer17 -- s4 [label="eth0\n.117"]; + peer18 -- s4 [label="eth0\n.118"]; + peer19 -- s4 [label="eth0\n.119"]; + peer20 -- s4 [label="eth0\n.120"]; + + # Arrange network to make cleaner diagram + { rank=same peer1 peer2 peer3 peer4 peer5 } -- s1 -- { rank=same peer6 peer7 peer8 peer9 peer10 } -- s2 + -- { rank=same peer11 peer12 peer13 peer14 peer15 } -- s3 -- { rank=same peer16 peer17 peer18 peer19 peer20 } -- s4 + -- { rank=same r1 } [style=invis] +} diff --git a/tests/topotests/bgp-ecmp-topo1/bgp-ecmp-topo1.pdf b/tests/topotests/bgp-ecmp-topo1/bgp-ecmp-topo1.pdf new file mode 100644 index 0000000000..b4d4f6a5e5 Binary files /dev/null and b/tests/topotests/bgp-ecmp-topo1/bgp-ecmp-topo1.pdf differ diff --git a/tests/topotests/bgp-ecmp-topo1/exabgp.env b/tests/topotests/bgp-ecmp-topo1/exabgp.env new file mode 100644 index 0000000000..a328e04962 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/exabgp.env @@ -0,0 +1,54 @@ + +[exabgp.api] +encoder = text +highres = false +respawn = false +socket = '' + +[exabgp.bgp] +openwait = 60 + +[exabgp.cache] +attributes = true +nexthops = true + +[exabgp.daemon] +daemonize = true +pid = '/var/run/exabgp/exabgp.pid' +user = 'exabgp' +##daemonize = false + +[exabgp.log] +all = false +configuration = true +daemon = true +destination = '/var/log/exabgp.log' +enable = true +level = INFO +message = false +network = true +packets = false +parser = false +processes = true +reactor = true +rib = false +routes = false +short = false +timers = false + +[exabgp.pdb] +enable = false + +[exabgp.profile] +enable = false +file = '' + +[exabgp.reactor] +speed = 1.0 + +[exabgp.tcp] +acl = false +bind = '' +delay = 0 +once = false +port = 179 diff --git a/tests/topotests/bgp-ecmp-topo1/peer1/exa-receive.py b/tests/topotests/bgp-ecmp-topo1/peer1/exa-receive.py new file mode 100755 index 0000000000..5334ea5369 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer1/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp-ecmp-topo1/peer1/exa-send.py b/tests/topotests/bgp-ecmp-topo1/peer1/exa-send.py new file mode 100755 index 0000000000..647c254250 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer1/exa-send.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) +if (peer <= 10): + asnum = 99 +else: + asnum = peer+100 + +# Announce numRoutes equal routes per PE - different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.201.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp\n' % (i, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes per PE - different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.202.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.203.%s.0/24 med %i next-hop 10.0.%i.%i origin igp\n' % (i, peer, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.204.%s.0/24 med %i next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, peer, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce 2 different route per peer +stdout.write('announce route 10.205.%i.0/24 next-hop 10.0.%i.%i origin igp\n' % (peer, (((peer-1) / 5) + 1), peer+100)) +stdout.write('announce route 10.206.%i.0/24 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (peer, (((peer-1) / 5) + 1), peer+100, asnum)) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) + diff --git a/tests/topotests/bgp-ecmp-topo1/peer1/exabgp.cfg b/tests/topotests/bgp-ecmp-topo1/peer1/exabgp.cfg new file mode 100644 index 0000000000..2d0ca89f0f --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer1/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa-send.py 1 10"; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 1"; + receive-routes; + encoder text; + } + + neighbor 10.0.1.1 { + router-id 10.0.1.101; + local-address 10.0.1.101; + local-as 99; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp-ecmp-topo1/peer10/exa-receive.py b/tests/topotests/bgp-ecmp-topo1/peer10/exa-receive.py new file mode 100755 index 0000000000..5334ea5369 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer10/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp-ecmp-topo1/peer10/exa-send.py b/tests/topotests/bgp-ecmp-topo1/peer10/exa-send.py new file mode 100755 index 0000000000..647c254250 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer10/exa-send.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) +if (peer <= 10): + asnum = 99 +else: + asnum = peer+100 + +# Announce numRoutes equal routes per PE - different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.201.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp\n' % (i, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes per PE - different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.202.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.203.%s.0/24 med %i next-hop 10.0.%i.%i origin igp\n' % (i, peer, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.204.%s.0/24 med %i next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, peer, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce 2 different route per peer +stdout.write('announce route 10.205.%i.0/24 next-hop 10.0.%i.%i origin igp\n' % (peer, (((peer-1) / 5) + 1), peer+100)) +stdout.write('announce route 10.206.%i.0/24 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (peer, (((peer-1) / 5) + 1), peer+100, asnum)) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) + diff --git a/tests/topotests/bgp-ecmp-topo1/peer10/exabgp.cfg b/tests/topotests/bgp-ecmp-topo1/peer10/exabgp.cfg new file mode 100644 index 0000000000..0c842a0e7f --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer10/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa-send.py 10 10"; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 10"; + receive-routes; + encoder text; + } + + neighbor 10.0.2.1 { + router-id 10.0.2.110; + local-address 10.0.2.110; + local-as 99; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp-ecmp-topo1/peer11/exa-receive.py b/tests/topotests/bgp-ecmp-topo1/peer11/exa-receive.py new file mode 100755 index 0000000000..5334ea5369 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer11/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp-ecmp-topo1/peer11/exa-send.py b/tests/topotests/bgp-ecmp-topo1/peer11/exa-send.py new file mode 100755 index 0000000000..647c254250 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer11/exa-send.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) +if (peer <= 10): + asnum = 99 +else: + asnum = peer+100 + +# Announce numRoutes equal routes per PE - different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.201.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp\n' % (i, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes per PE - different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.202.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.203.%s.0/24 med %i next-hop 10.0.%i.%i origin igp\n' % (i, peer, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.204.%s.0/24 med %i next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, peer, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce 2 different route per peer +stdout.write('announce route 10.205.%i.0/24 next-hop 10.0.%i.%i origin igp\n' % (peer, (((peer-1) / 5) + 1), peer+100)) +stdout.write('announce route 10.206.%i.0/24 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (peer, (((peer-1) / 5) + 1), peer+100, asnum)) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) + diff --git a/tests/topotests/bgp-ecmp-topo1/peer11/exabgp.cfg b/tests/topotests/bgp-ecmp-topo1/peer11/exabgp.cfg new file mode 100644 index 0000000000..936dc572bd --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer11/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa-send.py 11 10"; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 11"; + receive-routes; + encoder text; + } + + neighbor 10.0.3.1 { + router-id 10.0.3.111; + local-address 10.0.3.111; + local-as 111; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp-ecmp-topo1/peer12/exa-receive.py b/tests/topotests/bgp-ecmp-topo1/peer12/exa-receive.py new file mode 100755 index 0000000000..5334ea5369 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer12/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp-ecmp-topo1/peer12/exa-send.py b/tests/topotests/bgp-ecmp-topo1/peer12/exa-send.py new file mode 100755 index 0000000000..647c254250 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer12/exa-send.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) +if (peer <= 10): + asnum = 99 +else: + asnum = peer+100 + +# Announce numRoutes equal routes per PE - different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.201.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp\n' % (i, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes per PE - different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.202.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.203.%s.0/24 med %i next-hop 10.0.%i.%i origin igp\n' % (i, peer, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.204.%s.0/24 med %i next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, peer, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce 2 different route per peer +stdout.write('announce route 10.205.%i.0/24 next-hop 10.0.%i.%i origin igp\n' % (peer, (((peer-1) / 5) + 1), peer+100)) +stdout.write('announce route 10.206.%i.0/24 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (peer, (((peer-1) / 5) + 1), peer+100, asnum)) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) + diff --git a/tests/topotests/bgp-ecmp-topo1/peer12/exabgp.cfg b/tests/topotests/bgp-ecmp-topo1/peer12/exabgp.cfg new file mode 100644 index 0000000000..56b33eae8e --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer12/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa-send.py 12 10"; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 12"; + receive-routes; + encoder text; + } + + neighbor 10.0.3.1 { + router-id 10.0.3.112; + local-address 10.0.3.112; + local-as 112; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp-ecmp-topo1/peer13/exa-receive.py b/tests/topotests/bgp-ecmp-topo1/peer13/exa-receive.py new file mode 100755 index 0000000000..5334ea5369 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer13/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp-ecmp-topo1/peer13/exa-send.py b/tests/topotests/bgp-ecmp-topo1/peer13/exa-send.py new file mode 100755 index 0000000000..647c254250 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer13/exa-send.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) +if (peer <= 10): + asnum = 99 +else: + asnum = peer+100 + +# Announce numRoutes equal routes per PE - different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.201.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp\n' % (i, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes per PE - different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.202.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.203.%s.0/24 med %i next-hop 10.0.%i.%i origin igp\n' % (i, peer, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.204.%s.0/24 med %i next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, peer, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce 2 different route per peer +stdout.write('announce route 10.205.%i.0/24 next-hop 10.0.%i.%i origin igp\n' % (peer, (((peer-1) / 5) + 1), peer+100)) +stdout.write('announce route 10.206.%i.0/24 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (peer, (((peer-1) / 5) + 1), peer+100, asnum)) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) + diff --git a/tests/topotests/bgp-ecmp-topo1/peer13/exabgp.cfg b/tests/topotests/bgp-ecmp-topo1/peer13/exabgp.cfg new file mode 100644 index 0000000000..b933ffb5cf --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer13/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa-send.py 13 10"; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 13"; + receive-routes; + encoder text; + } + + neighbor 10.0.3.1 { + router-id 10.0.3.113; + local-address 10.0.3.113; + local-as 113; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp-ecmp-topo1/peer14/exa-receive.py b/tests/topotests/bgp-ecmp-topo1/peer14/exa-receive.py new file mode 100755 index 0000000000..5334ea5369 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer14/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp-ecmp-topo1/peer14/exa-send.py b/tests/topotests/bgp-ecmp-topo1/peer14/exa-send.py new file mode 100755 index 0000000000..647c254250 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer14/exa-send.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) +if (peer <= 10): + asnum = 99 +else: + asnum = peer+100 + +# Announce numRoutes equal routes per PE - different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.201.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp\n' % (i, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes per PE - different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.202.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.203.%s.0/24 med %i next-hop 10.0.%i.%i origin igp\n' % (i, peer, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.204.%s.0/24 med %i next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, peer, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce 2 different route per peer +stdout.write('announce route 10.205.%i.0/24 next-hop 10.0.%i.%i origin igp\n' % (peer, (((peer-1) / 5) + 1), peer+100)) +stdout.write('announce route 10.206.%i.0/24 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (peer, (((peer-1) / 5) + 1), peer+100, asnum)) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) + diff --git a/tests/topotests/bgp-ecmp-topo1/peer14/exabgp.cfg b/tests/topotests/bgp-ecmp-topo1/peer14/exabgp.cfg new file mode 100644 index 0000000000..bcfa41eb2e --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer14/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa-send.py 14 10"; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 14"; + receive-routes; + encoder text; + } + + neighbor 10.0.3.1 { + router-id 10.0.3.114; + local-address 10.0.3.114; + local-as 114; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp-ecmp-topo1/peer15/exa-receive.py b/tests/topotests/bgp-ecmp-topo1/peer15/exa-receive.py new file mode 100755 index 0000000000..5334ea5369 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer15/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp-ecmp-topo1/peer15/exa-send.py b/tests/topotests/bgp-ecmp-topo1/peer15/exa-send.py new file mode 100755 index 0000000000..647c254250 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer15/exa-send.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) +if (peer <= 10): + asnum = 99 +else: + asnum = peer+100 + +# Announce numRoutes equal routes per PE - different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.201.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp\n' % (i, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes per PE - different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.202.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.203.%s.0/24 med %i next-hop 10.0.%i.%i origin igp\n' % (i, peer, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.204.%s.0/24 med %i next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, peer, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce 2 different route per peer +stdout.write('announce route 10.205.%i.0/24 next-hop 10.0.%i.%i origin igp\n' % (peer, (((peer-1) / 5) + 1), peer+100)) +stdout.write('announce route 10.206.%i.0/24 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (peer, (((peer-1) / 5) + 1), peer+100, asnum)) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) + diff --git a/tests/topotests/bgp-ecmp-topo1/peer15/exabgp.cfg b/tests/topotests/bgp-ecmp-topo1/peer15/exabgp.cfg new file mode 100644 index 0000000000..022e835798 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer15/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa-send.py 15 10"; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 15"; + receive-routes; + encoder text; + } + + neighbor 10.0.3.1 { + router-id 10.0.3.115; + local-address 10.0.3.115; + local-as 115; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp-ecmp-topo1/peer16/exa-receive.py b/tests/topotests/bgp-ecmp-topo1/peer16/exa-receive.py new file mode 100755 index 0000000000..5334ea5369 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer16/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp-ecmp-topo1/peer16/exa-send.py b/tests/topotests/bgp-ecmp-topo1/peer16/exa-send.py new file mode 100755 index 0000000000..647c254250 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer16/exa-send.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) +if (peer <= 10): + asnum = 99 +else: + asnum = peer+100 + +# Announce numRoutes equal routes per PE - different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.201.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp\n' % (i, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes per PE - different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.202.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.203.%s.0/24 med %i next-hop 10.0.%i.%i origin igp\n' % (i, peer, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.204.%s.0/24 med %i next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, peer, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce 2 different route per peer +stdout.write('announce route 10.205.%i.0/24 next-hop 10.0.%i.%i origin igp\n' % (peer, (((peer-1) / 5) + 1), peer+100)) +stdout.write('announce route 10.206.%i.0/24 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (peer, (((peer-1) / 5) + 1), peer+100, asnum)) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) + diff --git a/tests/topotests/bgp-ecmp-topo1/peer16/exabgp.cfg b/tests/topotests/bgp-ecmp-topo1/peer16/exabgp.cfg new file mode 100644 index 0000000000..0649202f1f --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer16/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa-send.py 16 10"; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 16"; + receive-routes; + encoder text; + } + + neighbor 10.0.4.1 { + router-id 10.0.4.116; + local-address 10.0.4.116; + local-as 116; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp-ecmp-topo1/peer17/exa-receive.py b/tests/topotests/bgp-ecmp-topo1/peer17/exa-receive.py new file mode 100755 index 0000000000..5334ea5369 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer17/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp-ecmp-topo1/peer17/exa-send.py b/tests/topotests/bgp-ecmp-topo1/peer17/exa-send.py new file mode 100755 index 0000000000..647c254250 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer17/exa-send.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) +if (peer <= 10): + asnum = 99 +else: + asnum = peer+100 + +# Announce numRoutes equal routes per PE - different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.201.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp\n' % (i, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes per PE - different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.202.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.203.%s.0/24 med %i next-hop 10.0.%i.%i origin igp\n' % (i, peer, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.204.%s.0/24 med %i next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, peer, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce 2 different route per peer +stdout.write('announce route 10.205.%i.0/24 next-hop 10.0.%i.%i origin igp\n' % (peer, (((peer-1) / 5) + 1), peer+100)) +stdout.write('announce route 10.206.%i.0/24 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (peer, (((peer-1) / 5) + 1), peer+100, asnum)) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) + diff --git a/tests/topotests/bgp-ecmp-topo1/peer17/exabgp.cfg b/tests/topotests/bgp-ecmp-topo1/peer17/exabgp.cfg new file mode 100644 index 0000000000..0aeeed9d95 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer17/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa-send.py 17 10"; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 17"; + receive-routes; + encoder text; + } + + neighbor 10.0.4.1 { + router-id 10.0.4.117; + local-address 10.0.4.117; + local-as 117; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp-ecmp-topo1/peer18/exa-receive.py b/tests/topotests/bgp-ecmp-topo1/peer18/exa-receive.py new file mode 100755 index 0000000000..5334ea5369 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer18/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp-ecmp-topo1/peer18/exa-send.py b/tests/topotests/bgp-ecmp-topo1/peer18/exa-send.py new file mode 100755 index 0000000000..647c254250 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer18/exa-send.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) +if (peer <= 10): + asnum = 99 +else: + asnum = peer+100 + +# Announce numRoutes equal routes per PE - different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.201.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp\n' % (i, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes per PE - different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.202.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.203.%s.0/24 med %i next-hop 10.0.%i.%i origin igp\n' % (i, peer, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.204.%s.0/24 med %i next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, peer, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce 2 different route per peer +stdout.write('announce route 10.205.%i.0/24 next-hop 10.0.%i.%i origin igp\n' % (peer, (((peer-1) / 5) + 1), peer+100)) +stdout.write('announce route 10.206.%i.0/24 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (peer, (((peer-1) / 5) + 1), peer+100, asnum)) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) + diff --git a/tests/topotests/bgp-ecmp-topo1/peer18/exabgp.cfg b/tests/topotests/bgp-ecmp-topo1/peer18/exabgp.cfg new file mode 100644 index 0000000000..352c030eda --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer18/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa-send.py 18 10"; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 18"; + receive-routes; + encoder text; + } + + neighbor 10.0.4.1 { + router-id 10.0.4.118; + local-address 10.0.4.118; + local-as 118; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp-ecmp-topo1/peer19/exa-receive.py b/tests/topotests/bgp-ecmp-topo1/peer19/exa-receive.py new file mode 100755 index 0000000000..5334ea5369 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer19/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp-ecmp-topo1/peer19/exa-send.py b/tests/topotests/bgp-ecmp-topo1/peer19/exa-send.py new file mode 100755 index 0000000000..647c254250 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer19/exa-send.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) +if (peer <= 10): + asnum = 99 +else: + asnum = peer+100 + +# Announce numRoutes equal routes per PE - different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.201.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp\n' % (i, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes per PE - different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.202.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.203.%s.0/24 med %i next-hop 10.0.%i.%i origin igp\n' % (i, peer, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.204.%s.0/24 med %i next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, peer, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce 2 different route per peer +stdout.write('announce route 10.205.%i.0/24 next-hop 10.0.%i.%i origin igp\n' % (peer, (((peer-1) / 5) + 1), peer+100)) +stdout.write('announce route 10.206.%i.0/24 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (peer, (((peer-1) / 5) + 1), peer+100, asnum)) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) + diff --git a/tests/topotests/bgp-ecmp-topo1/peer19/exabgp.cfg b/tests/topotests/bgp-ecmp-topo1/peer19/exabgp.cfg new file mode 100644 index 0000000000..9913c226f6 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer19/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa-send.py 19 10"; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 19"; + receive-routes; + encoder text; + } + + neighbor 10.0.4.1 { + router-id 10.0.4.119; + local-address 10.0.4.119; + local-as 119; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp-ecmp-topo1/peer2/exa-receive.py b/tests/topotests/bgp-ecmp-topo1/peer2/exa-receive.py new file mode 100755 index 0000000000..5334ea5369 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer2/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp-ecmp-topo1/peer2/exa-send.py b/tests/topotests/bgp-ecmp-topo1/peer2/exa-send.py new file mode 100755 index 0000000000..647c254250 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer2/exa-send.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) +if (peer <= 10): + asnum = 99 +else: + asnum = peer+100 + +# Announce numRoutes equal routes per PE - different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.201.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp\n' % (i, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes per PE - different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.202.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.203.%s.0/24 med %i next-hop 10.0.%i.%i origin igp\n' % (i, peer, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.204.%s.0/24 med %i next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, peer, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce 2 different route per peer +stdout.write('announce route 10.205.%i.0/24 next-hop 10.0.%i.%i origin igp\n' % (peer, (((peer-1) / 5) + 1), peer+100)) +stdout.write('announce route 10.206.%i.0/24 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (peer, (((peer-1) / 5) + 1), peer+100, asnum)) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) + diff --git a/tests/topotests/bgp-ecmp-topo1/peer2/exabgp.cfg b/tests/topotests/bgp-ecmp-topo1/peer2/exabgp.cfg new file mode 100644 index 0000000000..46b436d2af --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer2/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa-send.py 2 10"; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 2"; + receive-routes; + encoder text; + } + + neighbor 10.0.1.1 { + router-id 10.0.1.102; + local-address 10.0.1.102; + local-as 99; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp-ecmp-topo1/peer20/exa-receive.py b/tests/topotests/bgp-ecmp-topo1/peer20/exa-receive.py new file mode 100755 index 0000000000..5334ea5369 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer20/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp-ecmp-topo1/peer20/exa-send.py b/tests/topotests/bgp-ecmp-topo1/peer20/exa-send.py new file mode 100755 index 0000000000..647c254250 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer20/exa-send.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) +if (peer <= 10): + asnum = 99 +else: + asnum = peer+100 + +# Announce numRoutes equal routes per PE - different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.201.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp\n' % (i, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes per PE - different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.202.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.203.%s.0/24 med %i next-hop 10.0.%i.%i origin igp\n' % (i, peer, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.204.%s.0/24 med %i next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, peer, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce 2 different route per peer +stdout.write('announce route 10.205.%i.0/24 next-hop 10.0.%i.%i origin igp\n' % (peer, (((peer-1) / 5) + 1), peer+100)) +stdout.write('announce route 10.206.%i.0/24 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (peer, (((peer-1) / 5) + 1), peer+100, asnum)) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) + diff --git a/tests/topotests/bgp-ecmp-topo1/peer20/exabgp.cfg b/tests/topotests/bgp-ecmp-topo1/peer20/exabgp.cfg new file mode 100644 index 0000000000..17fb816a75 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer20/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa-send.py 20 10"; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 20"; + receive-routes; + encoder text; + } + + neighbor 10.0.4.1 { + router-id 10.0.4.120; + local-address 10.0.4.120; + local-as 120; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp-ecmp-topo1/peer3/exa-receive.py b/tests/topotests/bgp-ecmp-topo1/peer3/exa-receive.py new file mode 100755 index 0000000000..5334ea5369 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer3/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp-ecmp-topo1/peer3/exa-send.py b/tests/topotests/bgp-ecmp-topo1/peer3/exa-send.py new file mode 100755 index 0000000000..647c254250 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer3/exa-send.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) +if (peer <= 10): + asnum = 99 +else: + asnum = peer+100 + +# Announce numRoutes equal routes per PE - different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.201.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp\n' % (i, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes per PE - different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.202.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.203.%s.0/24 med %i next-hop 10.0.%i.%i origin igp\n' % (i, peer, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.204.%s.0/24 med %i next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, peer, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce 2 different route per peer +stdout.write('announce route 10.205.%i.0/24 next-hop 10.0.%i.%i origin igp\n' % (peer, (((peer-1) / 5) + 1), peer+100)) +stdout.write('announce route 10.206.%i.0/24 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (peer, (((peer-1) / 5) + 1), peer+100, asnum)) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) + diff --git a/tests/topotests/bgp-ecmp-topo1/peer3/exabgp.cfg b/tests/topotests/bgp-ecmp-topo1/peer3/exabgp.cfg new file mode 100644 index 0000000000..acd57756b9 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer3/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa-send.py 3 10"; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 3"; + receive-routes; + encoder text; + } + + neighbor 10.0.1.1 { + router-id 10.0.1.103; + local-address 10.0.1.103; + local-as 99; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp-ecmp-topo1/peer4/exa-receive.py b/tests/topotests/bgp-ecmp-topo1/peer4/exa-receive.py new file mode 100755 index 0000000000..5334ea5369 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer4/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp-ecmp-topo1/peer4/exa-send.py b/tests/topotests/bgp-ecmp-topo1/peer4/exa-send.py new file mode 100755 index 0000000000..647c254250 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer4/exa-send.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) +if (peer <= 10): + asnum = 99 +else: + asnum = peer+100 + +# Announce numRoutes equal routes per PE - different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.201.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp\n' % (i, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes per PE - different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.202.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.203.%s.0/24 med %i next-hop 10.0.%i.%i origin igp\n' % (i, peer, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.204.%s.0/24 med %i next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, peer, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce 2 different route per peer +stdout.write('announce route 10.205.%i.0/24 next-hop 10.0.%i.%i origin igp\n' % (peer, (((peer-1) / 5) + 1), peer+100)) +stdout.write('announce route 10.206.%i.0/24 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (peer, (((peer-1) / 5) + 1), peer+100, asnum)) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) + diff --git a/tests/topotests/bgp-ecmp-topo1/peer4/exabgp.cfg b/tests/topotests/bgp-ecmp-topo1/peer4/exabgp.cfg new file mode 100644 index 0000000000..4c9a989b5a --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer4/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa-send.py 4 10"; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 4"; + receive-routes; + encoder text; + } + + neighbor 10.0.1.1 { + router-id 10.0.1.104; + local-address 10.0.1.104; + local-as 99; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp-ecmp-topo1/peer5/exa-receive.py b/tests/topotests/bgp-ecmp-topo1/peer5/exa-receive.py new file mode 100755 index 0000000000..5334ea5369 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer5/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp-ecmp-topo1/peer5/exa-send.py b/tests/topotests/bgp-ecmp-topo1/peer5/exa-send.py new file mode 100755 index 0000000000..647c254250 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer5/exa-send.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) +if (peer <= 10): + asnum = 99 +else: + asnum = peer+100 + +# Announce numRoutes equal routes per PE - different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.201.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp\n' % (i, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes per PE - different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.202.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.203.%s.0/24 med %i next-hop 10.0.%i.%i origin igp\n' % (i, peer, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.204.%s.0/24 med %i next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, peer, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce 2 different route per peer +stdout.write('announce route 10.205.%i.0/24 next-hop 10.0.%i.%i origin igp\n' % (peer, (((peer-1) / 5) + 1), peer+100)) +stdout.write('announce route 10.206.%i.0/24 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (peer, (((peer-1) / 5) + 1), peer+100, asnum)) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) + diff --git a/tests/topotests/bgp-ecmp-topo1/peer5/exabgp.cfg b/tests/topotests/bgp-ecmp-topo1/peer5/exabgp.cfg new file mode 100644 index 0000000000..eba2aae378 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer5/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa-send.py 5 10"; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 5"; + receive-routes; + encoder text; + } + + neighbor 10.0.1.1 { + router-id 10.0.1.105; + local-address 10.0.1.105; + local-as 99; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp-ecmp-topo1/peer6/exa-receive.py b/tests/topotests/bgp-ecmp-topo1/peer6/exa-receive.py new file mode 100755 index 0000000000..5334ea5369 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer6/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp-ecmp-topo1/peer6/exa-send.py b/tests/topotests/bgp-ecmp-topo1/peer6/exa-send.py new file mode 100755 index 0000000000..647c254250 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer6/exa-send.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) +if (peer <= 10): + asnum = 99 +else: + asnum = peer+100 + +# Announce numRoutes equal routes per PE - different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.201.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp\n' % (i, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes per PE - different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.202.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.203.%s.0/24 med %i next-hop 10.0.%i.%i origin igp\n' % (i, peer, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.204.%s.0/24 med %i next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, peer, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce 2 different route per peer +stdout.write('announce route 10.205.%i.0/24 next-hop 10.0.%i.%i origin igp\n' % (peer, (((peer-1) / 5) + 1), peer+100)) +stdout.write('announce route 10.206.%i.0/24 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (peer, (((peer-1) / 5) + 1), peer+100, asnum)) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) + diff --git a/tests/topotests/bgp-ecmp-topo1/peer6/exabgp.cfg b/tests/topotests/bgp-ecmp-topo1/peer6/exabgp.cfg new file mode 100644 index 0000000000..38b6af0e85 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer6/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa-send.py 6 10"; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 6"; + receive-routes; + encoder text; + } + + neighbor 10.0.2.1 { + router-id 10.0.2.106; + local-address 10.0.2.106; + local-as 99; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp-ecmp-topo1/peer7/exa-receive.py b/tests/topotests/bgp-ecmp-topo1/peer7/exa-receive.py new file mode 100755 index 0000000000..5334ea5369 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer7/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp-ecmp-topo1/peer7/exa-send.py b/tests/topotests/bgp-ecmp-topo1/peer7/exa-send.py new file mode 100755 index 0000000000..647c254250 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer7/exa-send.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) +if (peer <= 10): + asnum = 99 +else: + asnum = peer+100 + +# Announce numRoutes equal routes per PE - different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.201.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp\n' % (i, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes per PE - different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.202.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.203.%s.0/24 med %i next-hop 10.0.%i.%i origin igp\n' % (i, peer, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.204.%s.0/24 med %i next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, peer, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce 2 different route per peer +stdout.write('announce route 10.205.%i.0/24 next-hop 10.0.%i.%i origin igp\n' % (peer, (((peer-1) / 5) + 1), peer+100)) +stdout.write('announce route 10.206.%i.0/24 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (peer, (((peer-1) / 5) + 1), peer+100, asnum)) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) + diff --git a/tests/topotests/bgp-ecmp-topo1/peer7/exabgp.cfg b/tests/topotests/bgp-ecmp-topo1/peer7/exabgp.cfg new file mode 100644 index 0000000000..7631e43750 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer7/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa-send.py 7 10"; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 7"; + receive-routes; + encoder text; + } + + neighbor 10.0.2.1 { + router-id 10.0.2.107; + local-address 10.0.2.107; + local-as 99; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp-ecmp-topo1/peer8/exa-receive.py b/tests/topotests/bgp-ecmp-topo1/peer8/exa-receive.py new file mode 100755 index 0000000000..5334ea5369 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer8/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp-ecmp-topo1/peer8/exa-send.py b/tests/topotests/bgp-ecmp-topo1/peer8/exa-send.py new file mode 100755 index 0000000000..647c254250 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer8/exa-send.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) +if (peer <= 10): + asnum = 99 +else: + asnum = peer+100 + +# Announce numRoutes equal routes per PE - different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.201.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp\n' % (i, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes per PE - different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.202.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.203.%s.0/24 med %i next-hop 10.0.%i.%i origin igp\n' % (i, peer, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.204.%s.0/24 med %i next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, peer, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce 2 different route per peer +stdout.write('announce route 10.205.%i.0/24 next-hop 10.0.%i.%i origin igp\n' % (peer, (((peer-1) / 5) + 1), peer+100)) +stdout.write('announce route 10.206.%i.0/24 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (peer, (((peer-1) / 5) + 1), peer+100, asnum)) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) + diff --git a/tests/topotests/bgp-ecmp-topo1/peer8/exabgp.cfg b/tests/topotests/bgp-ecmp-topo1/peer8/exabgp.cfg new file mode 100644 index 0000000000..1cd1cd9024 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer8/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa-send.py 8 10"; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 8"; + receive-routes; + encoder text; + } + + neighbor 10.0.2.1 { + router-id 10.0.2.108; + local-address 10.0.2.108; + local-as 99; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp-ecmp-topo1/peer9/exa-receive.py b/tests/topotests/bgp-ecmp-topo1/peer9/exa-receive.py new file mode 100755 index 0000000000..5334ea5369 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer9/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp-ecmp-topo1/peer9/exa-send.py b/tests/topotests/bgp-ecmp-topo1/peer9/exa-send.py new file mode 100755 index 0000000000..647c254250 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer9/exa-send.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) +if (peer <= 10): + asnum = 99 +else: + asnum = peer+100 + +# Announce numRoutes equal routes per PE - different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.201.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp\n' % (i, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes per PE - different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.202.%s.0/24 med 100 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.203.%s.0/24 med %i next-hop 10.0.%i.%i origin igp\n' % (i, peer, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +# Announce numRoutes equal routes with different med per PE and different neighbor AS, but same source AS +for i in range(0, numRoutes): + stdout.write('announce route 10.204.%s.0/24 med %i next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (i, peer, (((peer-1) / 5) + 1), peer+100, asnum)) + stdout.flush() + +# Announce 2 different route per peer +stdout.write('announce route 10.205.%i.0/24 next-hop 10.0.%i.%i origin igp\n' % (peer, (((peer-1) / 5) + 1), peer+100)) +stdout.write('announce route 10.206.%i.0/24 next-hop 10.0.%i.%i origin igp as-path [ %i 200 ]\n' % (peer, (((peer-1) / 5) + 1), peer+100, asnum)) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) + diff --git a/tests/topotests/bgp-ecmp-topo1/peer9/exabgp.cfg b/tests/topotests/bgp-ecmp-topo1/peer9/exabgp.cfg new file mode 100644 index 0000000000..5771553962 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/peer9/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa-send.py 9 10"; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 9"; + receive-routes; + encoder text; + } + + neighbor 10.0.2.1 { + router-id 10.0.2.109; + local-address 10.0.2.109; + local-as 99; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp-ecmp-topo1/r1/bgpd.conf b/tests/topotests/bgp-ecmp-topo1/r1/bgpd.conf new file mode 100644 index 0000000000..627dc76c1b --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/r1/bgpd.conf @@ -0,0 +1,30 @@ +! +hostname r1 +log file bgpd.log +! +router bgp 100 + bgp router-id 10.0.255.1 + bgp bestpath as-path multipath-relax + neighbor 10.0.1.101 remote-as 99 + neighbor 10.0.1.102 remote-as 99 + neighbor 10.0.1.103 remote-as 99 + neighbor 10.0.1.104 remote-as 99 + neighbor 10.0.1.105 remote-as 99 + neighbor 10.0.2.106 remote-as 99 + neighbor 10.0.2.107 remote-as 99 + neighbor 10.0.2.108 remote-as 99 + neighbor 10.0.2.109 remote-as 99 + neighbor 10.0.2.110 remote-as 99 + neighbor 10.0.3.111 remote-as 111 + neighbor 10.0.3.112 remote-as 112 + neighbor 10.0.3.113 remote-as 113 + neighbor 10.0.3.114 remote-as 114 + neighbor 10.0.3.115 remote-as 115 + neighbor 10.0.4.116 remote-as 116 + neighbor 10.0.4.117 remote-as 117 + neighbor 10.0.4.118 remote-as 118 + neighbor 10.0.4.119 remote-as 119 + neighbor 10.0.4.120 remote-as 120 + ! +! + diff --git a/tests/topotests/bgp-ecmp-topo1/r1/summary.txt b/tests/topotests/bgp-ecmp-topo1/r1/summary.txt new file mode 100644 index 0000000000..bccc483d52 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/r1/summary.txt @@ -0,0 +1,132 @@ +{ +"ipv4Unicast":{ + "routerId":"10.0.255.1", + "as":100, + "vrfId":0, + "vrfName":"Default", + "peerCount":20, + "peers":{ + "10.0.1.101":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.1.102":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.1.103":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.1.104":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.1.105":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.2.106":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.2.107":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.2.108":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.2.109":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.2.110":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.3.111":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.3.112":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.3.113":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.3.114":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.3.115":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.4.116":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.4.117":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.4.118":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.4.119":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.4.120":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + } + }, + "totalPeers":20 +} +} diff --git a/tests/topotests/bgp-ecmp-topo1/r1/summary20.txt b/tests/topotests/bgp-ecmp-topo1/r1/summary20.txt new file mode 100644 index 0000000000..73ae256abe --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/r1/summary20.txt @@ -0,0 +1,130 @@ +{ + "routerId":"10.0.255.1", + "as":100, + "vrfId":0, + "vrfName":"Default", + "peerCount":20, + "peers":{ + "10.0.1.101":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.1.102":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.1.103":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.1.104":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.1.105":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.2.106":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.2.107":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.2.108":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.2.109":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.2.110":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.3.111":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.3.112":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.3.113":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.3.114":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.3.115":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.4.116":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.4.117":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.4.118":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.4.119":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + }, + "10.0.4.120":{ + "outq":0, + "inq":0, + "prefixReceivedCount":42, + "state":"Established" + } + }, + "totalPeers":20 +} diff --git a/tests/topotests/bgp-ecmp-topo1/r1/zebra.conf b/tests/topotests/bgp-ecmp-topo1/r1/zebra.conf new file mode 100644 index 0000000000..77c76cd490 --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/r1/zebra.conf @@ -0,0 +1,16 @@ +! +hostname r1 +log file zebra.log +! +interface r1-eth0 + ip address 10.0.1.1/24 +! +interface r1-eth1 + ip address 10.0.2.1/24 +! +interface r1-eth2 + ip address 10.0.3.1/24 +! +interface r1-eth3 + ip address 10.0.4.1/24 +! diff --git a/tests/topotests/bgp-ecmp-topo1/test_bgp_ecmp_topo1.py b/tests/topotests/bgp-ecmp-topo1/test_bgp_ecmp_topo1.py new file mode 100755 index 0000000000..d806226dff --- /dev/null +++ b/tests/topotests/bgp-ecmp-topo1/test_bgp_ecmp_topo1.py @@ -0,0 +1,190 @@ +#!/usr/bin/env python + +# +# test_bgp_ecmp_topo1.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2017 by +# Network Device Education Foundation, Inc. ("NetDEF") +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_bgp_ecmp_topo1.py: Test BGP topology with ECMP (Equal Cost MultiPath). +""" + +import json +import functools +import os +import sys +import pytest + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, '../')) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. +from mininet.topo import Topo + +total_ebgp_peers = 20 + +##################################################### +# +# Network Topology Definition +# +##################################################### + + +class BGPECMPTopo1(Topo): + "BGP ECMP Topology 1" + + def build(self, **_opts): + tgen = get_topogen(self) + + # Create the BGP router + router = tgen.add_router('r1') + + # Setup Switches - 1 switch per 5 peering routers + for swNum in range(1, (total_ebgp_peers + 4) / 5 + 1): + switch = tgen.add_switch('s{}'.format(swNum)) + switch.add_link(router) + + # Add 'total_ebgp_peers' number of eBGP ExaBGP neighbors + for peerNum in range(1, total_ebgp_peers+1): + swNum = ((peerNum - 1) / 5 + 1) + + peer_ip = '10.0.{}.{}'.format(swNum, peerNum + 100) + peer_route = 'via 10.0.{}.1'.format(swNum) + peer = tgen.add_exabgp_peer('peer{}'.format(peerNum), + ip=peer_ip, defaultRoute=peer_route) + + switch = tgen.gears['s{}'.format(swNum)] + switch.add_link(peer) + + +##################################################### +# +# Tests starting +# +##################################################### + +def setup_module(module): + tgen = Topogen(BGPECMPTopo1, module.__name__) + tgen.start_topology() + + # Starting Routers + router_list = tgen.routers() + for rname, router in router_list.iteritems(): + router.load_config( + TopoRouter.RD_ZEBRA, + os.path.join(CWD, '{}/zebra.conf'.format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, + os.path.join(CWD, '{}/bgpd.conf'.format(rname)) + ) + router.start() + + # Starting Hosts and init ExaBGP on each of them + topotest.sleep(10, 'starting BGP on all {} peers'.format(total_ebgp_peers)) + peer_list = tgen.exabgp_peers() + for pname, peer in peer_list.iteritems(): + peer_dir = os.path.join(CWD, pname) + env_file = os.path.join(CWD, 'exabgp.env') + peer.start(peer_dir, env_file) + logger.info(pname) + + +def teardown_module(module): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_convergence(): + "Test for BGP topology convergence" + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Expected result + router = tgen.gears['r1'] + if router.has_version('<', '3.0'): + reffile = os.path.join(CWD, 'r1/summary20.txt') + else: + reffile = os.path.join(CWD, 'r1/summary.txt') + + expected = json.loads(open(reffile).read()) + + def _output_summary_cmp(router, cmd, data): + """ + Runs `cmd` that returns JSON data (normally the command ends + with 'json') and compare with `data` contents. + """ + output = router.vtysh_cmd(cmd, isjson=True) + if 'ipv4Unicast' in output: + output['ipv4Unicast']['vrfName'] = \ + output['ipv4Unicast']['vrfName'].replace( + 'default', 'Default') + elif 'vrfName' in output: + output['vrfName'] = output['vrfName'].replace('default', 'Default') + return topotest.json_cmp(output, data) + + test_func = functools.partial( + _output_summary_cmp, router, 'show ip bgp summary json', expected) + _, res = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assertmsg = 'BGP router network did not converge' + assert res is None, assertmsg + + +def test_bgp_ecmp(): + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + expect = { + 'routerId': '10.0.255.1', + 'routes': { + }, + } + + for net in range(1, 5): + for subnet in range(0, 10): + netkey = '10.20{}.{}.0/24'.format(net, subnet) + expect['routes'][netkey] = [] + for _ in range(0, 10): + peer = {'multipath': True, 'valid': True} + expect['routes'][netkey].append(peer) + + test_func = functools.partial(topotest.router_json_cmp, + tgen.gears['r1'], 'show ip bgp json', expect) + _, res = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assertmsg = 'expected multipath routes in "show ip bgp" output' + assert res is None, assertmsg + + +if __name__ == '__main__': + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/__init__.py b/tests/topotests/bgp_l3vpn_to_bgp_direct/__init__.py new file mode 100755 index 0000000000..e69de29bb2 diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/ce1/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/ce1/bgpd.conf new file mode 100644 index 0000000000..bd10248d7b --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/ce1/bgpd.conf @@ -0,0 +1,33 @@ +frr defaults traditional +! +hostname ce1 +password zebra +log stdout notifications +log monitor notifications +log commands +router bgp 5226 + bgp router-id 99.0.0.1 + neighbor 192.168.1.1 remote-as 5226 + neighbor 192.168.1.1 update-source 192.168.1.2 + address-family ipv4 unicast + network 5.1.0.0/24 route-map rm-nh + network 5.1.1.0/24 route-map rm-nh + neighbor 192.168.1.1 activate + exit-address-family +! +access-list al-any permit any +! +route-map rm-nh permit 10 + match ip address al-any + set ip next-hop 99.0.0.1 + set local-preference 123 + set metric 98 + set large-community 12:34:56 + set extcommunity rt 89:123 + set community 0:67 +! + +end + + + diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/ce1/zebra.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/ce1/zebra.conf new file mode 100644 index 0000000000..46831bb711 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/ce1/zebra.conf @@ -0,0 +1,17 @@ +log file zebra.log +! +hostname ce1 +! +interface lo + ip address 99.0.0.1/32 +! +interface ce1-eth0 + description to r1 + ip address 192.168.1.2/24 + no link-detect +! +ip forwarding +! +! +line vty +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/ce2/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/ce2/bgpd.conf new file mode 100644 index 0000000000..ab86c5e1b8 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/ce2/bgpd.conf @@ -0,0 +1,33 @@ +frr defaults traditional +! +hostname ce2 +password zebra +log stdout notifications +log monitor notifications +log commands +router bgp 5226 + bgp router-id 99.0.0.2 + neighbor 192.168.1.1 remote-as 5226 + neighbor 192.168.1.1 update-source 192.168.1.2 + address-family ipv4 unicast + network 5.1.0.0/24 route-map rm-nh + network 5.1.1.0/24 route-map rm-nh + neighbor 192.168.1.1 activate + exit-address-family +! +access-list al-any permit any +! +route-map rm-nh permit 10 + match ip address al-any + set ip next-hop 99.0.0.2 + set local-preference 100 + set metric 100 + set large-community 12:34:56 + set extcommunity rt 89:123 + set community 0:67 +! + +end + + + diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/ce2/zebra.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/ce2/zebra.conf new file mode 100644 index 0000000000..fb4d8cc9c4 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/ce2/zebra.conf @@ -0,0 +1,17 @@ +log file zebra.log +! +hostname ce2 +! +interface lo + ip address 99.0.0.2/32 +! +interface ce2-eth0 + description to r3 + ip address 192.168.1.2/24 + no link-detect +! +ip forwarding +! +! +line vty +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/ce3/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/ce3/bgpd.conf new file mode 100644 index 0000000000..7d239b0bd5 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/ce3/bgpd.conf @@ -0,0 +1,33 @@ +frr defaults traditional +! +hostname ce3 +password zebra +log stdout notifications +log monitor notifications +log commands +router bgp 5226 + bgp router-id 99.0.0.3 + neighbor 192.168.1.1 remote-as 5226 + neighbor 192.168.1.1 update-source 192.168.1.2 + address-family ipv4 unicast + network 5.1.2.0/24 route-map rm-nh + network 5.1.3.0/24 route-map rm-nh + neighbor 192.168.1.1 activate + exit-address-family +! +access-list al-any permit any +! +route-map rm-nh permit 10 + match ip address al-any + set ip next-hop 99.0.0.3 + set local-preference 50 + set metric 200 + set large-community 12:34:56 + set extcommunity rt 89:123 + set community 0:67 +! + +end + + + diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/ce3/zebra.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/ce3/zebra.conf new file mode 100644 index 0000000000..77a1163a4b --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/ce3/zebra.conf @@ -0,0 +1,17 @@ +log file zebra.log +! +hostname ce3 +! +interface lo + ip address 99.0.0.3/32 +! +interface ce3-eth0 + description to r4 + ip address 192.168.1.2/24 + no link-detect +! +ip forwarding +! +! +line vty +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/customize.py b/tests/topotests/bgp_l3vpn_to_bgp_direct/customize.py new file mode 100644 index 0000000000..b4649059bc --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/customize.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python + +# +# Part of NetDEF Topology Tests +# +# Copyright (c) 2017 by +# Network Device Education Foundation, Inc. ("NetDEF") +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +customize.py: Simple FRR/Quagga MPLS L3VPN test topology + + | + +----+----+ + | ce1 | + | 99.0.0.1| CE Router + +----+----+ + 192.168.1. | .2 ce1-eth0 + | .1 r1-eth4 + +---------+ + | r1 | + | 1.1.1.1 | PE Router + +----+----+ + | .1 r1-eth0 + | + ~~~~~~~~~~~~~ + ~~ sw0 ~~ + ~~ 10.0.1.0/24 ~~ + ~~~~~~~~~~~~~ + |10.0.1.0/24 + | + | .2 r2-eth0 + +----+----+ + | r2 | + | 2.2.2.2 | P router + +--+---+--+ + r2-eth2 .2 | | .2 r2-eth1 + ______/ \______ + / \ + ~~~~~~~~~~~~~ ~~~~~~~~~~~~~ +~~ sw2 ~~ ~~ sw1 ~~ +~~ 10.0.3.0/24 ~~ ~~ 10.0.2.0/24 ~~ + ~~~~~~~~~~~~~ ~~~~~~~~~~~~~ + | / | + \ _________/ | + \ / \ +r3-eth1 .3 | | .3 r3-eth0 | .4 r4-eth0 + +----+--+---+ +----+----+ + | r3 | | r4 | + | 3.3.3.3 | | 4.4.4.4 | PE Routers + +-----------+ +---------+ + 192.168.1. | .1 192.168.1. | .1 rX-eth4 + | .2 | .2 ceX-eth0 + +-----+-----+ +----+-----+ + | ce2 | | ce3 | + | 99.0.0.2 | | 99.0.0.3 | CE Routers + +-----+-----+ +----+-----+ + | | + +""" + +import os +import re +import pytest + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger +from lib.ltemplate import ltemplateRtrCmd + +# Required to instantiate the topology builder class. +from mininet.topo import Topo + +import shutil +CWD = os.path.dirname(os.path.realpath(__file__)) +# test name based on directory +TEST = os.path.basename(CWD) + +class ThisTestTopo(Topo): + "Test topology builder" + def build(self, *_args, **_opts): + "Build function" + tgen = get_topogen(self) + + # This function only purpose is to define allocation and relationship + # between routers, switches and hosts. + # + # Create P/PE routers + tgen.add_router('r1') + #check for mpls + if tgen.hasmpls != True: + logger.info('MPLS not available, tests will be skipped') + return + for routern in range(2, 5): + tgen.add_router('r{}'.format(routern)) + # Create CE routers + for routern in range(1, 4): + tgen.add_router('ce{}'.format(routern)) + + #CE/PE links + tgen.add_link(tgen.gears['ce1'], tgen.gears['r1'], 'ce1-eth0', 'r1-eth4') + tgen.add_link(tgen.gears['ce2'], tgen.gears['r3'], 'ce2-eth0', 'r3-eth4') + tgen.add_link(tgen.gears['ce3'], tgen.gears['r4'], 'ce3-eth0', 'r4-eth4') + + # Create a switch with just one router connected to it to simulate a + # empty network. + switch = {} + switch[0] = tgen.add_switch('sw0') + switch[0].add_link(tgen.gears['r1'], nodeif='r1-eth0') + switch[0].add_link(tgen.gears['r2'], nodeif='r2-eth0') + + switch[1] = tgen.add_switch('sw1') + switch[1].add_link(tgen.gears['r2'], nodeif='r2-eth1') + switch[1].add_link(tgen.gears['r3'], nodeif='r3-eth0') + switch[1].add_link(tgen.gears['r4'], nodeif='r4-eth0') + + switch[1] = tgen.add_switch('sw2') + switch[1].add_link(tgen.gears['r2'], nodeif='r2-eth2') + switch[1].add_link(tgen.gears['r3'], nodeif='r3-eth1') + +def ltemplatePreRouterStartHook(): + cc = ltemplateRtrCmd() + tgen = get_topogen() + logger.info('pre router-start hook') + #check for mpls + if tgen.hasmpls != True: + logger.info('MPLS not available, skipping setup') + return False + #check for normal init + if len(tgen.net) == 1: + logger.info('Topology not configured, skipping setup') + return False + #configure r2 mpls interfaces + intfs = ['lo', 'r2-eth0', 'r2-eth1', 'r2-eth2'] + for intf in intfs: + cc.doCmd(tgen, 'r2', 'echo 1 > /proc/sys/net/mpls/conf/{}/input'.format(intf)) + #configure MPLS + rtrs = ['r1', 'r3', 'r4'] + cmds = ['echo 1 > /proc/sys/net/mpls/conf/lo/input'] + for rtr in rtrs: + router = tgen.gears[rtr] + for cmd in cmds: + cc.doCmd(tgen, rtr, cmd) + intfs = ['lo', rtr+'-eth0', rtr+'-eth4'] + for intf in intfs: + cc.doCmd(tgen, rtr, 'echo 1 > /proc/sys/net/mpls/conf/{}/input'.format(intf)) + logger.info('setup mpls input') + return True + +def ltemplatePostRouterStartHook(): + logger.info('post router-start hook') + return True + diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r1/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r1/bgpd.conf new file mode 100644 index 0000000000..7ec941ee6b --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r1/bgpd.conf @@ -0,0 +1,40 @@ +frr defaults traditional +! +hostname r1 +password zebra +log stdout notifications +log monitor notifications +log commands +router bgp 5226 + bgp router-id 1.1.1.1 + bgp cluster-id 1.1.1.1 + neighbor 192.168.1.2 remote-as 5226 + neighbor 192.168.1.2 update-source 192.168.1.1 + neighbor 192.168.1.2 route-reflector-client + neighbor 2.2.2.2 remote-as 5226 + neighbor 2.2.2.2 update-source 1.1.1.1 +! + address-family ipv4 unicast + redistribute vnc-direct + neighbor 192.168.1.2 activate + neighbor 192.168.1.2 next-hop-self + no neighbor 2.2.2.2 activate + exit-address-family +! + address-family ipv4 vpn + neighbor 2.2.2.2 activate + exit-address-family +! + vrf-policy cust1 + label 101 + rd 10:1 + rt both 52:100 + nexthop 192.168.1.1 + exit-vrf-policy +! + vnc export bgp mode group-nve + vnc export bgp group-nve group cust1 + vnc redistribute mode resolve-nve + vnc redistribute ipv4 bgp-direct + ! +end diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r1/ldpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r1/ldpd.conf new file mode 100644 index 0000000000..3c6cbddc2a --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r1/ldpd.conf @@ -0,0 +1,23 @@ +hostname r1 +log file ldpd.log +! +debug mpls ldp zebra +debug mpls ldp event +debug mpls ldp errors +debug mpls ldp messages recv +debug mpls ldp messages sent +debug mpls ldp discovery hello recv +debug mpls ldp discovery hello sent +! +mpls ldp + router-id 1.1.1.1 + ! + address-family ipv4 + discovery transport-address 1.1.1.1 + ! + interface r1-eth0 + ! + ! +! +line vty +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r1/ospfd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r1/ospfd.conf new file mode 100644 index 0000000000..c5097e214f --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r1/ospfd.conf @@ -0,0 +1,8 @@ +hostname r1 +log file ospfd.log +! +router ospf + router-id 1.1.1.1 + network 0.0.0.0/4 area 0 + redistribute static +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r1/zebra.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r1/zebra.conf new file mode 100644 index 0000000000..18f61e0c54 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r1/zebra.conf @@ -0,0 +1,24 @@ +log file zebra.log +! +hostname r1 +! +interface lo + ip address 1.1.1.1/32 +! +interface r1-eth0 + description to sw0 + ip address 10.0.1.1/24 + no link-detect +! +interface r1-eth4 + description to ce1 + ip address 192.168.1.1/24 + no link-detect +! +ip route 99.0.0.1/32 192.168.1.2 +! +ip forwarding +! +! +line vty +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r2/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r2/bgpd.conf new file mode 100644 index 0000000000..241c2ac0ae --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r2/bgpd.conf @@ -0,0 +1,33 @@ +frr defaults traditional +! +hostname r2 +password zebra +log stdout notifications +log monitor notifications +log commands +router bgp 5226 + bgp router-id 2.2.2.2 + bgp cluster-id 2.2.2.2 + neighbor 1.1.1.1 remote-as 5226 + neighbor 1.1.1.1 update-source 2.2.2.2 + neighbor 3.3.3.3 remote-as 5226 + neighbor 3.3.3.3 update-source 2.2.2.2 + neighbor 4.4.4.4 remote-as 5226 + neighbor 4.4.4.4 update-source 2.2.2.2 + address-family ipv4 unicast + no neighbor 1.1.1.1 activate + no neighbor 3.3.3.3 activate + no neighbor 4.4.4.4 activate + exit-address-family + address-family ipv4 vpn + neighbor 1.1.1.1 activate + neighbor 1.1.1.1 route-reflector-client + neighbor 3.3.3.3 activate + neighbor 3.3.3.3 route-reflector-client + neighbor 4.4.4.4 activate + neighbor 4.4.4.4 route-reflector-client + exit-address-family +end + + + diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r2/ldpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r2/ldpd.conf new file mode 100644 index 0000000000..bfdef21b75 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r2/ldpd.conf @@ -0,0 +1,25 @@ +hostname r2 +log file ldpd.log +! +debug mpls ldp zebra +debug mpls ldp event +debug mpls ldp errors +debug mpls ldp messages recv +debug mpls ldp messages sent +debug mpls ldp discovery hello recv +debug mpls ldp discovery hello sent +! +mpls ldp + router-id 2.2.2.2 + ! + address-family ipv4 + discovery transport-address 2.2.2.2 + ! + interface r2-eth0 + ! + interface r2-eth1 + ! + ! +! +line vty +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r2/ospfd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r2/ospfd.conf new file mode 100644 index 0000000000..8678813665 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r2/ospfd.conf @@ -0,0 +1,7 @@ +hostname r2 +log file ospfd.log +! +router ospf + router-id 2.2.2.2 + network 0.0.0.0/0 area 0 +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r2/zebra.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r2/zebra.conf new file mode 100644 index 0000000000..dd1dbac32b --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r2/zebra.conf @@ -0,0 +1,27 @@ +log file zebra.log +! +hostname r2 +! +interface lo + ip address 2.2.2.2/32 +! +interface r2-eth0 + description to sw0 + ip address 10.0.1.2/24 + no link-detect +! +interface r2-eth1 + description to sw1 + ip address 10.0.2.2/24 + no link-detect +! +interface r2-eth2 + description to sw2 + ip address 10.0.3.2/24 + no link-detect +! +ip forwarding +! +! +line vty +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r3/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r3/bgpd.conf new file mode 100644 index 0000000000..5591c633c6 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r3/bgpd.conf @@ -0,0 +1,42 @@ +frr defaults traditional +! +hostname r3 +password zebra +log stdout notifications +log monitor notifications +log commands +router bgp 5226 + bgp router-id 3.3.3.3 + bgp cluster-id 3.3.3.3 + neighbor 192.168.1.2 remote-as 5226 + neighbor 192.168.1.2 update-source 192.168.1.2 + neighbor 192.168.1.2 route-reflector-client + neighbor 2.2.2.2 remote-as 5226 + neighbor 2.2.2.2 update-source 3.3.3.3 +! + address-family ipv4 unicast + redistribute vnc-direct + neighbor 192.168.1.2 activate + neighbor 192.168.1.2 next-hop-self + no neighbor 2.2.2.2 activate + exit-address-family + address-family ipv4 vpn + neighbor 2.2.2.2 activate + exit-address-family +! + vrf-policy cust1 + label 103 + rd 10:3 + rt both 52:100 + nexthop 192.168.1.1 + exit-vrf-policy +! + vnc export bgp mode group-nve + vnc export bgp group-nve group cust1 + vnc redistribute mode resolve-nve + vnc redistribute ipv4 bgp-direct +! +end + + + diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r3/ldpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r3/ldpd.conf new file mode 100644 index 0000000000..dbf1d72b5f --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r3/ldpd.conf @@ -0,0 +1,23 @@ +hostname r3 +log file ldpd.log +! +debug mpls ldp zebra +debug mpls ldp event +debug mpls ldp errors +debug mpls ldp messages recv +debug mpls ldp messages sent +debug mpls ldp discovery hello recv +debug mpls ldp discovery hello sent +! +mpls ldp + router-id 3.3.3.3 + ! + address-family ipv4 + discovery transport-address 3.3.3.3 + ! + interface r3-eth0 + ! + ! +! +line vty +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r3/ospfd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r3/ospfd.conf new file mode 100644 index 0000000000..c7c358f9dc --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r3/ospfd.conf @@ -0,0 +1,9 @@ +hostname r3 +password 1 +log file ospfd.log +! +router ospf + router-id 3.3.3.3 + network 0.0.0.0/4 area 0 + redistribute static +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r3/zebra.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r3/zebra.conf new file mode 100644 index 0000000000..9dbc290243 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r3/zebra.conf @@ -0,0 +1,29 @@ +log file zebra.log +! +hostname r3 +! +interface lo + ip address 3.3.3.3/32 +! +interface r3-eth0 + description to sw1 + ip address 10.0.2.3/24 + no link-detect +! +interface r3-eth1 + description to sw2 + ip address 10.0.3.3/24 + no link-detect +! +interface r3-eth4 + description to ce2 + ip address 192.168.1.1/24 + no link-detect +! +ip route 99.0.0.2/32 192.168.1.2 +! +ip forwarding +! +! +line vty +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r4/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r4/bgpd.conf new file mode 100644 index 0000000000..145390d724 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r4/bgpd.conf @@ -0,0 +1,42 @@ +frr defaults traditional +! +hostname r4 +password zebra +log stdout notifications +log monitor notifications +log commands +router bgp 5226 + bgp router-id 4.4.4.4 + bgp cluster-id 4.4.4.4 + neighbor 192.168.1.2 remote-as 5226 + neighbor 192.168.1.2 update-source 192.168.1.1 + neighbor 192.168.1.2 route-reflector-client + neighbor 2.2.2.2 remote-as 5226 + neighbor 2.2.2.2 update-source 4.4.4.4 +! + address-family ipv4 unicast + redistribute vnc-direct + neighbor 192.168.1.2 activate + neighbor 192.168.1.2 next-hop-self + no neighbor 2.2.2.2 activate + exit-address-family + address-family ipv4 vpn + neighbor 2.2.2.2 activate + exit-address-family +! + vrf-policy cust1 + label 104 + rd 10:4 + rt both 52:100 + nexthop 192.168.1.1 + exit-vrf-policy +! + vnc export bgp mode group-nve + vnc export bgp group-nve group cust1 + vnc redistribute mode resolve-nve + vnc redistribute ipv4 bgp-direct +! +end + + + diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r4/ldpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r4/ldpd.conf new file mode 100644 index 0000000000..8f3533527d --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r4/ldpd.conf @@ -0,0 +1,23 @@ +hostname r4 +log file ldpd.log +! +debug mpls ldp zebra +debug mpls ldp event +debug mpls ldp errors +debug mpls ldp messages recv +debug mpls ldp messages sent +debug mpls ldp discovery hello recv +debug mpls ldp discovery hello sent +! +mpls ldp + router-id 4.4.4.4 + ! + address-family ipv4 + discovery transport-address 4.4.4.4 + ! + interface r4-eth0 + ! + ! +! +line vty +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r4/ospfd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r4/ospfd.conf new file mode 100644 index 0000000000..83d09c09a4 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r4/ospfd.conf @@ -0,0 +1,8 @@ +hostname r4 +log file ospfd.log +! +router ospf + router-id 4.4.4.4 + network 0.0.0.0/4 area 0 + redistribute static +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r4/zebra.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r4/zebra.conf new file mode 100644 index 0000000000..415f03df51 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r4/zebra.conf @@ -0,0 +1,23 @@ +log file zebra.log +! +hostname r4 +! +interface lo + ip address 4.4.4.4/32 +! +interface r4-eth0 + description to sw1 + ip address 10.0.2.4/24 + no link-detect +! +interface r4-eth4 + description to ce3 + ip address 192.168.1.1/24 + no link-detect +! +ip route 99.0.0.3/32 192.168.1.2 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/scripts/add_routes.py b/tests/topotests/bgp_l3vpn_to_bgp_direct/scripts/add_routes.py new file mode 100644 index 0000000000..3a24367a56 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/scripts/add_routes.py @@ -0,0 +1,51 @@ +from lutil import luCommand +luCommand('r1','vtysh -c "show bgp next"','99.0.0.. valid', 'wait', 'See CE static NH') +luCommand('r3','vtysh -c "show bgp next"','99.0.0.. valid', 'wait', 'See CE static NH') +luCommand('r4','vtysh -c "show bgp next"','99.0.0.. valid', 'wait', 'See CE static NH') +luCommand('r1','vtysh -c "show bgp ipv4 uni"','i5.*i5','wait','See CE routes') +luCommand('r3','vtysh -c "show bgp ipv4 uni"','i5.*i5','wait','See CE routes') +luCommand('r4','vtysh -c "show bgp ipv4 uni"','i5.*i5','wait','See CE routes') +luCommand('ce1','vtysh -c "show bgp ipv4 uni 5.1.0.0/24"','','none','See CE routes') +luCommand('r1','vtysh -c "show bgp ipv4 uni 5.1.0.0/24"','','none','See CE routes') +luCommand('ce2','vtysh -c "show bgp ipv4 uni 5.1.0.0/24"','','none','See CE routes') +luCommand('r3','vtysh -c "show bgp ipv4 uni 5.1.0.0/24"','','none','See CE routes') +luCommand('ce3','vtysh -c "show bgp ipv4 uni 5.1.2.0/24"','','none','See CE routes') +luCommand('r4','vtysh -c "show bgp ipv4 uni 5.1.2.0/24"','','none','See CE routes') + +luCommand('r1','vtysh -c "add vrf cust1 prefix 99.0.0.1/32"','.','none','IP Address') +luCommand('r1','vtysh -c "show vnc registrations local"','99.0.0.1','wait','Local Registration') +luCommand('r1','vtysh -c "show vnc registrations imported"','2 out of 2 imported','wait','Imported Registrations') +luCommand('r3','vtysh -c "show bgp ipv4 vpn"','i99.0.0.1/32','wait','See R1s static address') +luCommand('r4','vtysh -c "show bgp ipv4 vpn"','i99.0.0.1/32','wait','See R1s static address') +luCommand('r3','vtysh -c "show bgp ipv4 vpn rd 10:1"','i5.*i5','wait','See R1s imports') +luCommand('r4','vtysh -c "show bgp ipv4 vpn rd 10:1"','i5.*i5','wait','See R1s imports') + +luCommand('r3','vtysh -c "add vrf cust1 prefix 99.0.0.2/32"','.','none','IP Address') +luCommand('r3','vtysh -c "show vnc registrations local"','99.0.0.2','wait','Local Registration') +have2ndImports = luCommand('r3','vtysh -c "show vnc registrations imported"','2 out of 2 imported','none','Imported Registrations',2) +if have2ndImports: + luCommand('r3','vtysh -c "show vnc registrations imported"','2 out of 2 imported','pass','Imported Registrations') +luCommand('r1','vtysh -c "show bgp ipv4 vpn"','i99.0.0.2/32','wait','See R3s static address') +luCommand('r4','vtysh -c "show bgp ipv4 vpn"','i99.0.0.2/32','wait','See R3s static address') +if have2ndImports: + luCommand('r1','vtysh -c "show bgp ipv4 vpn rd 10:3"','i5.*i5','none','See R3s imports') + luCommand('r4','vtysh -c "show bgp ipv4 vpn rd 10:3"','i5.*i5','none','See R3s imports') + +luCommand('r4','vtysh -c "add vrf cust1 prefix 99.0.0.3/32"','.','none','IP Address') +luCommand('r4','vtysh -c "show vnc registrations local"','99.0.0.3','wait','Local Registration') +luCommand('r4','vtysh -c "show vnc registrations imported"','2 out of 2 imported','wait','Imported Registrations') +luCommand('r1','vtysh -c "show bgp ipv4 vpn"','i99.0.0.3/32','wait','See R4s static address') +luCommand('r3','vtysh -c "show bgp ipv4 vpn"','i99.0.0.3/32','wait','See R4s static address') +luCommand('r1','vtysh -c "show bgp ipv4 vpn rd 10:4"','i5.*i5','wait','See R4s imports') +luCommand('r3','vtysh -c "show bgp ipv4 vpn rd 10:4"','i5.*i5','wait','See R4s imports') + + +luCommand('r1','vtysh -c "show vnc registrations remote"','5.1.2.0/24 .*5.1.3.0/24','wait','R4s registrations') +luCommand('r3','vtysh -c "show vnc registrations remote"','5.1.2.0/24 .*5.1.3.0/24','wait','R4s registrations') +if have2ndImports: + luCommand('r1','vtysh -c "show vnc registrations remote"','5.1.0.0/24 .*5.1.1.0/24','wait','Remote registrations') + luCommand('r3','vtysh -c "show vnc registrations remote"','5.1.0.0/24 .*5.1.1.0/24','wait','Remote registrations') +luCommand('r4','vtysh -c "show vnc registrations remote"','5.1.0.0/24 .*5.1.1.0/24','wait','Remote registrations') +luCommand('r1','vtysh -c "show vnc registrations"','.','none') +luCommand('r3','vtysh -c "show vnc registrations"','.','none') +luCommand('r4','vtysh -c "show vnc registrations"','.','none') diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/scripts/adjacencies.py b/tests/topotests/bgp_l3vpn_to_bgp_direct/scripts/adjacencies.py new file mode 100644 index 0000000000..7b3a883afa --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/scripts/adjacencies.py @@ -0,0 +1,20 @@ +from lutil import luCommand +luCommand('ce1','ping 192.168.1.1 -c 1',' 0. packet loss','pass','CE->PE ping') +luCommand('ce2','ping 192.168.1.1 -c 1',' 0. packet loss','pass','CE->PE ping') +luCommand('ce3','ping 192.168.1.1 -c 1',' 0. packet loss','pass','CE->PE ping') +luCommand('ce1','vtysh -c "show bgp summary"',' 00:0','wait','Adjacencies up',90) +luCommand('ce2','vtysh -c "show bgp summary"',' 00:0','wait','Adjacencies up') +luCommand('ce3','vtysh -c "show bgp summary"',' 00:0','wait','Adjacencies up') +luCommand('r1','ping 2.2.2.2 -c 1',' 0. packet loss','wait','PE->P2 (loopback) ping',60) +luCommand('r3','ping 2.2.2.2 -c 1',' 0. packet loss','wait','PE->P2 (loopback) ping',60) +luCommand('r4','ping 2.2.2.2 -c 1',' 0. packet loss','wait','PE->P2 (loopback) ping',60) +luCommand('r2','vtysh -c "show bgp summary"',' 00:0.* 00:0.* 00:0','wait','Core adjacencies up') +luCommand('r1','vtysh -c "show bgp summary"',' 00:0','pass','Core adjacencies up') +luCommand('r3','vtysh -c "show bgp summary"',' 00:0','pass','Core adjacencies up') +luCommand('r4','vtysh -c "show bgp summary"',' 00:0','pass','Core adjacencies up') +luCommand('r1','vtysh -c "show bgp vrf all summary"',' 00:0.* 00:0','pass','All adjacencies up') +luCommand('r3','vtysh -c "show bgp vrf all summary"',' 00:0.* 00:0','pass','All adjacencies up') +luCommand('r4','vtysh -c "show bgp vrf all summary"',' 00:0.* 00:0','pass','All adjacencies up') +luCommand('r1','ping 3.3.3.3 -c 1',' 0. packet loss','wait','PE->PE3 (loopback) ping') +luCommand('r1','ping 4.4.4.4 -c 1',' 0. packet loss','wait','PE->PE4 (loopback) ping') +luCommand('r4','ping 3.3.3.3 -c 1',' 0. packet loss','wait','PE->PE3 (loopback) ping') diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/scripts/check_routes.py b/tests/topotests/bgp_l3vpn_to_bgp_direct/scripts/check_routes.py new file mode 100644 index 0000000000..492be9e4da --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/scripts/check_routes.py @@ -0,0 +1,17 @@ +from lutil import luCommand +luCommand('ce1','vtysh -c "show bgp ipv4 uni"','7 routes and 7','wait','Local and remote routes') +luCommand('ce2','vtysh -c "show bgp ipv4 uni"','7 routes and 9','wait','Local and remote routes') +luCommand('ce3','vtysh -c "show bgp ipv4 uni"','7 routes and 7','wait','Local and remote routes') +luCommand('r1','vtysh -c "show bgp ipv4 uni"','7 routes and 9','pass','Unicast SAFI') +luCommand('r2','vtysh -c "show bgp ipv4 uni"','No BGP prefixes displayed','pass','Unicast SAFI') +luCommand('r3','vtysh -c "show bgp ipv4 uni"','7 routes and 9','pass','Unicast SAFI') +luCommand('r4','vtysh -c "show bgp ipv4 uni"','7 routes and 9','pass','Unicast SAFI') +have2ndImports = luCommand('r3','vtysh -c "show vnc registrations imported"','2 out of 2 imported','none','Imported Registrations',2) +if have2ndImports: + num = '9 routes and 9' +else: + num = '7 routes and 7' +luCommand('r1','vtysh -c "show bgp ipv4 vpn"',num,'pass','VPN SAFI') +luCommand('r2','vtysh -c "show bgp ipv4 vpn"',num,'pass','VPN SAFI') +luCommand('r3','vtysh -c "show bgp ipv4 vpn"',num,'pass','VPN SAFI') +luCommand('r4','vtysh -c "show bgp ipv4 vpn"',num,'pass','VPN SAFI') diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/scripts/cleanup_all.py b/tests/topotests/bgp_l3vpn_to_bgp_direct/scripts/cleanup_all.py new file mode 100644 index 0000000000..3a2f037833 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/scripts/cleanup_all.py @@ -0,0 +1,17 @@ +from lutil import luCommand +luCommand('r1','vtysh -c "clear vrf cust1 prefix 99.0.0.1/32"','.','none','Cleared VRF route') +luCommand('r3','vtysh -c "clear vrf cust1 prefix 99.0.0.2/32"','.','none','Cleared VRF route') +luCommand('r4','vtysh -c "clear vrf cust1 prefix 99.0.0.3/32"','.','none','Cleared VRF route') +luCommand('r1','vtysh -c "show vnc registrations local"','99.0.0.1','fail','Local Registration cleared') +luCommand('r3','vtysh -c "show vnc registrations local"','99.0.0.2','fail','Local Registration cleared') +luCommand('r4','vtysh -c "show vnc registrations local"','99.0.0.3','fail','Local Registration cleared') +luCommand('r1','vtysh -c "show bgp ipv4 uni"','2 routes and 2','wait','Unicast SAFI updated') +luCommand('r2','vtysh -c "show bgp ipv4 uni"','No BGP prefixes displayed','pass','Unicast SAFI') +luCommand('r3','vtysh -c "show bgp ipv4 uni"','2 routes and 2','wait','Unicast SAFI updated') +luCommand('r4','vtysh -c "show bgp ipv4 uni"','2 routes and 2','wait','Unicast SAFI updated') +luCommand('ce1','vtysh -c "show bgp ipv4 uni"','2 routes and 2','wait','Local and remote routes') +luCommand('ce2','vtysh -c "show bgp ipv4 uni"','2 routes and 2','wait','Local and remote routes') +luCommand('ce3','vtysh -c "show bgp ipv4 uni"','2 routes and 2','wait','Local and remote routes') +luCommand('r1','vtysh -c "show vnc registrations remote"','Prefix ','fail','Remote Registration cleared') +luCommand('r3','vtysh -c "show vnc registrations remote"','Prefix ','fail','Remote Registration cleared') +luCommand('r4','vtysh -c "show vnc registrations remote"','Prefix ','fail','Remote Registration cleared') diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/test_bgp_l3vpn_to_bgp_direct.py b/tests/topotests/bgp_l3vpn_to_bgp_direct/test_bgp_l3vpn_to_bgp_direct.py new file mode 100755 index 0000000000..f710c84c37 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/test_bgp_l3vpn_to_bgp_direct.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python + +# +# Part of NetDEF Topology Tests +# +# Copyright (c) 2018, LabN Consulting, L.L.C. +# Authored by Lou Berger +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +import os +import sys +import pytest + +sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..')) + +from lib.ltemplate import * + +def test_adjacencies(): + CliOnFail = None + # For debugging, uncomment the next line + #CliOnFail = 'tgen.mininet_cli' + CheckFunc = 'ltemplateVersionCheck(\'3.1\')' + #uncomment next line to start cli *before* script is run + #CheckFunc = 'ltemplateVersionCheck(\'3.1\', cli=True)' + ltemplateTest('scripts/adjacencies.py', False, CliOnFail, CheckFunc) + +def test_add_routes(): + CliOnFail = None + # For debugging, uncomment the next line + #CliOnFail = 'tgen.mininet_cli' + CheckFunc = 'ltemplateVersionCheck(\'3.1\')' + #uncomment next line to start cli *before* script is run + #CheckFunc = 'ltemplateVersionCheck(\'3.1\', cli=True)' + ltemplateTest('scripts/add_routes.py', False, CliOnFail, CheckFunc) + +def test_check_routes(): + CliOnFail = None + # For debugging, uncomment the next line + #CliOnFail = 'tgen.mininet_cli' + CheckFunc = 'ltemplateVersionCheck(\'3.1\')' + #uncomment next line to start cli *before* script is run + #CheckFunc = 'ltemplateVersionCheck(\'3.1\', cli=True)' + ltemplateTest('scripts/check_routes.py', False, CliOnFail, CheckFunc) + +def test_cleanup_all(): + CliOnFail = None + # For debugging, uncomment the next line + #CliOnFail = 'tgen.mininet_cli' + CheckFunc = 'ltemplateVersionCheck(\'3.1\')' + #uncomment next line to start cli *before* script is run + #CheckFunc = 'ltemplateVersionCheck(\'3.1\', cli=True)' + ltemplateTest('scripts/cleanup_all.py', False, CliOnFail, CheckFunc) + +if __name__ == '__main__': + retval = pytest.main(["-s"]) + sys.exit(retval) diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/__init__.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/__init__.py new file mode 100755 index 0000000000..e69de29bb2 diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce1/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce1/bgpd.conf new file mode 100644 index 0000000000..4bd0f95f2c --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce1/bgpd.conf @@ -0,0 +1,36 @@ +frr defaults traditional +! +hostname ce1 +password zebra +log stdout notifications +log monitor notifications +log commands +log file bgpd.log + +router bgp 5227 + bgp router-id 99.0.0.1 + neighbor 192.168.1.1 remote-as 5227 + neighbor 192.168.1.1 update-source 192.168.1.2 + address-family ipv4 unicast + network 99.0.0.1/32 + network 5.1.0.0/24 route-map rm-nh + network 5.1.1.0/24 route-map rm-nh + neighbor 192.168.1.1 activate + exit-address-family +! +access-list al-any permit any +! +route-map rm-nh permit 10 + match ip address al-any + set ip next-hop 99.0.0.1 + set local-preference 123 + set metric 98 + set large-community 12:34:56 + set extcommunity rt 89:123 + set community 0:67 +! + +end + + + diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce1/zebra.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce1/zebra.conf new file mode 100644 index 0000000000..46831bb711 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce1/zebra.conf @@ -0,0 +1,17 @@ +log file zebra.log +! +hostname ce1 +! +interface lo + ip address 99.0.0.1/32 +! +interface ce1-eth0 + description to r1 + ip address 192.168.1.2/24 + no link-detect +! +ip forwarding +! +! +line vty +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce2/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce2/bgpd.conf new file mode 100644 index 0000000000..2115f08741 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce2/bgpd.conf @@ -0,0 +1,36 @@ +frr defaults traditional +! +hostname ce2 +password zebra +log stdout notifications +log monitor notifications +log commands +log file bgpd.log + +router bgp 5227 + bgp router-id 99.0.0.2 + neighbor 192.168.1.1 remote-as 5227 + neighbor 192.168.1.1 update-source 192.168.1.2 + address-family ipv4 unicast + network 99.0.0.2/32 + network 5.1.0.0/24 route-map rm-nh + network 5.1.1.0/24 route-map rm-nh + neighbor 192.168.1.1 activate + exit-address-family +! +access-list al-any permit any +! +route-map rm-nh permit 10 + match ip address al-any + set ip next-hop 99.0.0.2 + set local-preference 100 + set metric 100 + set large-community 12:34:56 + set extcommunity rt 89:123 + set community 0:67 +! + +end + + + diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce2/zebra.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce2/zebra.conf new file mode 100644 index 0000000000..fb4d8cc9c4 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce2/zebra.conf @@ -0,0 +1,17 @@ +log file zebra.log +! +hostname ce2 +! +interface lo + ip address 99.0.0.2/32 +! +interface ce2-eth0 + description to r3 + ip address 192.168.1.2/24 + no link-detect +! +ip forwarding +! +! +line vty +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/bgpd.conf new file mode 100644 index 0000000000..a65b36f364 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/bgpd.conf @@ -0,0 +1,36 @@ +frr defaults traditional +! +hostname ce3 +password zebra +log stdout notifications +log monitor notifications +log commands +log file bgpd.log + +router bgp 5227 + bgp router-id 99.0.0.3 + neighbor 192.168.1.1 remote-as 5227 + neighbor 192.168.1.1 update-source 192.168.1.2 + address-family ipv4 unicast + network 99.0.0.3/32 + network 5.1.2.0/24 route-map rm-nh + network 5.1.3.0/24 route-map rm-nh + neighbor 192.168.1.1 activate + exit-address-family +! +access-list al-any permit any +! +route-map rm-nh permit 10 + match ip address al-any + set ip next-hop 99.0.0.3 + set local-preference 50 + set metric 200 + set large-community 12:34:56 + set extcommunity rt 89:123 + set community 0:67 +! + +end + + + diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/zebra.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/zebra.conf new file mode 100644 index 0000000000..77a1163a4b --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/zebra.conf @@ -0,0 +1,17 @@ +log file zebra.log +! +hostname ce3 +! +interface lo + ip address 99.0.0.3/32 +! +interface ce3-eth0 + description to r4 + ip address 192.168.1.2/24 + no link-detect +! +ip forwarding +! +! +line vty +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/bgpd.conf new file mode 100644 index 0000000000..274eceaf0f --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/bgpd.conf @@ -0,0 +1,36 @@ +frr defaults traditional +! +hostname ce4 +password zebra +log stdout notifications +log monitor notifications +log commands +log file bgpd.log + +router bgp 5228 + bgp router-id 99.0.0.4 + neighbor 192.168.2.1 remote-as 5228 + neighbor 192.168.2.1 update-source 192.168.2.2 + address-family ipv4 unicast + network 99.0.0.4/32 + network 5.4.2.0/24 route-map rm-nh + network 5.4.3.0/24 route-map rm-nh + neighbor 192.168.2.1 activate + exit-address-family +! +access-list al-any permit any +! +route-map rm-nh permit 10 + match ip address al-any + set ip next-hop 99.0.0.4 + set local-preference 50 + set metric 200 + set large-community 12:34:56 + set extcommunity rt 89:123 + set community 0:67 +! + +end + + + diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/zebra.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/zebra.conf new file mode 100644 index 0000000000..bfd8ba8435 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/zebra.conf @@ -0,0 +1,17 @@ +log file zebra.log +! +hostname ce4 +! +interface lo + ip address 99.0.0.4/32 +! +interface ce4-eth0 + description to r4 + ip address 192.168.2.2/24 + no link-detect +! +ip forwarding +! +! +line vty +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py new file mode 100644 index 0000000000..596701cee2 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py @@ -0,0 +1,209 @@ +#!/usr/bin/env python + +# +# Part of NetDEF Topology Tests +# +# Copyright (c) 2017 by +# Network Device Education Foundation, Inc. ("NetDEF") +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +customize.py: Simple FRR/Quagga MPLS L3VPN test topology + + | + +----+----+ + | ce1 | + | 99.0.0.1| CE Router + +----+----+ + 192.168.1. | .2 ce1-eth0 + | .1 r1-eth4 + +---------+ + | r1 | + | 1.1.1.1 | PE Router + +----+----+ + | .1 r1-eth0 + | + ~~~~~~~~~~~~~ + ~~ sw0 ~~ + ~~ 10.0.1.0/24 ~~ + ~~~~~~~~~~~~~ + |10.0.1.0/24 + | + | .2 r2-eth0 + +----+----+ + | r2 | + | 2.2.2.2 | P router + +--+---+--+ + r2-eth2 .2 | | .2 r2-eth1 + ______/ \______ + / \ + ~~~~~~~~~~~~~ ~~~~~~~~~~~~~ +~~ sw2 ~~ ~~ sw1 ~~ +~~ 10.0.3.0/24 ~~ ~~ 10.0.2.0/24 ~~ + ~~~~~~~~~~~~~ ~~~~~~~~~~~~~ + | / | + \ _________/ | + \ / \ +r3-eth1 .3 | | .3 r3-eth0 | .4 r4-eth0 + +----+--+---+ +----+----+ + | r3 | | r4 | r4-eth5 + | 3.3.3.3 | | 4.4.4.4 |-------+ PE Routers + +-----------+ +---------+ | +192.168.1.1 |r3.eth4 192.168.1.1 | r4-eth4 |192.168.2.1 + .2 | ceX-eth0 .2 | | .2 + +-----+-----+ +----+-----+ +----+-----+ + | ce2 | | ce3 | | ce4 | + | 99.0.0.2 | | 99.0.0.3 | | 99.0.0.4 | CE Routers + +-----+-----+ +----+-----+ +----+-----+ + | | | + +""" + +import os +import re +import pytest +import platform + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger +from lib.ltemplate import ltemplateRtrCmd + +# Required to instantiate the topology builder class. +from mininet.topo import Topo + +import shutil +CWD = os.path.dirname(os.path.realpath(__file__)) +# test name based on directory +TEST = os.path.basename(CWD) + +class ThisTestTopo(Topo): + "Test topology builder" + def build(self, *_args, **_opts): + "Build function" + tgen = get_topogen(self) + + # This function only purpose is to define allocation and relationship + # between routers, switches and hosts. + # + # Create P/PE routers + #check for mpls + tgen.add_router('r1') + if tgen.hasmpls != True: + logger.info('MPLS not available, tests will be skipped') + return + mach = platform.machine() + krel = platform.release() + if mach[:1] == 'a' and topotest.version_cmp(krel, '4.11') < 0: + logger.info('Need Kernel version 4.11 to run on arm processor') + return + for routern in range(2, 5): + tgen.add_router('r{}'.format(routern)) + # Create CE routers + for routern in range(1, 5): + tgen.add_router('ce{}'.format(routern)) + + #CE/PE links + tgen.add_link(tgen.gears['ce1'], tgen.gears['r1'], 'ce1-eth0', 'r1-eth4') + tgen.add_link(tgen.gears['ce2'], tgen.gears['r3'], 'ce2-eth0', 'r3-eth4') + tgen.add_link(tgen.gears['ce3'], tgen.gears['r4'], 'ce3-eth0', 'r4-eth4') + tgen.add_link(tgen.gears['ce4'], tgen.gears['r4'], 'ce4-eth0', 'r4-eth5') + + # Create a switch with just one router connected to it to simulate a + # empty network. + switch = {} + switch[0] = tgen.add_switch('sw0') + switch[0].add_link(tgen.gears['r1'], nodeif='r1-eth0') + switch[0].add_link(tgen.gears['r2'], nodeif='r2-eth0') + + switch[1] = tgen.add_switch('sw1') + switch[1].add_link(tgen.gears['r2'], nodeif='r2-eth1') + switch[1].add_link(tgen.gears['r3'], nodeif='r3-eth0') + switch[1].add_link(tgen.gears['r4'], nodeif='r4-eth0') + + switch[1] = tgen.add_switch('sw2') + switch[1].add_link(tgen.gears['r2'], nodeif='r2-eth2') + switch[1].add_link(tgen.gears['r3'], nodeif='r3-eth1') + +def ltemplatePreRouterStartHook(): + cc = ltemplateRtrCmd() + krel = platform.release() + tgen = get_topogen() + logger.info('pre router-start hook, kernel=' + krel) + if topotest.version_cmp(krel, '4.15') == 0: + l3mdev_accept = 1 + else: + l3mdev_accept = 0 + logger.info('setting net.ipv4.tcp_l3mdev_accept={}'.format(l3mdev_accept)) + #check for mpls + if tgen.hasmpls != True: + logger.info('MPLS not available, skipping setup') + return False + #check for normal init + if len(tgen.net) == 1: + logger.info('Topology not configured, skipping setup') + return False + #trace errors/unexpected output + cc.resetCounts() + #configure r2 mpls interfaces + intfs = ['lo', 'r2-eth0', 'r2-eth1', 'r2-eth2'] + for intf in intfs: + cc.doCmd(tgen, 'r2', 'echo 1 > /proc/sys/net/mpls/conf/{}/input'.format(intf)) + + #configure cust1 VRFs & MPLS + rtrs = ['r1', 'r3', 'r4'] + cmds = ['ip link add {0}-cust1 type vrf table 10', + 'ip ru add oif {0}-cust1 table 10', + 'ip ru add iif {0}-cust1 table 10', + 'ip link set dev {0}-cust1 up', + 'sysctl -w net.ipv4.udp_l3mdev_accept={}'.format(l3mdev_accept)] + for rtr in rtrs: + router = tgen.gears[rtr] + for cmd in cmds: + cc.doCmd(tgen, rtr, cmd.format(rtr)) + cc.doCmd(tgen, rtr, 'ip link set dev {0}-eth4 master {0}-cust1'.format(rtr)) + intfs = [rtr+'-cust1', 'lo', rtr+'-eth0', rtr+'-eth4'] + for intf in intfs: + cc.doCmd(tgen, rtr, 'echo 1 > /proc/sys/net/mpls/conf/{}/input'.format(intf)) + logger.info('setup {0} vrf {0}-cust1, {0}-eth4. enabled mpls input.'.format(rtr)) + #configure cust2 VRFs & MPLS + rtrs = ['r4'] + cmds = ['ip link add {0}-cust2 type vrf table 20', + 'ip ru add oif {0}-cust2 table 20', + 'ip ru add iif {0}-cust2 table 20', + 'ip link set dev {0}-cust2 up'] + for rtr in rtrs: + for cmd in cmds: + cc.doCmd(tgen, rtr, cmd.format(rtr)) + cc.doCmd(tgen, rtr, 'ip link set dev {0}-eth5 master {0}-cust2'.format(rtr)) + intfs = [rtr+'-cust2', rtr+'-eth5'] + for intf in intfs: + cc.doCmd(tgen, rtr, 'echo 1 > /proc/sys/net/mpls/conf/{}/input'.format(intf)) + logger.info('setup {0} vrf {0}-cust2, {0}-eth5. enabled mpls input.'.format(rtr)) + if cc.getOutput() != 3: + InitSuccess = False + logger.info('Unexpected output seen ({} times, tests will be skipped'.format(cc.getOutput())) + else: + InitSuccess = True + logger.info('VRF config successful!') + return InitSuccess + +def ltemplatePostRouterStartHook(): + logger.info('post router-start hook') + return True diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf new file mode 100644 index 0000000000..c1bad0b7c6 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf @@ -0,0 +1,52 @@ +frr defaults traditional + +hostname r1 +password zebra +log stdout notifications +log monitor notifications +log commands + +log file bgpd.log debugging + +#debug bgp vpn leak-to-vrf +#debug bgp vpn leak-from-vrf +#debug bgp vpn label +#debug bgp updates out + +router bgp 5226 + bgp router-id 1.1.1.1 + bgp cluster-id 1.1.1.1 + neighbor 2.2.2.2 remote-as 5226 + neighbor 2.2.2.2 update-source 1.1.1.1 + + address-family ipv4 unicast + no neighbor 2.2.2.2 activate + exit-address-family + + address-family ipv4 vpn + neighbor 2.2.2.2 activate + exit-address-family + + +router bgp 5227 vrf r1-cust1 + + bgp router-id 192.168.1.1 + + neighbor 192.168.1.2 remote-as 5227 + neighbor 192.168.1.2 update-source 192.168.1.1 + + address-family ipv4 unicast + neighbor 192.168.1.2 activate + neighbor 192.168.1.2 next-hop-self + + label vpn export 101 + rd vpn export 10:1 + rt vpn both 52:100 + + import vpn + export vpn + exit-address-family + + +! +end diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/ldpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/ldpd.conf new file mode 100644 index 0000000000..de84f2bc3f --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/ldpd.conf @@ -0,0 +1,24 @@ +hostname r1 +log file ldpd.log +password zebra +! +debug mpls ldp zebra +debug mpls ldp event +debug mpls ldp errors +debug mpls ldp messages recv +debug mpls ldp messages sent +debug mpls ldp discovery hello recv +debug mpls ldp discovery hello sent +! +mpls ldp + router-id 1.1.1.1 + ! + address-family ipv4 + discovery transport-address 1.1.1.1 + ! + interface r1-eth0 + ! + ! +! +line vty +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/ospfd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/ospfd.conf new file mode 100644 index 0000000000..c5097e214f --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/ospfd.conf @@ -0,0 +1,8 @@ +hostname r1 +log file ospfd.log +! +router ospf + router-id 1.1.1.1 + network 0.0.0.0/4 area 0 + redistribute static +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/zebra.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/zebra.conf new file mode 100644 index 0000000000..221bc7a839 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/zebra.conf @@ -0,0 +1,25 @@ +log file zebra.log + +hostname r1 +password zebra + +#debug zebra packet + +interface lo + ip address 1.1.1.1/32 + +interface r1-eth0 + description to sw0 + ip address 10.0.1.1/24 + no link-detect + +interface r1-eth4 + description to ce1 + ip address 192.168.1.1/24 + no link-detect + +ip forwarding + + +line vty + diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/bgpd.conf new file mode 100644 index 0000000000..4ccb0ca5c0 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/bgpd.conf @@ -0,0 +1,35 @@ +frr defaults traditional + +hostname r2 +password zebra +log stdout notifications +log monitor notifications +log commands +log file bgpd.log debugging + +router bgp 5226 + bgp router-id 2.2.2.2 + bgp cluster-id 2.2.2.2 + neighbor 1.1.1.1 remote-as 5226 + neighbor 1.1.1.1 update-source 2.2.2.2 + neighbor 3.3.3.3 remote-as 5226 + neighbor 3.3.3.3 update-source 2.2.2.2 + neighbor 4.4.4.4 remote-as 5226 + neighbor 4.4.4.4 update-source 2.2.2.2 + address-family ipv4 unicast + no neighbor 1.1.1.1 activate + no neighbor 3.3.3.3 activate + no neighbor 4.4.4.4 activate + exit-address-family + address-family ipv4 vpn + neighbor 1.1.1.1 activate + neighbor 1.1.1.1 route-reflector-client + neighbor 3.3.3.3 activate + neighbor 3.3.3.3 route-reflector-client + neighbor 4.4.4.4 activate + neighbor 4.4.4.4 route-reflector-client + exit-address-family +end + + + diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/ldpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/ldpd.conf new file mode 100644 index 0000000000..411ba85ef6 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/ldpd.conf @@ -0,0 +1,26 @@ +hostname r2 +log file ldpd.log +password zebra +! +debug mpls ldp zebra +debug mpls ldp event +debug mpls ldp errors +debug mpls ldp messages recv +debug mpls ldp messages sent +debug mpls ldp discovery hello recv +debug mpls ldp discovery hello sent +! +mpls ldp + router-id 2.2.2.2 + ! + address-family ipv4 + discovery transport-address 2.2.2.2 + ! + interface r2-eth0 + ! + interface r2-eth1 + ! + ! +! +line vty +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/ospfd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/ospfd.conf new file mode 100644 index 0000000000..8678813665 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/ospfd.conf @@ -0,0 +1,7 @@ +hostname r2 +log file ospfd.log +! +router ospf + router-id 2.2.2.2 + network 0.0.0.0/0 area 0 +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/zebra.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/zebra.conf new file mode 100644 index 0000000000..dc4ef7ecc1 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/zebra.conf @@ -0,0 +1,28 @@ +log file zebra.log + +hostname r2 +password zebra +! +interface lo + ip address 2.2.2.2/32 +! +interface r2-eth0 + description to sw0 + ip address 10.0.1.2/24 + no link-detect +! +interface r2-eth1 + description to sw1 + ip address 10.0.2.2/24 + no link-detect +! +interface r2-eth2 + description to sw2 + ip address 10.0.3.2/24 + no link-detect +! +ip forwarding +! +! +line vty +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/bgpd.conf new file mode 100644 index 0000000000..2004612557 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/bgpd.conf @@ -0,0 +1,45 @@ +frr defaults traditional + +hostname r3 +password zebra +log stdout notifications +log monitor notifications +log commands +log file bgpd.log + +debug bgp vpn label +router bgp 5226 + bgp router-id 3.3.3.3 + bgp cluster-id 3.3.3.3 + neighbor 2.2.2.2 remote-as 5226 + neighbor 2.2.2.2 update-source 3.3.3.3 + + address-family ipv4 unicast + no neighbor 2.2.2.2 activate + exit-address-family + + address-family ipv4 vpn + neighbor 2.2.2.2 activate + exit-address-family + +router bgp 5227 vrf r3-cust1 + + bgp router-id 192.168.1.1 + + neighbor 192.168.1.2 remote-as 5227 + neighbor 192.168.1.2 update-source 192.168.1.1 + + address-family ipv4 unicast + neighbor 192.168.1.2 activate + neighbor 192.168.1.2 next-hop-self + + label vpn export 103 + rd vpn export 10:3 + rt vpn both 52:100 + + import vpn + export vpn + exit-address-family + + +end diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/ldpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/ldpd.conf new file mode 100644 index 0000000000..6002895f48 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/ldpd.conf @@ -0,0 +1,24 @@ +hostname r3 +password zebra +log file ldpd.log +! +debug mpls ldp zebra +debug mpls ldp event +debug mpls ldp errors +debug mpls ldp messages recv +debug mpls ldp messages sent +debug mpls ldp discovery hello recv +debug mpls ldp discovery hello sent +! +mpls ldp + router-id 3.3.3.3 + ! + address-family ipv4 + discovery transport-address 3.3.3.3 + ! + interface r3-eth0 + ! + ! +! +line vty +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/ospfd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/ospfd.conf new file mode 100644 index 0000000000..c7c358f9dc --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/ospfd.conf @@ -0,0 +1,9 @@ +hostname r3 +password 1 +log file ospfd.log +! +router ospf + router-id 3.3.3.3 + network 0.0.0.0/4 area 0 + redistribute static +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/zebra.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/zebra.conf new file mode 100644 index 0000000000..9ffc84fe2d --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/zebra.conf @@ -0,0 +1,29 @@ +log file zebra.log + +hostname r3 +password zebra +! +interface lo + ip address 3.3.3.3/32 +! +interface r3-eth0 + description to sw1 + ip address 10.0.2.3/24 + no link-detect +! +interface r3-eth1 + description to sw2 + ip address 10.0.3.3/24 + no link-detect +! +interface r3-eth4 + description to ce2 + ip address 192.168.1.1/24 + no link-detect +! +! +ip forwarding +! +! +line vty +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/bgpd.conf new file mode 100644 index 0000000000..b2df5990ce --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/bgpd.conf @@ -0,0 +1,67 @@ +frr defaults traditional + +hostname r4 +password zebra +log stdout notifications +log monitor notifications +log commands +log file bgpd.log debug + +debug bgp vpn label +debug bgp nht +debug bgp zebra + +router bgp 5226 + bgp router-id 4.4.4.4 + bgp cluster-id 4.4.4.4 + neighbor 2.2.2.2 remote-as 5226 + neighbor 2.2.2.2 update-source 4.4.4.4 + + address-family ipv4 unicast + no neighbor 2.2.2.2 activate + exit-address-family + + address-family ipv4 vpn + neighbor 2.2.2.2 activate + exit-address-family + +router bgp 5227 vrf r4-cust1 + + bgp router-id 192.168.1.1 + + neighbor 192.168.1.2 remote-as 5227 + neighbor 192.168.1.2 update-source 192.168.1.1 + + address-family ipv4 unicast + neighbor 192.168.1.2 activate + neighbor 192.168.1.2 next-hop-self + + label vpn export 1041 + rd vpn export 10:41 + rt vpn both 52:100 + + import vpn + export vpn + exit-address-family + +router bgp 5228 vrf r4-cust2 + + bgp router-id 192.168.2.1 + + neighbor 192.168.2.2 remote-as 5228 + neighbor 192.168.2.2 update-source 192.168.2.1 + + address-family ipv4 unicast + neighbor 192.168.2.2 activate + neighbor 192.168.2.2 next-hop-self + + label vpn export 1042 + rd vpn export 10:42 + # note RT same as r4-cust1 for inter-vrf route leaking + rt vpn both 52:100 + + import vpn + export vpn + exit-address-family + +end diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/ldpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/ldpd.conf new file mode 100644 index 0000000000..292e9a7187 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/ldpd.conf @@ -0,0 +1,24 @@ +hostname r4 +password zebra +log file ldpd.log +! +debug mpls ldp zebra +debug mpls ldp event +debug mpls ldp errors +debug mpls ldp messages recv +debug mpls ldp messages sent +debug mpls ldp discovery hello recv +debug mpls ldp discovery hello sent +! +mpls ldp + router-id 4.4.4.4 + ! + address-family ipv4 + discovery transport-address 4.4.4.4 + ! + interface r4-eth0 + ! + ! +! +line vty +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/ospfd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/ospfd.conf new file mode 100644 index 0000000000..83d09c09a4 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/ospfd.conf @@ -0,0 +1,8 @@ +hostname r4 +log file ospfd.log +! +router ospf + router-id 4.4.4.4 + network 0.0.0.0/4 area 0 + redistribute static +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/zebra.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/zebra.conf new file mode 100644 index 0000000000..4f01a27b40 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/zebra.conf @@ -0,0 +1,28 @@ +log file zebra.log + +hostname r4 +password zebra +! +interface lo + ip address 4.4.4.4/32 +! +interface r4-eth0 + description to sw1 + ip address 10.0.2.4/24 + no link-detect +! +interface r4-eth4 + description to ce3 + ip address 192.168.1.1/24 + no link-detect +! +interface r4-eth5 + description to ce4 + ip address 192.168.2.1/24 + no link-detect +! +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/add_routes.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/add_routes.py new file mode 100644 index 0000000000..19b73d2057 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/add_routes.py @@ -0,0 +1,13 @@ +from lutil import luCommand +luCommand('r1','vtysh -c "add vrf r1-cust1 prefix 99.0.0.1/32"','.','none','IP Address') +luCommand('r3','vtysh -c "add vrf r3-cust1 prefix 99.0.0.2/32"','.','none','IP Address') +luCommand('r4','vtysh -c "add vrf r4-cust1 prefix 99.0.0.3/32"','.','none','IP Address') +luCommand('r1','vtysh -c "show vnc registrations local"','99.0.0.1','pass','Local Registration') +luCommand('r3','vtysh -c "show vnc registrations local"','99.0.0.2','pass','Local Registration') +luCommand('r4','vtysh -c "show vnc registrations local"','99.0.0.3','pass','Local Registration') +luCommand('r1','vtysh -c "show vnc registrations remote"','4 out of 4','wait','Remote Registration', 10) +luCommand('r3','vtysh -c "show vnc registrations remote"','6 out of 6','wait','Remote Registration', 10) +luCommand('r4','vtysh -c "show vnc registrations remote"','4 out of 4','wait','Remote Registration', 10) +luCommand('r1','vtysh -c "show vnc registrations"','.','none') +luCommand('r3','vtysh -c "show vnc registrations"','.','none') +luCommand('r4','vtysh -c "show vnc registrations"','.','none') diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/adjacencies.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/adjacencies.py new file mode 100644 index 0000000000..1dfd22f6bd --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/adjacencies.py @@ -0,0 +1,18 @@ +from lutil import luCommand +luCommand('ce1','vtysh -c "show bgp summary"',' 00:0','wait','Adjacencies up',180) +luCommand('ce2','vtysh -c "show bgp summary"',' 00:0','wait','Adjacencies up') +luCommand('ce3','vtysh -c "show bgp summary"',' 00:0','wait','Adjacencies up') +luCommand('ce4','vtysh -c "show bgp summary"',' 00:0','wait','Adjacencies up') +luCommand('r1','ping 2.2.2.2 -c 1',' 0. packet loss','wait','PE->P2 (loopback) ping',60) +luCommand('r3','ping 2.2.2.2 -c 1',' 0. packet loss','wait','PE->P2 (loopback) ping',60) +luCommand('r4','ping 2.2.2.2 -c 1',' 0. packet loss','wait','PE->P2 (loopback) ping',60) +luCommand('r2','vtysh -c "show bgp summary"',' 00:0.* 00:0.* 00:0','wait','Core adjacencies up',300) +luCommand('r1','vtysh -c "show bgp summary"',' 00:0','pass','Core adjacencies up') +luCommand('r3','vtysh -c "show bgp summary"',' 00:0','pass','Core adjacencies up') +luCommand('r4','vtysh -c "show bgp summary"',' 00:0','pass','Core adjacencies up') +luCommand('r1','vtysh -c "show bgp vrf all summary"',' 00:0.* 00:0','pass','All adjacencies up') +luCommand('r3','vtysh -c "show bgp vrf all summary"',' 00:0.* 00:0','pass','All adjacencies up') +luCommand('r4','vtysh -c "show bgp vrf all summary"',' 00:0.* 00:0.* 00:0','pass','All adjacencies up') +luCommand('r1','ping 3.3.3.3 -c 1',' 0. packet loss','wait','PE->PE3 (loopback) ping') +luCommand('r1','ping 4.4.4.4 -c 1',' 0. packet loss','wait','PE->PE4 (loopback) ping') +luCommand('r4','ping 3.3.3.3 -c 1',' 0. packet loss','wait','PE->PE3 (loopback) ping') diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_mpls.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_mpls.py new file mode 100644 index 0000000000..174666a075 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_mpls.py @@ -0,0 +1,46 @@ +from lutil import luCommand, luLast +from lib import topotest + +ret = luCommand('r2', 'ip -M route show', + '\d*(?= via inet 10.0.2.4 dev r2-eth1)','wait','See mpls route to r4') +found = luLast() + +if ret != False and found != None: + label4r4 = found.group(0) + luCommand('r2', 'ip -M route show', + '.', 'pass', + 'See %s as label to r4' % label4r4) + ret = luCommand('r2', 'ip -M route show', + '\d*(?= via inet 10.0.1.1 dev r2-eth0)', 'wait', + 'See mpls route to r1') + found = luLast() + +if ret != False and found != None: + label4r1 = found.group(0) + luCommand('r2', 'ip -M route show', + '.', 'pass', 'See %s as label to r1' % label4r1) + + luCommand('r1', 'ip route show vrf r1-cust1', + '99.0.0.4', 'pass', 'VRF->MPLS PHP route installed') + luCommand('r4', 'ip route show vrf r4-cust2', + '99.0.0.1','pass', 'VRF->MPLS PHP route installed') + + luCommand('r1', 'ip -M route show', '101', 'pass', 'MPLS->VRF route installed') + luCommand('r4', 'ip -M route show', '1041', 'pass', 'MPLS->VRF1 route installed') + luCommand('r4', 'ip -M route show', '1042', 'pass', 'MPLS->VRF2 route installed') + + luCommand('ce1', 'ping 99.0.0.4 -I 99.0.0.1 -c 1', + ' 0. packet loss','wait','CE->CE (loopback) ping - l3vpn+zebra case') + luCommand('ce4', 'ping 99.0.0.1 -I 99.0.0.4 -c 1', + ' 0. packet loss','wait','CE->CE (loopback) ping - l3vpn+zebra case') + + luCommand('ce1', 'ping 99.0.0.4 -I 99.0.0.1 -c 1', + ' 0. packet loss','wait','CE->CE (loopback) ping') + luCommand('ce4', 'ping 99.0.0.1 -I 99.0.0.4 -c 1', + ' 0. packet loss','wait','CE->CE (loopback) ping') + + luCommand('r3', 'ip -M route show', '103', 'pass', 'MPLS->VRF route installed') + luCommand('ce2', 'ping 99.0.0.3 -I 99.0.0.2 -c 1', + ' 0. packet loss','wait','CE2->CE3 (loopback) ping') + luCommand('ce3', 'ping 99.0.0.4 -I 99.0.0.3 -c 1', + ' 0. packet loss','wait','CE3->CE4 (loopback) ping') diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py new file mode 100644 index 0000000000..6239f77a82 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py @@ -0,0 +1,14 @@ +from lutil import luCommand +rtrs = ['r1', 'r3', 'r4'] +for rtr in rtrs: + luCommand(rtr, 'ip link show type vrf {}-cust1'.format(rtr),'cust1: .*UP,LOWER_UP','pass','VRF cust1 up') + luCommand(rtr, 'ip add show vrf {}-cust1'.format(rtr),'r..eth4: .*UP,LOWER_UP.* 192.168','pass','VRF cust1 IP config') + luCommand(rtr, 'ip route show vrf {}-cust1'.format(rtr),'192.168...0/24 dev r.-eth','pass','VRF cust1 interface route') +luCommand('r4', 'ip link show type vrf r4-cust2','cust2: .*UP,LOWER_UP','pass','VRF cust2 up') +luCommand('r4', 'ip add show vrf r4-cust2','r..eth5.*UP,LOWER_UP.* 192.168','pass','VRF cust1 IP config') +luCommand(rtr, 'ip route show vrf r4-cust2'.format(rtr),'192.168...0/24 dev r.-eth','pass','VRF cust2 interface route') +rtrs = ['ce1', 'ce2', 'ce3'] +for rtr in rtrs: + luCommand(rtr, 'ip route show','192.168...0/24 dev ce.-eth0','pass','CE interface route') + luCommand(rtr,'ping 192.168.1.1 -c 1',' 0. packet loss','wait','CE->PE ping') +luCommand('ce4','ping 192.168.2.1 -c 1',' 0. packet loss','wait','CE4->PE4 ping') diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py new file mode 100644 index 0000000000..7b2387bd0b --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py @@ -0,0 +1,318 @@ +from lutil import luCommand +from bgprib import bgpribRequireVpnRoutes,bgpribRequireUnicastRoutes + +######################################################################## +# CE routers: contain routes they originate +######################################################################## +# +# mininet CLI commands +# ce1 vtysh -c "show bgp ipv4 uni" +# ce2 vtysh -c "show bgp ipv4 uni" +# ce3 vtysh -c "show bgp ipv4 uni" +# ce4 vtysh -c "show bgp ipv4 uni" + +want = [ + {'p':'5.1.0.0/24', 'n':'99.0.0.1'}, + {'p':'5.1.1.0/24', 'n':'99.0.0.1'}, + {'p':'99.0.0.1/32', 'n':'0.0.0.0'}, +] +bgpribRequireUnicastRoutes('ce1','ipv4','','Cust 1 routes in ce1',want) + +want = [ + {'p':'5.1.0.0/24', 'n':'99.0.0.2'}, + {'p':'5.1.1.0/24', 'n':'99.0.0.2'}, + {'p':'99.0.0.2/32', 'n':'0.0.0.0'}, +] +bgpribRequireUnicastRoutes('ce2','ipv4','','Cust 2 routes in ce1',want) + +want = [ + {'p':'5.1.2.0/24', 'n':'99.0.0.3'}, + {'p':'5.1.3.0/24', 'n':'99.0.0.3'}, + {'p':'99.0.0.3/32', 'n':'0.0.0.0'}, +] +bgpribRequireUnicastRoutes('ce3','ipv4','','Cust 3 routes in ce1',want) + +want = [ + {'p':'5.4.2.0/24', 'n':'99.0.0.4'}, + {'p':'5.4.3.0/24', 'n':'99.0.0.4'}, + {'p':'99.0.0.4/32', 'n':'0.0.0.0'}, +] +bgpribRequireUnicastRoutes('ce4','ipv4','','Cust 4 routes in ce1',want) + + +######################################################################## +# PE routers: VRFs contain routes from locally-attached customer nets +######################################################################## +# +# r1 vtysh -c "show bgp vrf r1-cust1 ipv4" +# +want_r1_cust1_routes = [ + {'p':'5.1.0.0/24', 'n':'99.0.0.1'}, + {'p':'5.1.1.0/24', 'n':'99.0.0.1'}, + {'p':'99.0.0.1/32', 'n':'192.168.1.2'}, +] +bgpribRequireUnicastRoutes('r1','ipv4','r1-cust1','Customer 1 routes in r1 vrf',want_r1_cust1_routes) + +want_r3_cust1_routes = [ + {'p':'5.1.0.0/24', 'n':'99.0.0.2'}, + {'p':'5.1.1.0/24', 'n':'99.0.0.2'}, + {'p':'99.0.0.2/32', 'n':'192.168.1.2'}, +] +bgpribRequireUnicastRoutes('r3','ipv4','r3-cust1','Customer 1 routes in r3 vrf',want_r3_cust1_routes) + +want_r4_cust1_routes = [ + {'p':'5.1.2.0/24', 'n':'99.0.0.3'}, + {'p':'5.1.3.0/24', 'n':'99.0.0.3'}, + {'p':'99.0.0.3/32', 'n':'192.168.1.2'}, +] +bgpribRequireUnicastRoutes('r4','ipv4','r4-cust1','Customer 1 routes in r4 vrf',want_r4_cust1_routes) + +want_r4_cust2_routes = [ + {'p':'5.4.2.0/24', 'n':'99.0.0.4'}, + {'p':'5.4.3.0/24', 'n':'99.0.0.4'}, + {'p':'99.0.0.4/32', 'n':'192.168.2.2'}, +] +bgpribRequireUnicastRoutes('r4','ipv4','r4-cust2','Customer 2 routes in r4 vrf',want_r4_cust2_routes) + +######################################################################## +# PE routers: core unicast routes are empty +######################################################################## + +luCommand('r1','vtysh -c "show bgp ipv4 uni"','No BGP prefixes displayed','pass','Core Unicast SAFI clean') +luCommand('r2','vtysh -c "show bgp ipv4 uni"','No BGP prefixes displayed','pass','Core Unicast SAFI clean') +luCommand('r3','vtysh -c "show bgp ipv4 uni"','No BGP prefixes displayed','pass','Core Unicast SAFI clean') +luCommand('r4','vtysh -c "show bgp ipv4 uni"','No BGP prefixes displayed','pass','Core Unicast SAFI clean') + +######################################################################## +# PE routers: local ce-originated routes are leaked to vpn +######################################################################## + +# nhzero is for the new code that sets nh of locally-leaked routes to 0 +#nhzero = 1 +nhzero = 0 + +if nhzero: + luCommand('r1','vtysh -c "show bgp ipv4 vpn"', + 'Distinguisher: *10:1.*5.1.0.0/24 *0.0.0.0 .*5.1.1.0/24 *0.0.0.0 .*99.0.0.1/32 *0.0.0.0 ', + 'pass','vrf->vpn routes') + luCommand('r3','vtysh -c "show bgp ipv4 vpn"', + 'Distinguisher: *10:3.*5.1.0.0/24 *0.0.0.0 .*5.1.1.0/24 *0.0.0.0 .*99.0.0.2/32 *0.0.0.0 ', + 'pass','vrf->vpn routes') + want = [ + {'rd':'10:41', 'p':'5.1.2.0/24', 'n':'0.0.0.0'}, + {'rd':'10:41', 'p':'5.1.3.0/24', 'n':'0.0.0.0'}, + {'rd':'10:41', 'p':'99.0.0.3/32', 'n':'0.0.0.0'}, + + {'rd':'10:42', 'p':'5.4.2.0/24', 'n':'0.0.0.0'}, + {'rd':'10:42', 'p':'5.4.3.0/24', 'n':'0.0.0.0'}, + {'rd':'10:42', 'p':'99.0.0.4/32', 'n':'0.0.0.0'}, + ] + bgpribRequireVpnRoutes('r4','vrf->vpn routes',want) + +else: + luCommand('r1','vtysh -c "show bgp ipv4 vpn"', + r'Distinguisher: *10:1.*5.1.0.0/24 *99.0.0.1\b.*5.1.1.0/24 *99.0.0.1\b.*99.0.0.1/32 *192.168.1.2\b', + 'pass','vrf->vpn routes') + luCommand('r3','vtysh -c "show bgp ipv4 vpn"', + r'Distinguisher: *10:3.*5.1.0.0/24 *99.0.0.2\b.*5.1.1.0/24 *99.0.0.2\b.*99.0.0.2/32 *192.168.1.2\b', + 'pass','vrf->vpn routes') + want = [ + {'rd':'10:41', 'p':'5.1.2.0/24', 'n':'99.0.0.3'}, + {'rd':'10:41', 'p':'5.1.3.0/24', 'n':'99.0.0.3'}, + {'rd':'10:41', 'p':'99.0.0.3/32', 'n':'192.168.1.2'}, + + {'rd':'10:42', 'p':'5.4.2.0/24', 'n':'99.0.0.4'}, + {'rd':'10:42', 'p':'5.4.3.0/24', 'n':'99.0.0.4'}, + {'rd':'10:42', 'p':'99.0.0.4/32', 'n':'192.168.2.2'}, + ] + bgpribRequireVpnRoutes('r4','vrf->vpn routes',want) + +######################################################################## +# PE routers: exporting vrfs set MPLS vrf labels in kernel +######################################################################## + +luCommand('r1','vtysh -c "show mpls table"',' 101 *BGP *r1-cust1','pass','vrf labels') +luCommand('r3','vtysh -c "show mpls table"',' 103 *BGP *r3-cust1','pass','vrf labels') +luCommand('r4','vtysh -c "show mpls table"',' 1041 *BGP *r4-cust1 .*1042 *BGP *r4-cust2','pass','vrf labels') + +######################################################################## +# Core VPN router: all customer routes +######################################################################## + +want_rd_routes = [ + {'rd':'10:1', 'p':'5.1.0.0/24', 'n':'1.1.1.1'}, + {'rd':'10:1', 'p':'5.1.0.0/24', 'n':'1.1.1.1'}, + {'rd':'10:1', 'p':'99.0.0.1/32', 'n':'1.1.1.1'}, + + {'rd':'10:3', 'p':'5.1.0.0/24', 'n':'3.3.3.3'}, + {'rd':'10:3', 'p':'5.1.0.0/24', 'n':'3.3.3.3'}, + {'rd':'10:3', 'p':'99.0.0.2/32', 'n':'3.3.3.3'}, + + {'rd':'10:41', 'p':'5.1.2.0/24', 'n':'4.4.4.4'}, + {'rd':'10:41', 'p':'5.1.3.0/24', 'n':'4.4.4.4'}, + {'rd':'10:41', 'p':'99.0.0.3/32', 'n':'4.4.4.4'}, + + {'rd':'10:42', 'p':'5.4.2.0/24', 'n':'4.4.4.4'}, + {'rd':'10:42', 'p':'5.4.3.0/24', 'n':'4.4.4.4'}, + {'rd':'10:42', 'p':'99.0.0.4/32', 'n':'4.4.4.4'}, +] +bgpribRequireVpnRoutes('r2','Customer routes in provider vpn core',want_rd_routes) + +######################################################################## +# PE routers: VPN routes from remote customers +######################################################################## +# +# r1 vtysh -c "show bgp ipv4 vpn" +# +want_r1_remote_vpn_routes = [ + {'rd':'10:3', 'p':'5.1.0.0/24', 'n':'3.3.3.3'}, + {'rd':'10:3', 'p':'5.1.1.0/24', 'n':'3.3.3.3'}, + {'rd':'10:3', 'p':'99.0.0.2/32', 'n':'3.3.3.3'}, + + {'rd':'10:41', 'p':'5.1.2.0/24', 'n':'4.4.4.4'}, + {'rd':'10:41', 'p':'5.1.3.0/24', 'n':'4.4.4.4'}, + {'rd':'10:41', 'p':'99.0.0.3/32', 'n':'4.4.4.4'}, + + {'rd':'10:42', 'p':'5.4.2.0/24', 'n':'4.4.4.4'}, + {'rd':'10:42', 'p':'5.4.3.0/24', 'n':'4.4.4.4'}, + {'rd':'10:42', 'p':'99.0.0.4/32', 'n':'4.4.4.4'}, +] +bgpribRequireVpnRoutes('r1','Remote Customer routes in R1 vpn',want_r1_remote_vpn_routes) + +want_r3_remote_vpn_routes = [ + {'rd':'10:1', 'p':'5.1.0.0/24', 'n':'1.1.1.1'}, + {'rd':'10:1', 'p':'5.1.1.0/24', 'n':'1.1.1.1'}, + {'rd':'10:1', 'p':'99.0.0.1/32', 'n':'1.1.1.1'}, + + {'rd':'10:41', 'p':'5.1.2.0/24', 'n':'4.4.4.4'}, + {'rd':'10:41', 'p':'5.1.3.0/24', 'n':'4.4.4.4'}, + {'rd':'10:41', 'p':'99.0.0.3/32', 'n':'4.4.4.4'}, + + {'rd':'10:42', 'p':'5.4.2.0/24', 'n':'4.4.4.4'}, + {'rd':'10:42', 'p':'5.4.3.0/24', 'n':'4.4.4.4'}, + {'rd':'10:42', 'p':'99.0.0.4/32', 'n':'4.4.4.4'}, +] +bgpribRequireVpnRoutes('r3','Remote Customer routes in R3 vpn',want_r3_remote_vpn_routes) + +want_r4_remote_vpn_routes = [ + {'rd':'10:1', 'p':'5.1.0.0/24', 'n':'1.1.1.1'}, + {'rd':'10:1', 'p':'5.1.1.0/24', 'n':'1.1.1.1'}, + {'rd':'10:1', 'p':'99.0.0.1/32', 'n':'1.1.1.1'}, + + {'rd':'10:3', 'p':'5.1.0.0/24', 'n':'3.3.3.3'}, + {'rd':'10:3', 'p':'5.1.1.0/24', 'n':'3.3.3.3'}, + {'rd':'10:3', 'p':'99.0.0.2/32', 'n':'3.3.3.3'}, +] +bgpribRequireVpnRoutes('r4','Remote Customer routes in R4 vpn',want_r4_remote_vpn_routes) + + + +# r1 vtysh -c "show bgp vrf r1-cust1 ipv4" + +######################################################################## +# PE routers: VRFs contain routes from remote customer nets +######################################################################## +want_r1_remote_cust1_routes = [ + {'p':'5.1.0.0/24', 'n':'3.3.3.3'}, + {'p':'5.1.1.0/24', 'n':'3.3.3.3'}, + {'p':'99.0.0.2/32', 'n':'3.3.3.3'}, + + {'p':'5.1.2.0/24', 'n':'4.4.4.4'}, + {'p':'5.1.3.0/24', 'n':'4.4.4.4'}, + {'p':'99.0.0.3/32', 'n':'4.4.4.4'}, + + {'p':'5.4.2.0/24', 'n':'4.4.4.4'}, + {'p':'5.4.3.0/24', 'n':'4.4.4.4'}, + {'p':'99.0.0.3/32', 'n':'4.4.4.4'}, +] +bgpribRequireUnicastRoutes('r1','ipv4','r1-cust1','Customer 1 routes in r1 vrf',want_r1_remote_cust1_routes) + +want_r3_remote_cust1_routes = [ + {'p':'5.1.0.0/24', 'n':'1.1.1.1'}, + {'p':'5.1.1.0/24', 'n':'1.1.1.1'}, + {'p':'99.0.0.1/32', 'n':'1.1.1.1'}, + + {'p':'5.1.2.0/24', 'n':'4.4.4.4'}, + {'p':'5.1.3.0/24', 'n':'4.4.4.4'}, + {'p':'99.0.0.3/32', 'n':'4.4.4.4'}, + + {'p':'5.4.2.0/24', 'n':'4.4.4.4'}, + {'p':'5.4.3.0/24', 'n':'4.4.4.4'}, + {'p':'99.0.0.3/32', 'n':'4.4.4.4'}, +] +bgpribRequireUnicastRoutes('r3','ipv4','r3-cust1','Customer 1 routes in r3 vrf',want_r3_remote_cust1_routes) + +want_r4_remote_cust1_routes = [ + {'p':'5.1.0.0/24', 'n':'1.1.1.1'}, + {'p':'5.1.1.0/24', 'n':'1.1.1.1'}, + {'p':'5.1.0.0/24', 'n':'3.3.3.3'}, + {'p':'5.1.1.0/24', 'n':'3.3.3.3'}, + {'p':'99.0.0.1/32', 'n':'1.1.1.1'}, + {'p':'99.0.0.2/32', 'n':'3.3.3.3'}, +] +bgpribRequireUnicastRoutes('r4','ipv4','r4-cust1','Customer 1 routes in r4 vrf',want_r4_remote_cust1_routes) + +want_r4_remote_cust2_routes = [ + {'p':'5.1.0.0/24', 'n':'1.1.1.1'}, + {'p':'5.1.1.0/24', 'n':'1.1.1.1'}, + {'p':'5.1.0.0/24', 'n':'3.3.3.3'}, + {'p':'5.1.1.0/24', 'n':'3.3.3.3'}, + {'p':'99.0.0.1/32', 'n':'1.1.1.1'}, + {'p':'99.0.0.2/32', 'n':'3.3.3.3'}, +] +bgpribRequireUnicastRoutes('r4','ipv4','r4-cust2','Customer 2 routes in r4 vrf',want_r4_remote_cust2_routes) + + +######################################################################### +# CE routers: contain routes from remote customer nets +######################################################################### +# ce1 vtysh -c "show bgp ipv4 uni" +# r1 vtysh -c "show bgp vrf r1-cust1 ipv4" +# r1 vtysh -c "show bgp vrf r1-cust1 ipv4 5.1.2.0/24" + +luCommand('ce1','vtysh -c "show bgp ipv4 uni"','10 routes and 10','wait','Local and remote routes', 10) +want = [ + {'p':'5.1.2.0/24', 'n':'192.168.1.1'}, + {'p':'5.1.3.0/24', 'n':'192.168.1.1'}, + {'p':'5.4.2.0/24', 'n':'192.168.1.1'}, + {'p':'5.4.3.0/24', 'n':'192.168.1.1'}, +] +bgpribRequireUnicastRoutes('ce1','ipv4','','Cust 1 routes from remote',want) + +luCommand('ce2','vtysh -c "show bgp ipv4 uni"','10 routes and 12','wait','Local and remote routes', 10) +want = [ + {'p':'5.1.0.0/24', 'n':'192.168.1.1'}, + {'p':'5.1.1.0/24', 'n':'192.168.1.1'}, + {'p':'5.1.2.0/24', 'n':'192.168.1.1'}, + {'p':'5.1.3.0/24', 'n':'192.168.1.1'}, + {'p':'5.4.2.0/24', 'n':'192.168.1.1'}, + {'p':'5.4.3.0/24', 'n':'192.168.1.1'}, +] +bgpribRequireUnicastRoutes('ce2','ipv4','','Cust 1 routes from remote',want) + +# human readable output for debugging +luCommand('r4','vtysh -c "show bgp vrf r4-cust1 ipv4 uni"') +luCommand('r4','vtysh -c "show bgp vrf r4-cust2 ipv4 uni"') +luCommand('r4','vtysh -c "show bgp ipv4 vpn"') +luCommand('r4','vtysh -c "show ip route vrf r4-cust1"') +luCommand('r4','vtysh -c "show ip route vrf r4-cust2"') + +luCommand('ce3','vtysh -c "show bgp ipv4 uni"','10 routes and 10','wait','Local and remote routes', 10) +# Requires bvl-bug-degenerate-no-label fix (FRR PR #2053) +want = [ + {'p':'5.1.0.0/24', 'n':'192.168.1.1'}, + {'p':'5.1.1.0/24', 'n':'192.168.1.1'}, + {'p':'5.4.2.0/24', 'n':'192.168.1.1'}, + {'p':'5.4.3.0/24', 'n':'192.168.1.1'}, +] +bgpribRequireUnicastRoutes('ce3','ipv4','','Cust 1 routes from remote',want) + +luCommand('ce4','vtysh -c "show bgp ipv4 uni"','10 routes and 10','wait','Local and remote routes', 10) +want = [ + {'p':'5.1.0.0/24', 'n':'192.168.2.1'}, + {'p':'5.1.1.0/24', 'n':'192.168.2.1'}, + {'p':'5.1.2.0/24', 'n':'192.168.2.1'}, + {'p':'5.1.3.0/24', 'n':'192.168.2.1'}, +] +bgpribRequireUnicastRoutes('ce4','ipv4','','Cust 2 routes from remote',want) + diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/cleanup_all.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/cleanup_all.py new file mode 100644 index 0000000000..a721cf21bd --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/cleanup_all.py @@ -0,0 +1,17 @@ +from lutil import luCommand +luCommand('r1','vtysh -c "clear vrf r1-cust1 prefix 99.0.0.1/32"','.','none','Cleared VRF route') +luCommand('r3','vtysh -c "clear vrf r3-cust1 prefix 99.0.0.2/32"','.','none','Cleared VRF route') +luCommand('r4','vtysh -c "clear vrf r3-cust1 prefix 99.0.0.3/32"','.','none','Cleared VRF route') +luCommand('r1','vtysh -c "show vnc registrations local"','99.0.0.1','fail','Local Registration cleared') +luCommand('r3','vtysh -c "show vnc registrations local"','99.0.0.2','fail','Local Registration cleared') +luCommand('r4','vtysh -c "show vnc registrations local"','99.0.0.3','fail','Local Registration cleared') +luCommand('r1','vtysh -c "show bgp ipv4 uni"','2 routes and 2','wait','Unicast SAFI updated', 10) +luCommand('r2','vtysh -c "show bgp ipv4 uni"','No BGP prefixes displayed','pass','Unicast SAFI') +luCommand('r3','vtysh -c "show bgp ipv4 uni"','2 routes and 2','wait','Unicast SAFI updated', 10) +luCommand('r4','vtysh -c "show bgp ipv4 uni"','2 routes and 2','wait','Unicast SAFI updated', 10) +luCommand('ce1','vtysh -c "show bgp ipv4 uni"','2 routes and 2','wait','Local and remote routes', 10) +luCommand('ce2','vtysh -c "show bgp ipv4 uni"','2 routes and 2','wait','Local and remote routes', 10) +luCommand('ce3','vtysh -c "show bgp ipv4 uni"','2 routes and 2','wait','Local and remote routes', 10) +luCommand('r1','vtysh -c "show vnc registrations remote"','Prefix ','fail','Remote Registration cleared') +luCommand('r3','vtysh -c "show vnc registrations remote"','Prefix ','fail','Remote Registration cleared') +luCommand('r4','vtysh -c "show vnc registrations remote"','Prefix ','fail','Remote Registration cleared') diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/test_bgp_l3vpn_to_bgp_vrf.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/test_bgp_l3vpn_to_bgp_vrf.py new file mode 100755 index 0000000000..1da1066f0e --- /dev/null +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/test_bgp_l3vpn_to_bgp_vrf.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python + +# +# Part of NetDEF Topology Tests +# +# Copyright (c) 2018, LabN Consulting, L.L.C. +# Authored by Lou Berger +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +import os +import sys +import pytest + +sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../')) + +from lib.ltemplate import * + +def test_check_linux_vrf(): + CliOnFail = None + # For debugging, uncomment the next line + #CliOnFail = 'tgen.mininet_cli' + CheckFunc = 'ltemplateVersionCheck(\'4.1\', iproute2=\'4.9\')' + #uncomment next line to start cli *before* script is run + #CheckFunc = 'ltemplateVersionCheck(\'4.1\', cli=True, iproute2=\'4.9\')' + ltemplateTest('scripts/check_linux_vrf.py', False, CliOnFail, CheckFunc) + +def test_adjacencies(): + CliOnFail = None + # For debugging, uncomment the next line + #CliOnFail = 'tgen.mininet_cli' + CheckFunc = 'ltemplateVersionCheck(\'4.1\')' + #uncomment next line to start cli *before* script is run + #CheckFunc = 'ltemplateVersionCheck(\'4.1\', cli=True)' + ltemplateTest('scripts/adjacencies.py', False, CliOnFail, CheckFunc) + +def SKIP_test_add_routes(): + CliOnFail = None + # For debugging, uncomment the next line + #CliOnFail = 'tgen.mininet_cli' + CheckFunc = 'ltemplateVersionCheck(\'4.1\')' + #uncomment next line to start cli *before* script is run + #CheckFunc = 'ltemplateVersionCheck(\'4.1\', cli=True)' + ltemplateTest('scripts/add_routes.py', False, CliOnFail, CheckFunc) + +def test_check_routes(): + CliOnFail = None + # For debugging, uncomment the next line + #CliOnFail = 'tgen.mininet_cli' + CheckFunc = 'ltemplateVersionCheck(\'4.1\')' + #uncomment next line to start cli *before* script is run + #CheckFunc = 'ltemplateVersionCheck(\'4.1\', cli=True)' + ltemplateTest('scripts/check_routes.py', False, CliOnFail, CheckFunc) + +#manual data path setup test - remove once have bgp/zebra vrf path working +def test_check_linux_mpls(): + CliOnFail = None + # For debugging, uncomment the next line + #CliOnFail = 'tgen.mininet_cli' + CheckFunc = 'ltemplateVersionCheck(\'4.1\', iproute2=\'4.9\')' + #uncomment next line to start cli *before* script is run + #CheckFunc = 'ltemplateVersionCheck(\'4.1\', cli=True, iproute2=\'4.9\')' + ltemplateTest('scripts/check_linux_mpls.py', False, CliOnFail, CheckFunc) + +def SKIP_test_cleanup_all(): + CliOnFail = None + # For debugging, uncomment the next line + #CliOnFail = 'tgen.mininet_cli' + CheckFunc = 'ltemplateVersionCheck(\'4.1\')' + #uncomment next line to start cli *before* script is run + #CheckFunc = 'ltemplateVersionCheck(\'4.1\', cli=True)' + ltemplateTest('scripts/cleanup_all.py', False, CliOnFail, CheckFunc) + +if __name__ == '__main__': + retval = pytest.main(["-s"]) + sys.exit(retval) diff --git a/tests/topotests/bgp_multiview_topo1/README.md b/tests/topotests/bgp_multiview_topo1/README.md new file mode 100644 index 0000000000..b9982d4900 --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/README.md @@ -0,0 +1,127 @@ +# Simple FreeRangeRouting Route-Server Test + +## Topology + +----------+ +----------+ +----------+ +----------+ +----------+ + | peer1 | | peer2 | | peer3 | | peer4 | | peer5 | + | AS 65001 | | AS 65002 | | AS 65003 | | AS 65004 | | AS 65005 | + +-----+----+ +-----+----+ +-----+----+ +-----+----+ +-----+----+ + | .1 | .2 | .3 | .4 | .5 + | ______/ / / _________/ + \ / ________________/ / / + | | / _________________________/ / +----------+ + | | | / __________________________/ ___| peer6 | + | | | | / ____________________________/.6 | AS 65006 | + | | | | | / _________________________ +----------+ + | | | | | | / __________________ \ +----------+ + | | | | | | | / \ \___| peer7 | + | | | | | | | | \ .7 | AS 65007 | + ~~~~~~~~~~~~~~~~~~~~~ \ +----------+ + ~~ SW1 ~~ \ +----------+ + ~~ Switch ~~ \_____| peer8 | + ~~ 172.16.1.0/24 ~~ .8 | AS 65008 | + ~~~~~~~~~~~~~~~~~~~~~ +----------+ + | + | .254 + +---------+---------+ + | FRR R1 | + | BGP Multi-View | + | Peer 1-3 > View 1 | + | Peer 4-5 > View 2 | + | Peer 6-8 > View 3 | + +---------+---------+ + | .1 + | + ~~~~~~~~~~~~~ Stub Network is redistributed + ~~ SW0 ~~ into each BGP view with different + ~~ 172.20.0.1/28 ~~ attributes (using route-map) + ~~ Stub Switch ~~ + ~~~~~~~~~~~~~ + +## FRR Configuration + +Full config as used is in r1 subdirectory + +Simplified `R1` config: + + hostname r1 + ! + interface r1-stub + description Stub Network + ip address 172.20.0.1/28 + no link-detect + ! + interface r1-eth0 + description to PE router - vlan1 + ip address 172.16.1.254/24 + no link-detect + ! + bgp multiple-instance + ! + router bgp 100 view 1 + bgp router-id 172.30.1.1 + network 172.20.0.0/28 route-map local1 + timers bgp 60 180 + neighbor 172.16.1.1 remote-as 65001 + neighbor 172.16.1.2 remote-as 65002 + neighbor 172.16.1.5 remote-as 65005 + ! + router bgp 100 view 2 + bgp router-id 172.30.1.1 + network 172.20.0.0/28 route-map local2 + timers bgp 60 180 + neighbor 172.16.1.3 remote-as 65003 + neighbor 172.16.1.4 remote-as 65004 + ! + router bgp 100 view 3 + bgp router-id 172.30.1.1 + network 172.20.0.0/28 + timers bgp 60 180 + neighbor 172.16.1.6 remote-as 65006 + neighbor 172.16.1.7 remote-as 65007 + neighbor 172.16.1.8 remote-as 65008 + ! + route-map local1 permit 10 + set community 100:9999 additive + set metric 0 + ! + route-map local2 permit 10 + set as-path prepend 100 100 100 100 100 + set community 100:1 additive + set metric 9999 + ! + +## Tests executed + +### Check if FRR is running + +Test is executed by running + + vtysh -c "show log" | grep "Logging configuration for" + +on router `R1`. This should return the logging information for all daemons registered +to Zebra and the list of running daemons is compared to the daemons started for this +test (`zebra` and `bgpd`) + +### Verify for BGP to converge + +BGP is expected to converge on each view within 60s total time. Convergence is verified by executing + + vtysh -c "show ip bgp view 1 summary" + vtysh -c "show ip bgp view 2 summary" + vtysh -c "show ip bgp view 3 summary" + +and expecting 11 routes seen in the last column for each peer. (Each peer sends 11 routes) + +### Verifying BGP Routing Tables + +Routing table is verified by running + + vtysh -c "show ip bgp view 1" + vtysh -c "show ip bgp view 2" + vtysh -c "show ip bgp view 3" + +and comparing the result against the stored table in the r1/show_ip_bgp_view_NN.ref files +(with NN 1, 2, 3) (A few header and trailer lines are cut/adjusted ahead of the compare to +adjust for different output based on recent changes) + + diff --git a/tests/topotests/bgp_multiview_topo1/exabgp.env b/tests/topotests/bgp_multiview_topo1/exabgp.env new file mode 100644 index 0000000000..a328e04962 --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/exabgp.env @@ -0,0 +1,54 @@ + +[exabgp.api] +encoder = text +highres = false +respawn = false +socket = '' + +[exabgp.bgp] +openwait = 60 + +[exabgp.cache] +attributes = true +nexthops = true + +[exabgp.daemon] +daemonize = true +pid = '/var/run/exabgp/exabgp.pid' +user = 'exabgp' +##daemonize = false + +[exabgp.log] +all = false +configuration = true +daemon = true +destination = '/var/log/exabgp.log' +enable = true +level = INFO +message = false +network = true +packets = false +parser = false +processes = true +reactor = true +rib = false +routes = false +short = false +timers = false + +[exabgp.pdb] +enable = false + +[exabgp.profile] +enable = false +file = '' + +[exabgp.reactor] +speed = 1.0 + +[exabgp.tcp] +acl = false +bind = '' +delay = 0 +once = false +port = 179 diff --git a/tests/topotests/bgp_multiview_topo1/peer1/exa-receive.py b/tests/topotests/bgp_multiview_topo1/peer1/exa-receive.py new file mode 100755 index 0000000000..5334ea5369 --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer1/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp_multiview_topo1/peer1/exa-send.py b/tests/topotests/bgp_multiview_topo1/peer1/exa-send.py new file mode 100755 index 0000000000..2de2bce40a --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer1/exa-send.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) + +# Announce numRoutes different routes per PE +for i in range(0, numRoutes): + stdout.write('announce route 10.%s.%s.0/24 med 100 community %i:1 next-hop 172.16.1.%i\n' % ((peer+100), i, peer, peer)) + stdout.flush() + +# Announce 1 overlapping route per peer +stdout.write('announce route 10.0.1.0/24 next-hop 172.16.1.%i\n' % peer) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) diff --git a/tests/topotests/bgp_multiview_topo1/peer1/exabgp.cfg b/tests/topotests/bgp_multiview_topo1/peer1/exabgp.cfg new file mode 100644 index 0000000000..20e71c8420 --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer1/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa-send.py 1 10"; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 1"; + receive-routes; + encoder text; + } + + neighbor 172.16.1.254 { + router-id 172.16.1.1; + local-address 172.16.1.1; + local-as 65001; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp_multiview_topo1/peer2/exa-receive.py b/tests/topotests/bgp_multiview_topo1/peer2/exa-receive.py new file mode 100755 index 0000000000..5334ea5369 --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer2/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp_multiview_topo1/peer2/exa-send.py b/tests/topotests/bgp_multiview_topo1/peer2/exa-send.py new file mode 100755 index 0000000000..2de2bce40a --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer2/exa-send.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) + +# Announce numRoutes different routes per PE +for i in range(0, numRoutes): + stdout.write('announce route 10.%s.%s.0/24 med 100 community %i:1 next-hop 172.16.1.%i\n' % ((peer+100), i, peer, peer)) + stdout.flush() + +# Announce 1 overlapping route per peer +stdout.write('announce route 10.0.1.0/24 next-hop 172.16.1.%i\n' % peer) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) diff --git a/tests/topotests/bgp_multiview_topo1/peer2/exabgp.cfg b/tests/topotests/bgp_multiview_topo1/peer2/exabgp.cfg new file mode 100644 index 0000000000..1e8eef186f --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer2/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa-send.py 2 10"; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 2"; + receive-routes; + encoder text; + } + + neighbor 172.16.1.254 { + router-id 172.16.1.2; + local-address 172.16.1.2; + local-as 65002; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp_multiview_topo1/peer3/exa-receive.py b/tests/topotests/bgp_multiview_topo1/peer3/exa-receive.py new file mode 100755 index 0000000000..5334ea5369 --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer3/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp_multiview_topo1/peer3/exa-send.py b/tests/topotests/bgp_multiview_topo1/peer3/exa-send.py new file mode 100755 index 0000000000..2de2bce40a --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer3/exa-send.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) + +# Announce numRoutes different routes per PE +for i in range(0, numRoutes): + stdout.write('announce route 10.%s.%s.0/24 med 100 community %i:1 next-hop 172.16.1.%i\n' % ((peer+100), i, peer, peer)) + stdout.flush() + +# Announce 1 overlapping route per peer +stdout.write('announce route 10.0.1.0/24 next-hop 172.16.1.%i\n' % peer) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) diff --git a/tests/topotests/bgp_multiview_topo1/peer3/exabgp.cfg b/tests/topotests/bgp_multiview_topo1/peer3/exabgp.cfg new file mode 100644 index 0000000000..ef1b249aeb --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer3/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa-send.py 3 10"; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 3"; + receive-routes; + encoder text; + } + + neighbor 172.16.1.254 { + router-id 172.16.1.3; + local-address 172.16.1.3; + local-as 65003; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp_multiview_topo1/peer4/exa-receive.py b/tests/topotests/bgp_multiview_topo1/peer4/exa-receive.py new file mode 100755 index 0000000000..5334ea5369 --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer4/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp_multiview_topo1/peer4/exa-send.py b/tests/topotests/bgp_multiview_topo1/peer4/exa-send.py new file mode 100755 index 0000000000..2de2bce40a --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer4/exa-send.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) + +# Announce numRoutes different routes per PE +for i in range(0, numRoutes): + stdout.write('announce route 10.%s.%s.0/24 med 100 community %i:1 next-hop 172.16.1.%i\n' % ((peer+100), i, peer, peer)) + stdout.flush() + +# Announce 1 overlapping route per peer +stdout.write('announce route 10.0.1.0/24 next-hop 172.16.1.%i\n' % peer) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) diff --git a/tests/topotests/bgp_multiview_topo1/peer4/exabgp.cfg b/tests/topotests/bgp_multiview_topo1/peer4/exabgp.cfg new file mode 100644 index 0000000000..7c50f73b26 --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer4/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa-send.py 4 10"; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 4"; + receive-routes; + encoder text; + } + + neighbor 172.16.1.254 { + router-id 172.16.1.4; + local-address 172.16.1.4; + local-as 65004; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp_multiview_topo1/peer5/exa-receive.py b/tests/topotests/bgp_multiview_topo1/peer5/exa-receive.py new file mode 100755 index 0000000000..5334ea5369 --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer5/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp_multiview_topo1/peer5/exa-send.py b/tests/topotests/bgp_multiview_topo1/peer5/exa-send.py new file mode 100755 index 0000000000..2de2bce40a --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer5/exa-send.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) + +# Announce numRoutes different routes per PE +for i in range(0, numRoutes): + stdout.write('announce route 10.%s.%s.0/24 med 100 community %i:1 next-hop 172.16.1.%i\n' % ((peer+100), i, peer, peer)) + stdout.flush() + +# Announce 1 overlapping route per peer +stdout.write('announce route 10.0.1.0/24 next-hop 172.16.1.%i\n' % peer) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) diff --git a/tests/topotests/bgp_multiview_topo1/peer5/exabgp.cfg b/tests/topotests/bgp_multiview_topo1/peer5/exabgp.cfg new file mode 100644 index 0000000000..22163c7fb1 --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer5/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa-send.py 5 10"; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 5"; + receive-routes; + encoder text; + } + + neighbor 172.16.1.254 { + router-id 172.16.1.5; + local-address 172.16.1.5; + local-as 65005; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp_multiview_topo1/peer6/exa-receive.py b/tests/topotests/bgp_multiview_topo1/peer6/exa-receive.py new file mode 100755 index 0000000000..5334ea5369 --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer6/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp_multiview_topo1/peer6/exa-send.py b/tests/topotests/bgp_multiview_topo1/peer6/exa-send.py new file mode 100755 index 0000000000..2de2bce40a --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer6/exa-send.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) + +# Announce numRoutes different routes per PE +for i in range(0, numRoutes): + stdout.write('announce route 10.%s.%s.0/24 med 100 community %i:1 next-hop 172.16.1.%i\n' % ((peer+100), i, peer, peer)) + stdout.flush() + +# Announce 1 overlapping route per peer +stdout.write('announce route 10.0.1.0/24 next-hop 172.16.1.%i\n' % peer) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) diff --git a/tests/topotests/bgp_multiview_topo1/peer6/exabgp.cfg b/tests/topotests/bgp_multiview_topo1/peer6/exabgp.cfg new file mode 100644 index 0000000000..40b54c33c5 --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer6/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa-send.py 6 10"; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 6"; + receive-routes; + encoder text; + } + + neighbor 172.16.1.254 { + router-id 172.16.1.6; + local-address 172.16.1.6; + local-as 65006; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp_multiview_topo1/peer7/exa-receive.py b/tests/topotests/bgp_multiview_topo1/peer7/exa-receive.py new file mode 100755 index 0000000000..5334ea5369 --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer7/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp_multiview_topo1/peer7/exa-send.py b/tests/topotests/bgp_multiview_topo1/peer7/exa-send.py new file mode 100755 index 0000000000..2de2bce40a --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer7/exa-send.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) + +# Announce numRoutes different routes per PE +for i in range(0, numRoutes): + stdout.write('announce route 10.%s.%s.0/24 med 100 community %i:1 next-hop 172.16.1.%i\n' % ((peer+100), i, peer, peer)) + stdout.flush() + +# Announce 1 overlapping route per peer +stdout.write('announce route 10.0.1.0/24 next-hop 172.16.1.%i\n' % peer) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) diff --git a/tests/topotests/bgp_multiview_topo1/peer7/exabgp.cfg b/tests/topotests/bgp_multiview_topo1/peer7/exabgp.cfg new file mode 100644 index 0000000000..33312d052f --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer7/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa-send.py 7 10"; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 7"; + receive-routes; + encoder text; + } + + neighbor 172.16.1.254 { + router-id 172.16.1.7; + local-address 172.16.1.7; + local-as 65007; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp_multiview_topo1/peer8/exa-receive.py b/tests/topotests/bgp_multiview_topo1/peer8/exa-receive.py new file mode 100755 index 0000000000..5334ea5369 --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer8/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp_multiview_topo1/peer8/exa-send.py b/tests/topotests/bgp_multiview_topo1/peer8/exa-send.py new file mode 100755 index 0000000000..2de2bce40a --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer8/exa-send.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) + +# Announce numRoutes different routes per PE +for i in range(0, numRoutes): + stdout.write('announce route 10.%s.%s.0/24 med 100 community %i:1 next-hop 172.16.1.%i\n' % ((peer+100), i, peer, peer)) + stdout.flush() + +# Announce 1 overlapping route per peer +stdout.write('announce route 10.0.1.0/24 next-hop 172.16.1.%i\n' % peer) +stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) diff --git a/tests/topotests/bgp_multiview_topo1/peer8/exabgp.cfg b/tests/topotests/bgp_multiview_topo1/peer8/exabgp.cfg new file mode 100644 index 0000000000..173ccb980e --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/peer8/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa-send.py 8 10"; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 8"; + receive-routes; + encoder text; + } + + neighbor 172.16.1.254 { + router-id 172.16.1.8; + local-address 172.16.1.8; + local-as 65008; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp_multiview_topo1/r1/bgpd.conf b/tests/topotests/bgp_multiview_topo1/r1/bgpd.conf new file mode 100644 index 0000000000..0c24942f43 --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/r1/bgpd.conf @@ -0,0 +1,49 @@ +! +! Zebra configuration saved from vty +! 2015/12/24 21:46:33 +! +log file bgpd.log +! +!debug bgp events +!debug bgp keepalives +!debug bgp updates +!debug bgp fsm +!debug bgp filters +!debug bgp zebra +! +bgp multiple-instance +! +router bgp 100 view 1 + bgp router-id 172.30.1.1 + network 172.20.0.0/28 route-map local1 + timers bgp 60 180 + neighbor 172.16.1.1 remote-as 65001 + neighbor 172.16.1.2 remote-as 65002 + neighbor 172.16.1.5 remote-as 65005 +! +router bgp 100 view 2 + bgp router-id 172.30.1.1 + network 172.20.0.0/28 route-map local2 + timers bgp 60 180 + neighbor 172.16.1.3 remote-as 65003 + neighbor 172.16.1.4 remote-as 65004 +! +router bgp 100 view 3 + bgp router-id 172.30.1.1 + network 172.20.0.0/28 + timers bgp 60 180 + neighbor 172.16.1.6 remote-as 65006 + neighbor 172.16.1.7 remote-as 65007 + neighbor 172.16.1.8 remote-as 65008 +! +route-map local1 permit 10 + set community 100:9999 additive + set metric 0 +! +route-map local2 permit 10 + set as-path prepend 100 100 100 100 100 + set community 100:1 additive + set metric 9999 +! +line vty +! diff --git a/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_1-post4.1.ref b/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_1-post4.1.ref new file mode 100644 index 0000000000..9e30bf2ef0 --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_1-post4.1.ref @@ -0,0 +1,41 @@ +BGP table version is XXX, local router ID is 172.30.1.1, vrf id - +Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, + i internal, r RIB-failure, S Stale, R Removed +Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self +Origin codes: i - IGP, e - EGP, ? - incomplete + + Network Next Hop Metric LocPrf Weight Path +* 10.0.1.0/24 172.16.1.5 0 65005 i +* 172.16.1.2 0 65002 i +*> 172.16.1.1 0 65001 i +*> 10.101.0.0/24 172.16.1.1 100 0 65001 i +*> 10.101.1.0/24 172.16.1.1 100 0 65001 i +*> 10.101.2.0/24 172.16.1.1 100 0 65001 i +*> 10.101.3.0/24 172.16.1.1 100 0 65001 i +*> 10.101.4.0/24 172.16.1.1 100 0 65001 i +*> 10.101.5.0/24 172.16.1.1 100 0 65001 i +*> 10.101.6.0/24 172.16.1.1 100 0 65001 i +*> 10.101.7.0/24 172.16.1.1 100 0 65001 i +*> 10.101.8.0/24 172.16.1.1 100 0 65001 i +*> 10.101.9.0/24 172.16.1.1 100 0 65001 i +*> 10.102.0.0/24 172.16.1.2 100 0 65002 i +*> 10.102.1.0/24 172.16.1.2 100 0 65002 i +*> 10.102.2.0/24 172.16.1.2 100 0 65002 i +*> 10.102.3.0/24 172.16.1.2 100 0 65002 i +*> 10.102.4.0/24 172.16.1.2 100 0 65002 i +*> 10.102.5.0/24 172.16.1.2 100 0 65002 i +*> 10.102.6.0/24 172.16.1.2 100 0 65002 i +*> 10.102.7.0/24 172.16.1.2 100 0 65002 i +*> 10.102.8.0/24 172.16.1.2 100 0 65002 i +*> 10.102.9.0/24 172.16.1.2 100 0 65002 i +*> 10.105.0.0/24 172.16.1.5 100 0 65005 i +*> 10.105.1.0/24 172.16.1.5 100 0 65005 i +*> 10.105.2.0/24 172.16.1.5 100 0 65005 i +*> 10.105.3.0/24 172.16.1.5 100 0 65005 i +*> 10.105.4.0/24 172.16.1.5 100 0 65005 i +*> 10.105.5.0/24 172.16.1.5 100 0 65005 i +*> 10.105.6.0/24 172.16.1.5 100 0 65005 i +*> 10.105.7.0/24 172.16.1.5 100 0 65005 i +*> 10.105.8.0/24 172.16.1.5 100 0 65005 i +*> 10.105.9.0/24 172.16.1.5 100 0 65005 i +*> 172.20.0.0/28 0.0.0.0 0 32768 i diff --git a/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_1.ref b/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_1.ref new file mode 100644 index 0000000000..6f1b1a1036 --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_1.ref @@ -0,0 +1,40 @@ +BGP table version is XXX, local router ID is 172.30.1.1 +Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, + i internal, r RIB-failure, S Stale, R Removed +Origin codes: i - IGP, e - EGP, ? - incomplete + + Network Next Hop Metric LocPrf Weight Path +* 10.0.1.0/24 172.16.1.5 0 65005 i +* 172.16.1.2 0 65002 i +*> 172.16.1.1 0 65001 i +*> 10.101.0.0/24 172.16.1.1 100 0 65001 i +*> 10.101.1.0/24 172.16.1.1 100 0 65001 i +*> 10.101.2.0/24 172.16.1.1 100 0 65001 i +*> 10.101.3.0/24 172.16.1.1 100 0 65001 i +*> 10.101.4.0/24 172.16.1.1 100 0 65001 i +*> 10.101.5.0/24 172.16.1.1 100 0 65001 i +*> 10.101.6.0/24 172.16.1.1 100 0 65001 i +*> 10.101.7.0/24 172.16.1.1 100 0 65001 i +*> 10.101.8.0/24 172.16.1.1 100 0 65001 i +*> 10.101.9.0/24 172.16.1.1 100 0 65001 i +*> 10.102.0.0/24 172.16.1.2 100 0 65002 i +*> 10.102.1.0/24 172.16.1.2 100 0 65002 i +*> 10.102.2.0/24 172.16.1.2 100 0 65002 i +*> 10.102.3.0/24 172.16.1.2 100 0 65002 i +*> 10.102.4.0/24 172.16.1.2 100 0 65002 i +*> 10.102.5.0/24 172.16.1.2 100 0 65002 i +*> 10.102.6.0/24 172.16.1.2 100 0 65002 i +*> 10.102.7.0/24 172.16.1.2 100 0 65002 i +*> 10.102.8.0/24 172.16.1.2 100 0 65002 i +*> 10.102.9.0/24 172.16.1.2 100 0 65002 i +*> 10.105.0.0/24 172.16.1.5 100 0 65005 i +*> 10.105.1.0/24 172.16.1.5 100 0 65005 i +*> 10.105.2.0/24 172.16.1.5 100 0 65005 i +*> 10.105.3.0/24 172.16.1.5 100 0 65005 i +*> 10.105.4.0/24 172.16.1.5 100 0 65005 i +*> 10.105.5.0/24 172.16.1.5 100 0 65005 i +*> 10.105.6.0/24 172.16.1.5 100 0 65005 i +*> 10.105.7.0/24 172.16.1.5 100 0 65005 i +*> 10.105.8.0/24 172.16.1.5 100 0 65005 i +*> 10.105.9.0/24 172.16.1.5 100 0 65005 i +*> 172.20.0.0/28 0.0.0.0 0 32768 i diff --git a/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_2-post4.1.ref b/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_2-post4.1.ref new file mode 100644 index 0000000000..39eb3134be --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_2-post4.1.ref @@ -0,0 +1,30 @@ +BGP table version is XXX, local router ID is 172.30.1.1, vrf id - +Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, + i internal, r RIB-failure, S Stale, R Removed +Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self +Origin codes: i - IGP, e - EGP, ? - incomplete + + Network Next Hop Metric LocPrf Weight Path +* 10.0.1.0/24 172.16.1.4 0 65004 i +*> 172.16.1.3 0 65003 i +*> 10.103.0.0/24 172.16.1.3 100 0 65003 i +*> 10.103.1.0/24 172.16.1.3 100 0 65003 i +*> 10.103.2.0/24 172.16.1.3 100 0 65003 i +*> 10.103.3.0/24 172.16.1.3 100 0 65003 i +*> 10.103.4.0/24 172.16.1.3 100 0 65003 i +*> 10.103.5.0/24 172.16.1.3 100 0 65003 i +*> 10.103.6.0/24 172.16.1.3 100 0 65003 i +*> 10.103.7.0/24 172.16.1.3 100 0 65003 i +*> 10.103.8.0/24 172.16.1.3 100 0 65003 i +*> 10.103.9.0/24 172.16.1.3 100 0 65003 i +*> 10.104.0.0/24 172.16.1.4 100 0 65004 i +*> 10.104.1.0/24 172.16.1.4 100 0 65004 i +*> 10.104.2.0/24 172.16.1.4 100 0 65004 i +*> 10.104.3.0/24 172.16.1.4 100 0 65004 i +*> 10.104.4.0/24 172.16.1.4 100 0 65004 i +*> 10.104.5.0/24 172.16.1.4 100 0 65004 i +*> 10.104.6.0/24 172.16.1.4 100 0 65004 i +*> 10.104.7.0/24 172.16.1.4 100 0 65004 i +*> 10.104.8.0/24 172.16.1.4 100 0 65004 i +*> 10.104.9.0/24 172.16.1.4 100 0 65004 i +*> 172.20.0.0/28 0.0.0.0 9999 32768 100 100 100 100 100 i diff --git a/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_2.ref b/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_2.ref new file mode 100644 index 0000000000..0230d25f53 --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_2.ref @@ -0,0 +1,29 @@ +BGP table version is XXX, local router ID is 172.30.1.1 +Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, + i internal, r RIB-failure, S Stale, R Removed +Origin codes: i - IGP, e - EGP, ? - incomplete + + Network Next Hop Metric LocPrf Weight Path +* 10.0.1.0/24 172.16.1.4 0 65004 i +*> 172.16.1.3 0 65003 i +*> 10.103.0.0/24 172.16.1.3 100 0 65003 i +*> 10.103.1.0/24 172.16.1.3 100 0 65003 i +*> 10.103.2.0/24 172.16.1.3 100 0 65003 i +*> 10.103.3.0/24 172.16.1.3 100 0 65003 i +*> 10.103.4.0/24 172.16.1.3 100 0 65003 i +*> 10.103.5.0/24 172.16.1.3 100 0 65003 i +*> 10.103.6.0/24 172.16.1.3 100 0 65003 i +*> 10.103.7.0/24 172.16.1.3 100 0 65003 i +*> 10.103.8.0/24 172.16.1.3 100 0 65003 i +*> 10.103.9.0/24 172.16.1.3 100 0 65003 i +*> 10.104.0.0/24 172.16.1.4 100 0 65004 i +*> 10.104.1.0/24 172.16.1.4 100 0 65004 i +*> 10.104.2.0/24 172.16.1.4 100 0 65004 i +*> 10.104.3.0/24 172.16.1.4 100 0 65004 i +*> 10.104.4.0/24 172.16.1.4 100 0 65004 i +*> 10.104.5.0/24 172.16.1.4 100 0 65004 i +*> 10.104.6.0/24 172.16.1.4 100 0 65004 i +*> 10.104.7.0/24 172.16.1.4 100 0 65004 i +*> 10.104.8.0/24 172.16.1.4 100 0 65004 i +*> 10.104.9.0/24 172.16.1.4 100 0 65004 i +*> 172.20.0.0/28 0.0.0.0 9999 32768 100 100 100 100 100 i diff --git a/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_3-post4.1.ref b/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_3-post4.1.ref new file mode 100644 index 0000000000..fa53d79e88 --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_3-post4.1.ref @@ -0,0 +1,41 @@ +BGP table version is XXX, local router ID is 172.30.1.1, vrf id - +Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, + i internal, r RIB-failure, S Stale, R Removed +Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self +Origin codes: i - IGP, e - EGP, ? - incomplete + + Network Next Hop Metric LocPrf Weight Path +* 10.0.1.0/24 172.16.1.8 0 65008 i +* 172.16.1.7 0 65007 i +*> 172.16.1.6 0 65006 i +*> 10.106.0.0/24 172.16.1.6 100 0 65006 i +*> 10.106.1.0/24 172.16.1.6 100 0 65006 i +*> 10.106.2.0/24 172.16.1.6 100 0 65006 i +*> 10.106.3.0/24 172.16.1.6 100 0 65006 i +*> 10.106.4.0/24 172.16.1.6 100 0 65006 i +*> 10.106.5.0/24 172.16.1.6 100 0 65006 i +*> 10.106.6.0/24 172.16.1.6 100 0 65006 i +*> 10.106.7.0/24 172.16.1.6 100 0 65006 i +*> 10.106.8.0/24 172.16.1.6 100 0 65006 i +*> 10.106.9.0/24 172.16.1.6 100 0 65006 i +*> 10.107.0.0/24 172.16.1.7 100 0 65007 i +*> 10.107.1.0/24 172.16.1.7 100 0 65007 i +*> 10.107.2.0/24 172.16.1.7 100 0 65007 i +*> 10.107.3.0/24 172.16.1.7 100 0 65007 i +*> 10.107.4.0/24 172.16.1.7 100 0 65007 i +*> 10.107.5.0/24 172.16.1.7 100 0 65007 i +*> 10.107.6.0/24 172.16.1.7 100 0 65007 i +*> 10.107.7.0/24 172.16.1.7 100 0 65007 i +*> 10.107.8.0/24 172.16.1.7 100 0 65007 i +*> 10.107.9.0/24 172.16.1.7 100 0 65007 i +*> 10.108.0.0/24 172.16.1.8 100 0 65008 i +*> 10.108.1.0/24 172.16.1.8 100 0 65008 i +*> 10.108.2.0/24 172.16.1.8 100 0 65008 i +*> 10.108.3.0/24 172.16.1.8 100 0 65008 i +*> 10.108.4.0/24 172.16.1.8 100 0 65008 i +*> 10.108.5.0/24 172.16.1.8 100 0 65008 i +*> 10.108.6.0/24 172.16.1.8 100 0 65008 i +*> 10.108.7.0/24 172.16.1.8 100 0 65008 i +*> 10.108.8.0/24 172.16.1.8 100 0 65008 i +*> 10.108.9.0/24 172.16.1.8 100 0 65008 i +*> 172.20.0.0/28 0.0.0.0 0 32768 i diff --git a/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_3.ref b/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_3.ref new file mode 100644 index 0000000000..b7e8c79d3c --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_3.ref @@ -0,0 +1,40 @@ +BGP table version is XXX, local router ID is 172.30.1.1 +Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, + i internal, r RIB-failure, S Stale, R Removed +Origin codes: i - IGP, e - EGP, ? - incomplete + + Network Next Hop Metric LocPrf Weight Path +* 10.0.1.0/24 172.16.1.8 0 65008 i +* 172.16.1.7 0 65007 i +*> 172.16.1.6 0 65006 i +*> 10.106.0.0/24 172.16.1.6 100 0 65006 i +*> 10.106.1.0/24 172.16.1.6 100 0 65006 i +*> 10.106.2.0/24 172.16.1.6 100 0 65006 i +*> 10.106.3.0/24 172.16.1.6 100 0 65006 i +*> 10.106.4.0/24 172.16.1.6 100 0 65006 i +*> 10.106.5.0/24 172.16.1.6 100 0 65006 i +*> 10.106.6.0/24 172.16.1.6 100 0 65006 i +*> 10.106.7.0/24 172.16.1.6 100 0 65006 i +*> 10.106.8.0/24 172.16.1.6 100 0 65006 i +*> 10.106.9.0/24 172.16.1.6 100 0 65006 i +*> 10.107.0.0/24 172.16.1.7 100 0 65007 i +*> 10.107.1.0/24 172.16.1.7 100 0 65007 i +*> 10.107.2.0/24 172.16.1.7 100 0 65007 i +*> 10.107.3.0/24 172.16.1.7 100 0 65007 i +*> 10.107.4.0/24 172.16.1.7 100 0 65007 i +*> 10.107.5.0/24 172.16.1.7 100 0 65007 i +*> 10.107.6.0/24 172.16.1.7 100 0 65007 i +*> 10.107.7.0/24 172.16.1.7 100 0 65007 i +*> 10.107.8.0/24 172.16.1.7 100 0 65007 i +*> 10.107.9.0/24 172.16.1.7 100 0 65007 i +*> 10.108.0.0/24 172.16.1.8 100 0 65008 i +*> 10.108.1.0/24 172.16.1.8 100 0 65008 i +*> 10.108.2.0/24 172.16.1.8 100 0 65008 i +*> 10.108.3.0/24 172.16.1.8 100 0 65008 i +*> 10.108.4.0/24 172.16.1.8 100 0 65008 i +*> 10.108.5.0/24 172.16.1.8 100 0 65008 i +*> 10.108.6.0/24 172.16.1.8 100 0 65008 i +*> 10.108.7.0/24 172.16.1.8 100 0 65008 i +*> 10.108.8.0/24 172.16.1.8 100 0 65008 i +*> 10.108.9.0/24 172.16.1.8 100 0 65008 i +*> 172.20.0.0/28 0.0.0.0 0 32768 i diff --git a/tests/topotests/bgp_multiview_topo1/r1/zebra.conf b/tests/topotests/bgp_multiview_topo1/r1/zebra.conf new file mode 100644 index 0000000000..86343f56e4 --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/r1/zebra.conf @@ -0,0 +1,23 @@ +! +! Zebra configuration saved from vty +! 2015/12/24 16:48:27 +! +log file zebra.log +! +hostname r1 +! +interface r1-stub + description Stub Network + ip address 172.20.0.1/28 + no link-detect +! +interface r1-eth0 + description to PE router - vlan1 + ip address 172.16.1.254/24 + no link-detect +! +ip forwarding +! +! +line vty +! diff --git a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py new file mode 100755 index 0000000000..7607fe986b --- /dev/null +++ b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py @@ -0,0 +1,386 @@ +#!/usr/bin/env python + +# +# test_bgp_multiview_topo1.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2016 by +# Network Device Education Foundation, Inc. ("NetDEF") +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_bgp_multiview_topo1.py: Simple Quagga/FRR Route-Server Test + ++----------+ +----------+ +----------+ +----------+ +----------+ +| peer1 | | peer2 | | peer3 | | peer4 | | peer5 | +| AS 65001 | | AS 65002 | | AS 65003 | | AS 65004 | | AS 65005 | ++-----+----+ +-----+----+ +-----+----+ +-----+----+ +-----+----+ + | .1 | .2 | .3 | .4 | .5 + | ______/ / / _________/ + \ / ________________/ / / + | | / _________________________/ / +----------+ + | | | / __________________________/ ___| peer6 | + | | | | / ____________________________/.6 | AS 65006 | + | | | | | / _________________________ +----------+ + | | | | | | / __________________ \ +----------+ + | | | | | | | / \ \___| peer7 | + | | | | | | | | \ .7 | AS 65007 | + ~~~~~~~~~~~~~~~~~~~~~ \ +----------+ + ~~ SW1 ~~ \ +----------+ + ~~ Switch ~~ \_____| peer8 | + ~~ 172.16.1.0/24 ~~ .8 | AS 65008 | + ~~~~~~~~~~~~~~~~~~~~~ +----------+ + | + | .254 + +---------+---------+ + | FRR R1 | + | BGP Multi-View | + | Peer 1-3 > View 1 | + | Peer 4-5 > View 2 | + | Peer 6-8 > View 3 | + +---------+---------+ + | .1 + | + ~~~~~~~~~~~~~ Stub Network is redistributed + ~~ SW0 ~~ into each BGP view with different + ~~ 172.20.0.1/28 ~~ attributes (using route-map) + ~~ Stub Switch ~~ + ~~~~~~~~~~~~~ +""" + +import os +import re +import sys +import pytest +import glob +from time import sleep + +from mininet.topo import Topo +from mininet.net import Mininet +from mininet.node import Node, OVSSwitch, Host +from mininet.log import setLogLevel, info +from mininet.cli import CLI +from mininet.link import Intf + +from functools import partial + +sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +from lib import topotest + +fatal_error = "" + + +##################################################### +## +## Network Topology Definition +## +##################################################### + +class NetworkTopo(Topo): + "BGP Multiview Topology 1" + + def build(self, **_opts): + + exabgpPrivateDirs = ['/etc/exabgp', + '/var/run/exabgp', + '/var/log'] + + # Setup Routers + router = {} + for i in range(1, 2): + router[i] = topotest.addRouter(self, 'r%s' % i) + + # Setup Provider BGP peers + peer = {} + for i in range(1, 9): + peer[i] = self.addHost('peer%s' % i, ip='172.16.1.%s/24' % i, + defaultRoute='via 172.16.1.254', + privateDirs=exabgpPrivateDirs) + + # Setup Switches + switch = {} + # First switch is for a dummy interface (for local network) + switch[0] = self.addSwitch('sw0', cls=topotest.LegacySwitch) + self.addLink(switch[0], router[1], intfName2='r1-stub') + # Second switch is for connection to all peering routers + switch[1] = self.addSwitch('sw1', cls=topotest.LegacySwitch) + self.addLink(switch[1], router[1], intfName2='r1-eth0') + for j in range(1, 9): + self.addLink(switch[1], peer[j], intfName2='peer%s-eth0' % j) + + +##################################################### +## +## Tests starting +## +##################################################### + +def setup_module(module): + global topo, net + + print("\n\n** %s: Setup Topology" % module.__name__) + print("******************************************\n") + + print("Cleanup old Mininet runs") + os.system('sudo mn -c > /dev/null 2>&1') + + thisDir = os.path.dirname(os.path.realpath(__file__)) + topo = NetworkTopo() + + net = Mininet(controller=None, topo=topo) + net.start() + + # Starting Routers + for i in range(1, 2): + net['r%s' % i].loadConf('zebra', '%s/r%s/zebra.conf' % (thisDir, i)) + net['r%s' % i].loadConf('bgpd', '%s/r%s/bgpd.conf' % (thisDir, i)) + net['r%s' % i].startRouter() + + # Starting PE Hosts and init ExaBGP on each of them + print('*** Starting BGP on all 8 Peers in 10s') + sleep(10) + for i in range(1, 9): + net['peer%s' % i].cmd('cp %s/exabgp.env /etc/exabgp/exabgp.env' % thisDir) + net['peer%s' % i].cmd('cp %s/peer%s/* /etc/exabgp/' % (thisDir, i)) + net['peer%s' % i].cmd('chmod 644 /etc/exabgp/*') + net['peer%s' % i].cmd('chmod 755 /etc/exabgp/*.py') + net['peer%s' % i].cmd('chown -R exabgp:exabgp /etc/exabgp') + net['peer%s' % i].cmd('exabgp -e /etc/exabgp/exabgp.env /etc/exabgp/exabgp.cfg') + print('peer%s' % i), + print('') + + # For debugging after starting Quagga/FRR daemons, uncomment the next line + # CLI(net) + +def teardown_module(module): + global net + + print("\n\n** %s: Shutdown Topology" % module.__name__) + print("******************************************\n") + + # Shutdown - clean up everything + print('*** Killing BGP on Peer routers') + # Killing ExaBGP + for i in range(1, 9): + net['peer%s' % i].cmd('kill `cat /var/run/exabgp/exabgp.pid`') + + # End - Shutdown network + net.stop() + +def test_router_running(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + print("\n\n** Check if FRR/Quagga is running on each Router node") + print("******************************************\n") + sleep(5) + + # Starting Routers + for i in range(1, 2): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_bgp_converge(): + "Check for BGP converged on all peers and BGP views" + + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + # Wait for BGP to converge (All Neighbors in either Full or TwoWay State) + print("\n\n** Verify for BGP to converge") + print("******************************************\n") + timeout = 60 + while timeout > 0: + print("Timeout in %s: " % timeout), + sys.stdout.flush() + # Look for any node not yet converged + for i in range(1, 2): + for view in range(1, 4): + notConverged = net['r%s' % i].cmd('vtysh -c "show ip bgp view %s summary" 2> /dev/null | grep ^[0-9] | grep -v " 11$"' % view) + if notConverged: + print('Waiting for r%s, view %s' % (i, view)) + sys.stdout.flush() + break + if notConverged: + break + if notConverged: + sleep(5) + timeout -= 5 + else: + print('Done') + break + else: + # Bail out with error if a router fails to converge + bgpStatus = net['r%s' % i].cmd('vtysh -c "show ip bgp view %s summary"' % view) + assert False, "BGP did not converge:\n%s" % bgpStatus + + # Wait for an extra 30s to announce all routes + print('Waiting 30s for routes to be announced'); + sleep(30) + + print("BGP converged.") + + # if timeout < 60: + # # Only wait if we actually went through a convergence + # print("\nwaiting 15s for routes to populate") + # sleep(15) + + # Make sure that all daemons are running + for i in range(1, 2): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + + # For debugging after starting Quagga/FRR daemons, uncomment the next line + # CLI(net) + +def test_bgp_routingTable(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + print("\n\n** Verifying BGP Routing Tables") + print("******************************************\n") + diffresult = {} + for i in range(1, 2): + for view in range(1, 4): + success = 0 + # This glob pattern should work as long as number of views < 10 + for refTableFile in (glob.glob( + '%s/r%s/show_ip_bgp_view_%s*.ref' % (thisDir, i, view))): + + if os.path.isfile(refTableFile): + # Read expected result from file + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1) + + # Actual output from router + actual = net['r%s' % i].cmd('vtysh -c "show ip bgp view %s" 2> /dev/null' % view).rstrip() + + # Fix inconsitent spaces between 0.99.24 and newer versions of Quagga... + actual = re.sub('0 0', '0 0', actual) + actual = re.sub(r'([0-9]) 32768', r'\1 32768', actual) + # Remove summary line (changed recently) + actual = re.sub(r'Total number.*', '', actual) + actual = re.sub(r'Displayed.*', '', actual) + actual = actual.rstrip() + # Fix table version (ignore it) + actual = re.sub(r'(BGP table version is )[0-9]+', r'\1XXX', actual) + + # Fix newlines (make them all the same) + actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1) + + # Generate Diff + diff = topotest.get_textdiff(actual, expected, + title1="actual BGP routing table", + title2="expected BGP routing table") + + if diff: + diffresult[refTableFile] = diff + else: + success = 1 + print("template %s matched: r%s ok" % (refTableFile, i)) + break; + + if not success: + resultstr = 'No template matched.\n' + for f in diffresult.iterkeys(): + resultstr += ( + 'template %s: r%s failed Routing Table Check for view %s:\n%s\n' + % (f, i, view, diffresult[f])) + raise AssertionError( + "Routing Table verification failed for router r%s, view %s:\n%s" % (i, view, resultstr)) + + + # Make sure that all daemons are running + for i in range(1, 2): + fatal_error = net['r%s' % i].checkRouterRunning() + assert fatal_error == "", fatal_error + + # For debugging after starting FRR/Quagga daemons, uncomment the next line + # CLI(net) + + +def test_shutdown_check_stderr(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + if os.environ.get('TOPOTESTS_CHECK_STDERR') is None: + print("SKIPPED final check on StdErr output: Disabled (TOPOTESTS_CHECK_STDERR undefined)\n") + pytest.skip('Skipping test for Stderr output') + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + print("\n\n** Verifying unexpected STDERR output from daemons") + print("******************************************\n") + + net['r1'].stopRouter() + + log = net['r1'].getStdErr('bgpd') + if log: + print("\nBGPd StdErr Log:\n" + log) + log = net['r1'].getStdErr('zebra') + if log: + print("\nZebra StdErr Log:\n" + log) + + +def test_shutdown_check_memleak(): + global fatal_error + global net + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + if os.environ.get('TOPOTESTS_CHECK_MEMLEAK') is None: + print("SKIPPED final check on Memory leaks: Disabled (TOPOTESTS_CHECK_MEMLEAK undefined)\n") + pytest.skip('Skipping test for memory leaks') + + thisDir = os.path.dirname(os.path.realpath(__file__)) + + net['r1'].stopRouter() + net['r1'].report_memory_leaks(os.environ.get('TOPOTESTS_CHECK_MEMLEAK'), os.path.basename(__file__)) + + +if __name__ == '__main__': + + setLogLevel('info') + # To suppress tracebacks, either use the following pytest call or add "--tb=no" to cli + # retval = pytest.main(["-s", "--tb=no"]) + retval = pytest.main(["-s"]) + sys.exit(retval) diff --git a/tests/topotests/bgp_rfapi_basic_sanity/__init__.py b/tests/topotests/bgp_rfapi_basic_sanity/__init__.py new file mode 100755 index 0000000000..e69de29bb2 diff --git a/tests/topotests/bgp_rfapi_basic_sanity/customize.py b/tests/topotests/bgp_rfapi_basic_sanity/customize.py new file mode 100644 index 0000000000..a125c6582f --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity/customize.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python + +# +# Part of NetDEF Topology Tests +# +# Copyright (c) 2017-2018 by +# Network Device Education Foundation, Inc. ("NetDEF") +# Modified by LabN Consulting, L.L.C. +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +customize.py: Simple FRR/Quagga MPLS L3VPN test topology + + +---------+ + | r1 | + | 1.1.1.1 | PE Router + +----+----+ + | .1 r1-eth0 + | + ~~~~~~~~~~~~~ + ~~ sw0 ~~ + ~~ 10.0.1.0/24 ~~ + ~~~~~~~~~~~~~ + |10.0.1.0/24 + | + | .2 r2-eth0 + +----+----+ + | r2 | + | 2.2.2.2 | P router + +--+---+--+ + r2-eth2 .2 | | .2 r2-eth1 + ______/ \______ + / \ + ~~~~~~~~~~~~~ ~~~~~~~~~~~~~ +~~ sw2 ~~ ~~ sw1 ~~ +~~ 10.0.3.0/24 ~~ ~~ 10.0.2.0/24 ~~ + ~~~~~~~~~~~~~ ~~~~~~~~~~~~~ + | / | + \ _________/ | + \ / \ +r3-eth1 .3 | | .3 r3-eth0 | .4 r4-eth0 + +----+--+---+ +----+----+ + | r3 | | r4 | + | 3.3.3.3 | | 4.4.4.4 | PE Routers + +-----------+ +---------+ + +""" + +import os +import re +import pytest + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger +from lib.ltemplate import ltemplateRtrCmd + +# Required to instantiate the topology builder class. +from mininet.topo import Topo + +import shutil +CWD = os.path.dirname(os.path.realpath(__file__)) +# test name based on directory +TEST = os.path.basename(CWD) + +class ThisTestTopo(Topo): + "Test topology builder" + def build(self, *_args, **_opts): + "Build function" + tgen = get_topogen(self) + + # This function only purpose is to define allocation and relationship + # between routers, switches and hosts. + # + # Create P/PE routers + tgen.add_router('r1') + for routern in range(2, 5): + tgen.add_router('r{}'.format(routern)) + # Create a switch with just one router connected to it to simulate a + # empty network. + switch = {} + switch[0] = tgen.add_switch('sw0') + switch[0].add_link(tgen.gears['r1'], nodeif='r1-eth0') + switch[0].add_link(tgen.gears['r2'], nodeif='r2-eth0') + + switch[1] = tgen.add_switch('sw1') + switch[1].add_link(tgen.gears['r2'], nodeif='r2-eth1') + switch[1].add_link(tgen.gears['r3'], nodeif='r3-eth0') + switch[1].add_link(tgen.gears['r4'], nodeif='r4-eth0') + + switch[2] = tgen.add_switch('sw2') + switch[2].add_link(tgen.gears['r2'], nodeif='r2-eth2') + switch[2].add_link(tgen.gears['r3'], nodeif='r3-eth1') + +def ltemplatePreRouterStartHook(): + cc = ltemplateRtrCmd() + tgen = get_topogen() + logger.info('pre router-start hook') + #check for normal init + if len(tgen.net) == 1: + logger.info('Topology not configured, skipping setup') + return False + return True + +def ltemplatePostRouterStartHook(): + logger.info('post router-start hook') + return True + diff --git a/tests/topotests/bgp_rfapi_basic_sanity/r1/bgpd.conf b/tests/topotests/bgp_rfapi_basic_sanity/r1/bgpd.conf new file mode 100644 index 0000000000..fc301e13d7 --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity/r1/bgpd.conf @@ -0,0 +1,49 @@ +frr defaults traditional +! +hostname r1 +password zebra +log stdout notifications +log monitor notifications +log commands +router bgp 5226 + bgp router-id 1.1.1.1 + bgp cluster-id 1.1.1.1 + neighbor 2.2.2.2 remote-as 5226 + neighbor 2.2.2.2 update-source 1.1.1.1 +! + address-family ipv4 unicast + redistribute vnc-direct + no neighbor 2.2.2.2 activate + exit-address-family +! + address-family ipv4 vpn + neighbor 2.2.2.2 activate + exit-address-family +! + rfp holddown-factor 100 +! + vnc defaults + rd auto:vn:123 + response-lifetime 45 + rt both 1000:1 1000:2 + exit-vnc +! + vnc nve-group red + prefix vn 10.0.0.0/8 + rd auto:vn:10 + rt both 1000:10 + exit-vnc +! + vnc nve-group blue + prefix vn 20.0.0.0/8 + rd auto:vn:20 + rt both 1000:20 + exit-vnc +! + vnc nve-group green + prefix vn 30.0.0.0/8 + rd auto:vn:20 + rt both 1000:30 + exit-vnc +! +end diff --git a/tests/topotests/bgp_rfapi_basic_sanity/r1/ospfd.conf b/tests/topotests/bgp_rfapi_basic_sanity/r1/ospfd.conf new file mode 100644 index 0000000000..c5097e214f --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity/r1/ospfd.conf @@ -0,0 +1,8 @@ +hostname r1 +log file ospfd.log +! +router ospf + router-id 1.1.1.1 + network 0.0.0.0/4 area 0 + redistribute static +! diff --git a/tests/topotests/bgp_rfapi_basic_sanity/r1/zebra.conf b/tests/topotests/bgp_rfapi_basic_sanity/r1/zebra.conf new file mode 100644 index 0000000000..18f61e0c54 --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity/r1/zebra.conf @@ -0,0 +1,24 @@ +log file zebra.log +! +hostname r1 +! +interface lo + ip address 1.1.1.1/32 +! +interface r1-eth0 + description to sw0 + ip address 10.0.1.1/24 + no link-detect +! +interface r1-eth4 + description to ce1 + ip address 192.168.1.1/24 + no link-detect +! +ip route 99.0.0.1/32 192.168.1.2 +! +ip forwarding +! +! +line vty +! diff --git a/tests/topotests/bgp_rfapi_basic_sanity/r2/bgpd.conf b/tests/topotests/bgp_rfapi_basic_sanity/r2/bgpd.conf new file mode 100644 index 0000000000..241c2ac0ae --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity/r2/bgpd.conf @@ -0,0 +1,33 @@ +frr defaults traditional +! +hostname r2 +password zebra +log stdout notifications +log monitor notifications +log commands +router bgp 5226 + bgp router-id 2.2.2.2 + bgp cluster-id 2.2.2.2 + neighbor 1.1.1.1 remote-as 5226 + neighbor 1.1.1.1 update-source 2.2.2.2 + neighbor 3.3.3.3 remote-as 5226 + neighbor 3.3.3.3 update-source 2.2.2.2 + neighbor 4.4.4.4 remote-as 5226 + neighbor 4.4.4.4 update-source 2.2.2.2 + address-family ipv4 unicast + no neighbor 1.1.1.1 activate + no neighbor 3.3.3.3 activate + no neighbor 4.4.4.4 activate + exit-address-family + address-family ipv4 vpn + neighbor 1.1.1.1 activate + neighbor 1.1.1.1 route-reflector-client + neighbor 3.3.3.3 activate + neighbor 3.3.3.3 route-reflector-client + neighbor 4.4.4.4 activate + neighbor 4.4.4.4 route-reflector-client + exit-address-family +end + + + diff --git a/tests/topotests/bgp_rfapi_basic_sanity/r2/ospfd.conf b/tests/topotests/bgp_rfapi_basic_sanity/r2/ospfd.conf new file mode 100644 index 0000000000..8678813665 --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity/r2/ospfd.conf @@ -0,0 +1,7 @@ +hostname r2 +log file ospfd.log +! +router ospf + router-id 2.2.2.2 + network 0.0.0.0/0 area 0 +! diff --git a/tests/topotests/bgp_rfapi_basic_sanity/r2/zebra.conf b/tests/topotests/bgp_rfapi_basic_sanity/r2/zebra.conf new file mode 100644 index 0000000000..dd1dbac32b --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity/r2/zebra.conf @@ -0,0 +1,27 @@ +log file zebra.log +! +hostname r2 +! +interface lo + ip address 2.2.2.2/32 +! +interface r2-eth0 + description to sw0 + ip address 10.0.1.2/24 + no link-detect +! +interface r2-eth1 + description to sw1 + ip address 10.0.2.2/24 + no link-detect +! +interface r2-eth2 + description to sw2 + ip address 10.0.3.2/24 + no link-detect +! +ip forwarding +! +! +line vty +! diff --git a/tests/topotests/bgp_rfapi_basic_sanity/r3/bgpd.conf b/tests/topotests/bgp_rfapi_basic_sanity/r3/bgpd.conf new file mode 100644 index 0000000000..0066f65a40 --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity/r3/bgpd.conf @@ -0,0 +1,50 @@ +frr defaults traditional +! +hostname r3 +password zebra +log stdout notifications +log monitor notifications +log commands +router bgp 5226 + bgp router-id 3.3.3.3 + bgp cluster-id 3.3.3.3 + neighbor 2.2.2.2 remote-as 5226 + neighbor 2.2.2.2 update-source 3.3.3.3 +! + address-family ipv4 unicast + no neighbor 2.2.2.2 activate + exit-address-family + address-family ipv4 vpn + neighbor 2.2.2.2 activate + exit-address-family +! + rfp holddown-factor 100 +! + vnc defaults + rd auto:vn:123 + response-lifetime 45 + rt both 1000:1 1000:2 + exit-vnc +! + vnc nve-group red + prefix vn 10.0.0.0/8 + rd auto:vn:10 + rt both 1000:10 + exit-vnc +! + vnc nve-group blue + prefix vn 20.0.0.0/8 + rd auto:vn:20 + rt both 1000:20 + exit-vnc +! + vnc nve-group green + prefix vn 30.0.0.0/8 + rd auto:vn:20 + rt both 1000:30 + exit-vnc +! +end + + + diff --git a/tests/topotests/bgp_rfapi_basic_sanity/r3/ospfd.conf b/tests/topotests/bgp_rfapi_basic_sanity/r3/ospfd.conf new file mode 100644 index 0000000000..c7c358f9dc --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity/r3/ospfd.conf @@ -0,0 +1,9 @@ +hostname r3 +password 1 +log file ospfd.log +! +router ospf + router-id 3.3.3.3 + network 0.0.0.0/4 area 0 + redistribute static +! diff --git a/tests/topotests/bgp_rfapi_basic_sanity/r3/zebra.conf b/tests/topotests/bgp_rfapi_basic_sanity/r3/zebra.conf new file mode 100644 index 0000000000..9dbc290243 --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity/r3/zebra.conf @@ -0,0 +1,29 @@ +log file zebra.log +! +hostname r3 +! +interface lo + ip address 3.3.3.3/32 +! +interface r3-eth0 + description to sw1 + ip address 10.0.2.3/24 + no link-detect +! +interface r3-eth1 + description to sw2 + ip address 10.0.3.3/24 + no link-detect +! +interface r3-eth4 + description to ce2 + ip address 192.168.1.1/24 + no link-detect +! +ip route 99.0.0.2/32 192.168.1.2 +! +ip forwarding +! +! +line vty +! diff --git a/tests/topotests/bgp_rfapi_basic_sanity/r4/bgpd.conf b/tests/topotests/bgp_rfapi_basic_sanity/r4/bgpd.conf new file mode 100644 index 0000000000..67c06506b5 --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity/r4/bgpd.conf @@ -0,0 +1,51 @@ +frr defaults traditional +! +hostname r4 +password zebra +log stdout notifications +log monitor notifications +log commands +router bgp 5226 + bgp router-id 4.4.4.4 + bgp cluster-id 4.4.4.4 + neighbor 2.2.2.2 remote-as 5226 + neighbor 2.2.2.2 update-source 4.4.4.4 +! + address-family ipv4 unicast + no neighbor 2.2.2.2 activate + exit-address-family +! + address-family ipv4 vpn + neighbor 2.2.2.2 activate + exit-address-family +! + rfp holddown-factor 100 +! + vnc defaults + rd auto:vn:123 + response-lifetime 45 + rt both 1000:1 1000:2 + exit-vnc +! + vnc nve-group red + prefix vn 10.0.0.0/8 + rd auto:vn:10 + rt both 1000:10 + exit-vnc +! + vnc nve-group blue + prefix vn 20.0.0.0/8 + rd auto:vn:20 + rt both 1000:20 + exit-vnc +! + vnc nve-group green + prefix vn 30.0.0.0/8 + rd auto:vn:20 + rt both 1000:30 + exit-vnc +! +end + + + diff --git a/tests/topotests/bgp_rfapi_basic_sanity/r4/ospfd.conf b/tests/topotests/bgp_rfapi_basic_sanity/r4/ospfd.conf new file mode 100644 index 0000000000..83d09c09a4 --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity/r4/ospfd.conf @@ -0,0 +1,8 @@ +hostname r4 +log file ospfd.log +! +router ospf + router-id 4.4.4.4 + network 0.0.0.0/4 area 0 + redistribute static +! diff --git a/tests/topotests/bgp_rfapi_basic_sanity/r4/zebra.conf b/tests/topotests/bgp_rfapi_basic_sanity/r4/zebra.conf new file mode 100644 index 0000000000..415f03df51 --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity/r4/zebra.conf @@ -0,0 +1,23 @@ +log file zebra.log +! +hostname r4 +! +interface lo + ip address 4.4.4.4/32 +! +interface r4-eth0 + description to sw1 + ip address 10.0.2.4/24 + no link-detect +! +interface r4-eth4 + description to ce3 + ip address 192.168.1.1/24 + no link-detect +! +ip route 99.0.0.3/32 192.168.1.2 +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/bgp_rfapi_basic_sanity/scripts/add_routes.py b/tests/topotests/bgp_rfapi_basic_sanity/scripts/add_routes.py new file mode 100644 index 0000000000..4d6a7582ba --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity/scripts/add_routes.py @@ -0,0 +1,36 @@ +from lutil import luCommand +holddownFactorSet = luCommand('r1','vtysh -c "show running"','rfp holddown-factor','none','Holddown factor set') +if not holddownFactorSet: + to = "-1" + cost = "" +else: + to = "6" + cost = "cost 50" +luCommand('r1','vtysh -c "debug rfapi-dev open vn 10.0.0.1 un 1.1.1.1"','rfapi_set_response_cb: status 0', 'pass', 'Opened RFAPI') +luCommand('r1','vtysh -c "debug rfapi-dev query vn 10.0.0.1 un 1.1.1.1 target 11.11.11.11"','rc=2', 'pass', 'Clean query') +luCommand('r1','vtysh -c "debug rfapi-dev register vn 10.0.0.1 un 1.1.1.1 prefix 11.11.11.0/24 lifetime {}"'.format(to),'', 'none', 'Prefix registered') +luCommand('r1','vtysh -c "show vnc registrations local"','1 out of 1','wait','Local registration') +luCommand('r1','vtysh -c "debug rfapi-dev response-omit-self off"','.','none') +luCommand('r1','vtysh -c "debug rfapi-dev query vn 10.0.0.1 un 1.1.1.1 target 11.11.11.11"','11.11.11.0/24', 'pass', 'Query self') + +luCommand('r3','vtysh -c "debug rfapi-dev open vn 10.0.0.2 un 2.2.2.2"','rfapi_set_response_cb: status 0', 'pass', 'Opened RFAPI') +luCommand('r3','vtysh -c "debug rfapi-dev register vn 10.0.0.2 un 2.2.2.2 prefix 22.22.22.0/24 lifetime {}"'.format(to),'', 'none', 'Prefix registered') +luCommand('r3','vtysh -c "show vnc registrations local"','1 out of 1','wait','Local registration') +luCommand('r3','vtysh -c "debug rfapi-dev response-omit-self on"','.','none') +luCommand('r3','vtysh -c "debug rfapi-dev query vn 10.0.0.2 un 2.2.2.2 target 22.22.22.22"','rc=2', 'pass', 'Self excluded') +luCommand('r3','vtysh -c "debug rfapi-dev open vn 10.0.1.2 un 2.1.1.2"','rfapi_set_response_cb: status 0', 'pass', 'Opened query only RFAPI') +luCommand('r3','vtysh -c "debug rfapi-dev query vn 10.0.1.2 un 2.1.1.2 target 22.22.22.22"','22.22.22.0/24', 'pass', 'See local') + +luCommand('r4','vtysh -c "debug rfapi-dev open vn 10.0.0.3 un 3.3.3.3"','rfapi_set_response_cb: status 0', 'pass', 'Opened RFAPI') +luCommand('r4','vtysh -c "debug rfapi-dev register vn 10.0.0.3 un 3.3.3.3 prefix 33.33.33.0/24 lifetime {}"'.format(to),'', 'none', 'Prefix registered') +luCommand('r4','vtysh -c "show vnc registrations local"','1 out of 1','wait','Local registration') +luCommand('r4','vtysh -c "debug rfapi-dev response-omit-self off"','.','none') +luCommand('r4','vtysh -c "debug rfapi-dev query vn 10.0.0.3 un 3.3.3.3 target 33.33.33.33"','33.33.33.0/24', 'pass', 'Query self') + +luCommand('r4','vtysh -c "debug rfapi-dev register vn 10.0.0.3 un 3.3.3.3 prefix 11.11.11.0/24 lifetime {} {}"'.format(to, cost),'', 'none', 'MP Prefix registered') +luCommand('r4','vtysh -c "show vnc registrations local"','2 out of 2','wait','Local registration') +luCommand('r4','vtysh -c "debug rfapi-dev query vn 10.0.0.3 un 3.3.3.3 target 11.11.11.11"','11.11.11.0/24', 'pass', 'Query self MP') + +luCommand('r1','vtysh -c "show vnc registrations"','.','none') +luCommand('r3','vtysh -c "show vnc registrations"','.','none') +luCommand('r4','vtysh -c "show vnc registrations"','.','none') diff --git a/tests/topotests/bgp_rfapi_basic_sanity/scripts/adjacencies.py b/tests/topotests/bgp_rfapi_basic_sanity/scripts/adjacencies.py new file mode 100644 index 0000000000..1f53791f6a --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity/scripts/adjacencies.py @@ -0,0 +1,10 @@ +luCommand('r1','ping 2.2.2.2 -c 1',' 0. packet loss','wait','PE->P2 (loopback) ping',60) +luCommand('r3','ping 2.2.2.2 -c 1',' 0. packet loss','wait','PE->P2 (loopback) ping',60) +luCommand('r4','ping 2.2.2.2 -c 1',' 0. packet loss','wait','PE->P2 (loopback) ping',60) +luCommand('r2','vtysh -c "show bgp summary"',' 00:0.* 00:0.* 00:0','wait','Core adjacencies up',30) +luCommand('r1','vtysh -c "show bgp vrf all summary"',' 00:0','pass','All adjacencies up') +luCommand('r3','vtysh -c "show bgp vrf all summary"',' 00:0','pass','All adjacencies up') +luCommand('r4','vtysh -c "show bgp vrf all summary"',' 00:0','pass','All adjacencies up') +luCommand('r1','ping 3.3.3.3 -c 1',' 0. packet loss','wait','PE->PE3 (loopback) ping') +luCommand('r1','ping 4.4.4.4 -c 1',' 0. packet loss','wait','PE->PE4 (loopback) ping') +#luCommand('r4','ping 3.3.3.3 -c 1',' 0. packet loss','wait','PE->PE3 (loopback) ping') diff --git a/tests/topotests/bgp_rfapi_basic_sanity/scripts/check_close.py b/tests/topotests/bgp_rfapi_basic_sanity/scripts/check_close.py new file mode 100644 index 0000000000..5fffce7ca0 --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity/scripts/check_close.py @@ -0,0 +1,19 @@ +from lutil import luCommand +holddownFactorSet = luCommand('r1','vtysh -c "show running"','rfp holddown-factor','none','Holddown factor set') +if not holddownFactorSet: + to = "-1" +else: + to = "1" +luCommand('r1','vtysh -c "debug rfapi-dev open vn 20.0.0.1 un 1.1.1.21"','rfapi_set_response_cb: status 0', 'pass', 'Opened RFAPI') +luCommand('r1','vtysh -c "debug rfapi-dev register vn 20.0.0.1 un 1.1.1.21 prefix 111.111.111.0/24 lifetime {}"'.format(to),'', 'none', 'Prefix registered') +luCommand('r1','vtysh -c "show vnc registrations local"','111.111.111.0/24','wait','Local registration',1) +luCommand('r1','vtysh -c "show vnc registrations"','.','none') +luCommand('r3','vtysh -c "show vnc registrations"','111.111.111.0/24','wait','See registration') +luCommand('r4','vtysh -c "show vnc registrations"','111.111.111.0/24','wait','See registration') +luCommand('r1','vtysh -c "debug rfapi-dev close vn 20.0.0.1 un 1.1.1.21"','status 0', 'pass', 'Closed RFAPI') +luCommand('r1','vtysh -c "show vnc registrations"','Locally: *Active: 1 .* Remotely: *Active: 3','wait','See cleanup') +luCommand('r3','vtysh -c "show vnc registrations"','Locally: *Active: 1 .* Remotely: *Active: 3','wait','See cleanup') +luCommand('r4','vtysh -c "show vnc registrations"','Locally: *Active: 2 .* Remotely: *Active: 2','wait','See cleanup') +luCommand('r1','vtysh -c "show vnc registrations"','In Holddown: *Active: 0','wait','Out of holddown',20) +luCommand('r3','vtysh -c "show vnc registrations"','In Holddown: *Active: 0','wait','Out of holddown') +luCommand('r4','vtysh -c "show vnc registrations"','In Holddown: *Active: 0','wait','Out of holddown') diff --git a/tests/topotests/bgp_rfapi_basic_sanity/scripts/check_routes.py b/tests/topotests/bgp_rfapi_basic_sanity/scripts/check_routes.py new file mode 100644 index 0000000000..a380c79fcf --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity/scripts/check_routes.py @@ -0,0 +1,19 @@ +from lutil import luCommand +luCommand('r1','vtysh -c "show bgp ipv4 vpn"','','none','VPN SAFI') +luCommand('r2','vtysh -c "show bgp ipv4 vpn"','','none','VPN SAFI') +luCommand('r3','vtysh -c "show bgp ipv4 vpn"','','none','VPN SAFI') +luCommand('r4','vtysh -c "show bgp ipv4 vpn"','','none','VPN SAFI') +luCommand('r1','vtysh -c "show vnc registrations"','Locally: *Active: 1 .* Remotely: *Active: 3','wait','See all registrations') +luCommand('r3','vtysh -c "show vnc registrations"','Locally: *Active: 1 .* Remotely: *Active: 3','wait','See all registrations') +luCommand('r4','vtysh -c "show vnc registrations"','Locally: *Active: 2 .* Remotely: *Active: 2','wait','See all registrations') +num = '4 routes and 4' +luCommand('r1','vtysh -c "show bgp ipv4 vpn"',num,'pass','VPN SAFI okay') +luCommand('r2','vtysh -c "show bgp ipv4 vpn"',num,'pass','VPN SAFI okay') +luCommand('r3','vtysh -c "show bgp ipv4 vpn"',num,'pass','VPN SAFI okay') +luCommand('r4','vtysh -c "show bgp ipv4 vpn"',num,'pass','VPN SAFI okay') +luCommand('r1','vtysh -c "debug rfapi-dev query vn 10.0.0.1 un 1.1.1.1 target 22.22.22.22"','pfx=', 'pass', 'Query R2s info') +luCommand('r1','vtysh -c "debug rfapi-dev query vn 10.0.0.1 un 1.1.1.1 target 33.33.33.33"','pfx=', 'pass', 'Query R4s info') +luCommand('r3','vtysh -c "debug rfapi-dev query vn 10.0.0.2 un 2.2.2.2 target 11.11.11.11"','11.11.11.0/24.*11.11.11.0/24.*', 'pass', 'Query R1s+R4s info') +luCommand('r3','vtysh -c "debug rfapi-dev query vn 10.0.0.2 un 2.2.2.2 target 33.33.33.33"','pfx=', 'pass', 'Query R4s info') +luCommand('r4','vtysh -c "debug rfapi-dev query vn 10.0.0.3 un 3.3.3.3 target 11.11.11.11"','11.11.11.0/24.*11.11.11.0/24.*', 'pass', 'Query R1s+R4s info') +luCommand('r4','vtysh -c "debug rfapi-dev query vn 10.0.0.3 un 3.3.3.3 target 22.22.22.22"','pfx=', 'pass', 'Query R2s info') diff --git a/tests/topotests/bgp_rfapi_basic_sanity/scripts/check_timeout.py b/tests/topotests/bgp_rfapi_basic_sanity/scripts/check_timeout.py new file mode 100644 index 0000000000..f4467ecc33 --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity/scripts/check_timeout.py @@ -0,0 +1,68 @@ +from lutil import luCommand +holddownFactorSet = luCommand('r1','vtysh -c "show running"','rfp holddown-factor','none','Holddown factor set') +luCommand('r1','vtysh -c "show vnc registrations"','.','none') +luCommand('r3','vtysh -c "show vnc registrations"','.','none') +luCommand('r4','vtysh -c "show vnc registrations"','.','none') +if not holddownFactorSet: + luCommand('r1','vtysh -c "show vnc summary"','.','pass','Holddown factor not set -- skipping test') +else: + #holddown time test + luCommand('r1','vtysh -c "debug rfapi-dev register vn 10.0.0.1 un 1.1.1.1 prefix 1.111.0.0/16 lifetime 10"','', 'none', 'Prefix registered') + luCommand('r1','vtysh -c "show vnc registrations local"','1.111.0.0/16','wait','Local registration') + + luCommand('r3','vtysh -c "debug rfapi-dev register vn 10.0.0.2 un 2.2.2.2 prefix 1.222.0.0/16 lifetime 10"','', 'none', 'Prefix registered') + luCommand('r3','vtysh -c "show vnc registrations local"','1.222.0.0/16','wait','Local registration') + + luCommand('r4','vtysh -c "show vnc registrations"','Remotely: *Active: 4 ','wait', 'See registrations, L=10') + + luCommand('r4','vtysh -c "debug rfapi-dev register vn 10.0.0.3 un 3.3.3.3 prefix 1.222.0.0/16 lifetime 5 cost 50"','', 'none', 'MP Prefix registered') + luCommand('r4','vtysh -c "show vnc registrations local"','1.222.0.0/16','wait','Local registration (MP prefix)') + + luCommand('r1','vtysh -c "show vnc registrations"','.','none') + luCommand('r3','vtysh -c "show vnc registrations"','.','none') + + luCommand('r4','vtysh -c "debug rfapi-dev query vn 10.0.0.3 un 3.3.3.3 target 1.111.111.111"','pfx=', 'pass', 'Query R1s info') + luCommand('r4','vtysh -c "debug rfapi-dev query vn 10.0.0.3 un 3.3.3.3 target 1.222.222.222"','1.222.0.0/16.*1.222.0.0/16', 'pass', 'Query R3s+R4s info') + + luCommand('r4','vtysh -c "debug rfapi-dev unregister vn 10.0.0.3 un 3.3.3.3 prefix 1.222.0.0/16"','', 'none', 'MP Prefix removed') + luCommand('r4','vtysh -c "show vnc registrations"','In Holddown: *Active: 1 ','wait', 'MP prefix in holddown') + luCommand('r1','vtysh -c "show vnc registrations"','In Holddown: *Active: 1 ','wait', 'MP prefix in holddown') + luCommand('r3','vtysh -c "show vnc registrations"','In Holddown: *Active: 1 ','wait', 'MP prefix in holddown') + luCommand('r1','vtysh -c "debug rfapi-dev query vn 10.0.0.1 un 1.1.1.1 target 1.222.222.222"','1.222.0.0/16', 'pass', 'Query R3s info') + luCommand('r1','vtysh -c "debug rfapi-dev unregister vn 10.0.0.1 un 1.1.1.1 prefix 1.111.0.0/16"','', 'none', 'Prefix timeout') + luCommand('r1','vtysh -c "show vnc registrations holddown"','1.111.0.0/16','wait','Local holddown',1) + luCommand('r3','vtysh -c "debug rfapi-dev unregister vn 10.0.0.2 un 2.2.2.2 prefix 1.222.0.0/16"','', 'none', 'Prefix timeout') + luCommand('r3','vtysh -c "show vnc registrations holddown"','1.222.0.0/16','wait','Local holddown',1) + luCommand('r4','vtysh -c "show vnc registrations"','.','none') + luCommand('r4','vtysh -c "show vnc registrations"','.','none') + + luCommand('r4','vtysh -c "show vnc registrations"','In Holddown: *Active: 2 ','wait', 'In holddown') + luCommand('r1','vtysh -c "show vnc registrations"','In Holddown: *Active: 2 ','wait', 'In holddown') + luCommand('r3','vtysh -c "show vnc registrations"','In Holddown: *Active: 2 ','wait', 'In holddown') + + luCommand('r1','vtysh -c "show vnc registrations"','In Holddown: *Active: 0','wait','Out of holddown',20) + luCommand('r3','vtysh -c "show vnc registrations"','In Holddown: *Active: 0','wait','Out of holddown') + luCommand('r4','vtysh -c "show vnc registrations"','In Holddown: *Active: 0','wait','Out of holddown') + + #kill test + luCommand('r1','vtysh -c "debug rfapi-dev register vn 10.0.0.1 un 1.1.1.1 prefix 1.111.0.0/16 lifetime 10"','', 'none', 'Prefix registered') + luCommand('r1','vtysh -c "show vnc registrations local"','1.111.0.0/16','wait','Local registration') + + luCommand('r3','vtysh -c "debug rfapi-dev register vn 10.0.0.2 un 2.2.2.2 prefix 1.222.0.0/16 lifetime 10"','', 'none', 'Prefix registered') + luCommand('r3','vtysh -c "show vnc registrations local"','1.222.0.0/16','wait','Local registration') + + luCommand('r4','vtysh -c "show vnc registrations"','Remotely: *Active: 4 ','wait', 'See registrations L=10 (pre-kill)',5) + luCommand('r1','vtysh -c "show vnc registrations"','.','none') + luCommand('r3','vtysh -c "show vnc registrations"','.','none') + luCommand('r1','vtysh -c "debug rfapi-dev unregister vn 10.0.0.1 un 1.1.1.1 prefix 1.111.0.0/16 kill"','', 'none', 'Prefix kill') + luCommand('r1','vtysh -c "show vnc registrations"','Locally: *Active: 1 .* Remotely: *Active: 4 .*In Holddown: *Active: 0','wait','Registration killed',1) + luCommand('r3','vtysh -c "show vnc registrations"','Locally: *Active: 2 .* Remotely: *Active: 3 .*In Holddown: *Active: 1','wait','Remote in holddown',5) + luCommand('r4','vtysh -c "show vnc registrations"','Locally: *Active: 2 .* Remotely: *Active: 3 .*In Holddown: *Active: 1','wait','Remote in holddown',5) + + luCommand('r3','vtysh -c "debug rfapi-dev unregister vn 10.0.0.2 un 2.2.2.2 prefix 1.222.0.0/16 kill"','', 'none', 'Prefix kill') + luCommand('r3','vtysh -c "show vnc registrations"','Locally: *Active: 1 .* Remotely: *Active: 3 .*In Holddown: *Active: 1','wait','Registration killed',1) + luCommand('r4','vtysh -c "show vnc registrations"','Locally: *Active: 2 .* Remotely: *Active: 2 .*In Holddown: *Active: 2','wait','Remote in holddown',5) + + luCommand('r1','vtysh -c "show vnc registrations"','Locally: *Active: 1 .* Remotely: *Active: 3 .*In Holddown: *Active: 0','wait','Out of holddown',20) + luCommand('r3','vtysh -c "show vnc registrations"','Locally: *Active: 1 .* Remotely: *Active: 3 .*In Holddown: *Active: 0','wait','Out of holddown') + luCommand('r4','vtysh -c "show vnc registrations"','Locally: *Active: 2 .* Remotely: *Active: 2 .*In Holddown: *Active: 0','wait','Out of holddown') diff --git a/tests/topotests/bgp_rfapi_basic_sanity/scripts/cleanup_all.py b/tests/topotests/bgp_rfapi_basic_sanity/scripts/cleanup_all.py new file mode 100644 index 0000000000..096e97fa94 --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity/scripts/cleanup_all.py @@ -0,0 +1,32 @@ +from lutil import luCommand +luCommand('r1','vtysh -c "debug rfapi-dev unregister vn 10.0.0.1 un 1.1.1.1 prefix 11.11.11.0/24"','', 'none', 'Prefix removed') +luCommand('r1','vtysh -c "show vnc registrations"','Locally: *Active: 0 ','wait','Local registration removed') +luCommand('r1','vtysh -c "debug rfapi-dev close vn 10.0.0.1 un 1.1.1.1"','status 0', 'pass', 'Closed RFAPI') + +luCommand('r3','vtysh -c "debug rfapi-dev unregister vn 10.0.0.2 un 2.2.2.2 prefix 22.22.22.0/24"','', 'none', 'Prefix removed') +luCommand('r3','vtysh -c "show vnc registrations"','Locally: *Active: 0 ','wait','Local registration removed') +luCommand('r3','vtysh -c "debug rfapi-dev close vn 10.0.0.2 un 2.2.2.2"','status 0', 'pass', 'Closed RFAPI') + +luCommand('r4','vtysh -c "debug rfapi-dev unregister vn 10.0.0.3 un 3.3.3.3 prefix 33.33.33.0/24"','', 'none', 'Prefix removed') +luCommand('r4','vtysh -c "debug rfapi-dev unregister vn 10.0.0.3 un 3.3.3.3 prefix 11.11.11.0/24"','', 'none', 'MP prefix removed') +luCommand('r4','vtysh -c "show vnc registrations"','Locally: *Active: 0 ','wait','Local registration removed') +luCommand('r4','vtysh -c "debug rfapi-dev close vn 10.0.0.3 un 3.3.3.3"','status 0', 'pass', 'Closed RFAPI') + +luCommand('r1','vtysh -c "show vnc registrations"','Locally: *Active: 0 .* Remotely: *Active: 0','wait','All registrations cleared') +luCommand('r3','vtysh -c "show vnc registrations"','Locally: *Active: 0 .* Remotely: *Active: 0','wait','All registrations cleared') +luCommand('r4','vtysh -c "show vnc registrations"','Locally: *Active: 0 .* Remotely: *Active: 0','wait','All registrations cleared') + +num = '0 exist' +luCommand('r1','vtysh -c "show bgp ipv4 vpn"',num,'pass','VPN SAFI clear') +luCommand('r2','vtysh -c "show bgp ipv4 vpn"',num,'pass','VPN SAFI clear') +luCommand('r3','vtysh -c "show bgp ipv4 vpn"',num,'pass','VPN SAFI clear') +luCommand('r4','vtysh -c "show bgp ipv4 vpn"',num,'pass','VPN SAFI clear') + +luCommand('r1','vtysh -c "show vnc registrations"','Locally: *Active: 0 .* Remotely: *Active: 0 .*In Holddown: *Active: 0','wait','No holddowns',20) +luCommand('r3','vtysh -c "show vnc registrations"','Locally: *Active: 0 .* Remotely: *Active: 0 .*In Holddown: *Active: 0','wait','No holddowns') +luCommand('r4','vtysh -c "show vnc registrations"','Locally: *Active: 0 .* Remotely: *Active: 0 .*In Holddown: *Active: 0','wait','No holddowns') + +luCommand('r1','vtysh -c "show vnc summary"','.','none') +luCommand('r3','vtysh -c "show vnc summary"','.','none') +luCommand('r4','vtysh -c "show vnc summary"','.','none') + diff --git a/tests/topotests/bgp_rfapi_basic_sanity/test_bgp_rfapi_basic_sanity.py b/tests/topotests/bgp_rfapi_basic_sanity/test_bgp_rfapi_basic_sanity.py new file mode 100755 index 0000000000..0e1f236b7d --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity/test_bgp_rfapi_basic_sanity.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python + +# +# Part of NetDEF Topology Tests +# +# Copyright (c) 2018, LabN Consulting, L.L.C. +# Authored by Lou Berger +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +import os +import sys +import pytest + +sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..')) + +from lib.ltemplate import * + +def test_add_routes(): + CliOnFail = None + # For debugging, uncomment the next line + #CliOnFail = 'tgen.mininet_cli' + CheckFunc = 'ltemplateVersionCheck(\'3.1\')' + #uncomment next line to start cli *before* script is run + #CheckFunc = 'ltemplateVersionCheck(\'3.1\', cli=True)' + ltemplateTest('scripts/add_routes.py', False, CliOnFail, CheckFunc) + +def test_adjacencies(): + CliOnFail = None + # For debugging, uncomment the next line + #CliOnFail = 'tgen.mininet_cli' + CheckFunc = 'ltemplateVersionCheck(\'3.1\')' + #uncomment next line to start cli *before* script is run + #CheckFunc = 'ltemplateVersionCheck(\'3.1\', cli=True)' + ltemplateTest('scripts/adjacencies.py', False, CliOnFail, CheckFunc) + +def test_check_routes(): + CliOnFail = None + # For debugging, uncomment the next line + #CliOnFail = 'tgen.mininet_cli' + CheckFunc = 'ltemplateVersionCheck(\'3.1\')' + #uncomment next line to start cli *before* script is run + #CheckFunc = 'ltemplateVersionCheck(\'3.1\', cli=True)' + ltemplateTest('scripts/check_routes.py', False, CliOnFail, CheckFunc) + +def test_check_close(): + CliOnFail = None + # For debugging, uncomment the next line + #CliOnFail = 'tgen.mininet_cli' + CheckFunc = 'ltemplateVersionCheck(\'3.1\')' + #uncomment next line to start cli *before* script is run + #CheckFunc = 'ltemplateVersionCheck(\'3.1\', cli=True)' + ltemplateTest('scripts/check_close.py', False, CliOnFail, CheckFunc) + +def test_check_timeout(): + CliOnFail = None + # For debugging, uncomment the next line + #CliOnFail = 'tgen.mininet_cli' + CheckFunc = 'ltemplateVersionCheck(\'3.1\')' + #uncomment next line to start cli *before* script is run + #CheckFunc = 'ltemplateVersionCheck(\'3.1\', cli=True)' + ltemplateTest('scripts/check_timeout.py', False, CliOnFail, CheckFunc) + +def test_cleanup_all(): + CliOnFail = None + # For debugging, uncomment the next line + #CliOnFail = 'tgen.mininet_cli' + CheckFunc = 'ltemplateVersionCheck(\'3.1\')' + #uncomment next line to start cli *before* script is run + #CheckFunc = 'ltemplateVersionCheck(\'3.1\', cli=True)' + ltemplateTest('scripts/cleanup_all.py', False, CliOnFail, CheckFunc) + +if __name__ == '__main__': + retval = pytest.main(["-s"]) + sys.exit(retval) diff --git a/tests/topotests/bgp_rfapi_basic_sanity_config2/__init__.py b/tests/topotests/bgp_rfapi_basic_sanity_config2/__init__.py new file mode 100755 index 0000000000..e69de29bb2 diff --git a/tests/topotests/bgp_rfapi_basic_sanity_config2/customize.py b/tests/topotests/bgp_rfapi_basic_sanity_config2/customize.py new file mode 120000 index 0000000000..a6b653acab --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity_config2/customize.py @@ -0,0 +1 @@ +../bgp_rfapi_basic_sanity/customize.py \ No newline at end of file diff --git a/tests/topotests/bgp_rfapi_basic_sanity_config2/r1/bgpd.conf b/tests/topotests/bgp_rfapi_basic_sanity_config2/r1/bgpd.conf new file mode 100644 index 0000000000..eb8d703a35 --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity_config2/r1/bgpd.conf @@ -0,0 +1,50 @@ +frr defaults traditional +! +hostname r1 +password zebra +log stdout notifications +log monitor notifications +log commands +router bgp 5226 + bgp router-id 1.1.1.1 + bgp cluster-id 1.1.1.1 + neighbor 2.2.2.2 remote-as 5226 + neighbor 2.2.2.2 update-source 1.1.1.1 +! + address-family ipv4 unicast + redistribute vnc-direct + no neighbor 2.2.2.2 activate + exit-address-family +! + address-family ipv4 vpn + neighbor 2.2.2.2 activate + exit-address-family +! + rfp holddown-factor 100 + rfp full-table-download off +! + vnc defaults + rd auto:vn:123 + response-lifetime 45 + rt both 1000:1 1000:2 + exit-vnc +! + vnc nve-group red + prefix vn 10.0.0.0/8 + rd auto:vn:10 + rt both 1000:10 + exit-vnc +! + vnc nve-group blue + prefix vn 20.0.0.0/8 + rd auto:vn:20 + rt both 1000:20 + exit-vnc +! + vnc nve-group green + prefix vn 30.0.0.0/8 + rd auto:vn:20 + rt both 1000:30 + exit-vnc +! +end diff --git a/tests/topotests/bgp_rfapi_basic_sanity_config2/r1/ospfd.conf b/tests/topotests/bgp_rfapi_basic_sanity_config2/r1/ospfd.conf new file mode 120000 index 0000000000..d09b09eef4 --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity_config2/r1/ospfd.conf @@ -0,0 +1 @@ +../../bgp_rfapi_basic_sanity/r1/ospfd.conf \ No newline at end of file diff --git a/tests/topotests/bgp_rfapi_basic_sanity_config2/r1/zebra.conf b/tests/topotests/bgp_rfapi_basic_sanity_config2/r1/zebra.conf new file mode 120000 index 0000000000..728b1b9a3a --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity_config2/r1/zebra.conf @@ -0,0 +1 @@ +../../bgp_rfapi_basic_sanity/r1/zebra.conf \ No newline at end of file diff --git a/tests/topotests/bgp_rfapi_basic_sanity_config2/r2/bgpd.conf b/tests/topotests/bgp_rfapi_basic_sanity_config2/r2/bgpd.conf new file mode 100644 index 0000000000..241c2ac0ae --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity_config2/r2/bgpd.conf @@ -0,0 +1,33 @@ +frr defaults traditional +! +hostname r2 +password zebra +log stdout notifications +log monitor notifications +log commands +router bgp 5226 + bgp router-id 2.2.2.2 + bgp cluster-id 2.2.2.2 + neighbor 1.1.1.1 remote-as 5226 + neighbor 1.1.1.1 update-source 2.2.2.2 + neighbor 3.3.3.3 remote-as 5226 + neighbor 3.3.3.3 update-source 2.2.2.2 + neighbor 4.4.4.4 remote-as 5226 + neighbor 4.4.4.4 update-source 2.2.2.2 + address-family ipv4 unicast + no neighbor 1.1.1.1 activate + no neighbor 3.3.3.3 activate + no neighbor 4.4.4.4 activate + exit-address-family + address-family ipv4 vpn + neighbor 1.1.1.1 activate + neighbor 1.1.1.1 route-reflector-client + neighbor 3.3.3.3 activate + neighbor 3.3.3.3 route-reflector-client + neighbor 4.4.4.4 activate + neighbor 4.4.4.4 route-reflector-client + exit-address-family +end + + + diff --git a/tests/topotests/bgp_rfapi_basic_sanity_config2/r2/ospfd.conf b/tests/topotests/bgp_rfapi_basic_sanity_config2/r2/ospfd.conf new file mode 120000 index 0000000000..834554e5e7 --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity_config2/r2/ospfd.conf @@ -0,0 +1 @@ +../../bgp_rfapi_basic_sanity/r2/ospfd.conf \ No newline at end of file diff --git a/tests/topotests/bgp_rfapi_basic_sanity_config2/r2/zebra.conf b/tests/topotests/bgp_rfapi_basic_sanity_config2/r2/zebra.conf new file mode 120000 index 0000000000..2fefda556c --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity_config2/r2/zebra.conf @@ -0,0 +1 @@ +../../bgp_rfapi_basic_sanity/r2/zebra.conf \ No newline at end of file diff --git a/tests/topotests/bgp_rfapi_basic_sanity_config2/r3/bgpd.conf b/tests/topotests/bgp_rfapi_basic_sanity_config2/r3/bgpd.conf new file mode 100644 index 0000000000..61164c6948 --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity_config2/r3/bgpd.conf @@ -0,0 +1,51 @@ +frr defaults traditional +! +hostname r3 +password zebra +log stdout notifications +log monitor notifications +log commands +router bgp 5226 + bgp router-id 3.3.3.3 + bgp cluster-id 3.3.3.3 + neighbor 2.2.2.2 remote-as 5226 + neighbor 2.2.2.2 update-source 3.3.3.3 +! + address-family ipv4 unicast + no neighbor 2.2.2.2 activate + exit-address-family + address-family ipv4 vpn + neighbor 2.2.2.2 activate + exit-address-family +! + rfp holddown-factor 100 + rfp full-table-download off +! + vnc defaults + rd auto:vn:123 + response-lifetime 45 + rt both 1000:1 1000:2 + exit-vnc +! + vnc nve-group red + prefix vn 10.0.0.0/8 + rd auto:vn:10 + rt both 1000:10 + exit-vnc +! + vnc nve-group blue + prefix vn 20.0.0.0/8 + rd auto:vn:20 + rt both 1000:20 + exit-vnc +! + vnc nve-group green + prefix vn 30.0.0.0/8 + rd auto:vn:20 + rt both 1000:30 + exit-vnc +! +end + + + diff --git a/tests/topotests/bgp_rfapi_basic_sanity_config2/r3/ospfd.conf b/tests/topotests/bgp_rfapi_basic_sanity_config2/r3/ospfd.conf new file mode 120000 index 0000000000..353b9adb55 --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity_config2/r3/ospfd.conf @@ -0,0 +1 @@ +../../bgp_rfapi_basic_sanity/r3/ospfd.conf \ No newline at end of file diff --git a/tests/topotests/bgp_rfapi_basic_sanity_config2/r3/zebra.conf b/tests/topotests/bgp_rfapi_basic_sanity_config2/r3/zebra.conf new file mode 120000 index 0000000000..44a63cfdac --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity_config2/r3/zebra.conf @@ -0,0 +1 @@ +../../bgp_rfapi_basic_sanity/r3/zebra.conf \ No newline at end of file diff --git a/tests/topotests/bgp_rfapi_basic_sanity_config2/r4/bgpd.conf b/tests/topotests/bgp_rfapi_basic_sanity_config2/r4/bgpd.conf new file mode 100644 index 0000000000..4294274d3d --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity_config2/r4/bgpd.conf @@ -0,0 +1,52 @@ +frr defaults traditional +! +hostname r4 +password zebra +log stdout notifications +log monitor notifications +log commands +router bgp 5226 + bgp router-id 4.4.4.4 + bgp cluster-id 4.4.4.4 + neighbor 2.2.2.2 remote-as 5226 + neighbor 2.2.2.2 update-source 4.4.4.4 +! + address-family ipv4 unicast + no neighbor 2.2.2.2 activate + exit-address-family +! + address-family ipv4 vpn + neighbor 2.2.2.2 activate + exit-address-family +! + rfp holddown-factor 100 + rfp full-table-download off +! + vnc defaults + rd auto:vn:123 + response-lifetime 45 + rt both 1000:1 1000:2 + exit-vnc +! + vnc nve-group red + prefix vn 10.0.0.0/8 + rd auto:vn:10 + rt both 1000:10 + exit-vnc +! + vnc nve-group blue + prefix vn 20.0.0.0/8 + rd auto:vn:20 + rt both 1000:20 + exit-vnc +! + vnc nve-group green + prefix vn 30.0.0.0/8 + rd auto:vn:20 + rt both 1000:30 + exit-vnc +! +end + + + diff --git a/tests/topotests/bgp_rfapi_basic_sanity_config2/r4/ospfd.conf b/tests/topotests/bgp_rfapi_basic_sanity_config2/r4/ospfd.conf new file mode 120000 index 0000000000..3d7a0aafee --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity_config2/r4/ospfd.conf @@ -0,0 +1 @@ +../../bgp_rfapi_basic_sanity/r4/ospfd.conf \ No newline at end of file diff --git a/tests/topotests/bgp_rfapi_basic_sanity_config2/r4/zebra.conf b/tests/topotests/bgp_rfapi_basic_sanity_config2/r4/zebra.conf new file mode 120000 index 0000000000..c2fcd197bd --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity_config2/r4/zebra.conf @@ -0,0 +1 @@ +../../bgp_rfapi_basic_sanity/r4/zebra.conf \ No newline at end of file diff --git a/tests/topotests/bgp_rfapi_basic_sanity_config2/scripts b/tests/topotests/bgp_rfapi_basic_sanity_config2/scripts new file mode 120000 index 0000000000..8ac974dfad --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity_config2/scripts @@ -0,0 +1 @@ +../bgp_rfapi_basic_sanity/scripts/ \ No newline at end of file diff --git a/tests/topotests/bgp_rfapi_basic_sanity_config2/test_bgp_rfapi_basic_sanity_config2.py b/tests/topotests/bgp_rfapi_basic_sanity_config2/test_bgp_rfapi_basic_sanity_config2.py new file mode 120000 index 0000000000..54a67a86ba --- /dev/null +++ b/tests/topotests/bgp_rfapi_basic_sanity_config2/test_bgp_rfapi_basic_sanity_config2.py @@ -0,0 +1 @@ +../bgp_rfapi_basic_sanity/test_bgp_rfapi_basic_sanity.py \ No newline at end of file diff --git a/tests/topotests/bgp_vrf_netns/__init__.py b/tests/topotests/bgp_vrf_netns/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/topotests/bgp_vrf_netns/bgp-vrf-netns-topo.dot b/tests/topotests/bgp_vrf_netns/bgp-vrf-netns-topo.dot new file mode 100644 index 0000000000..2b1f72b822 --- /dev/null +++ b/tests/topotests/bgp_vrf_netns/bgp-vrf-netns-topo.dot @@ -0,0 +1,50 @@ +## Color coding: +######################### +## Main FRR: #f08080 red +## Switches: #d0e0d0 gray +## RIP: #19e3d9 Cyan +## RIPng: #fcb314 dark yellow +## OSPFv2: #32b835 Green +## OSPFv3: #19e3d9 Cyan +## ISIS IPv4 #fcb314 dark yellow +## ISIS IPv6 #9a81ec purple +## BGP IPv4 #eee3d3 beige +## BGP IPv6 #fdff00 yellow +##### Colors (see http://www.color-hex.com/) + +graph bgp_vrf_netns_eBGP_topo1 { + label="bgp vrf netns topo1 - eBGP with different AS numbers"; + labelloc="t"; + + # Routers + r1 [ + label="r1\nrtr-id 10.0.255.1/32", + shape=doubleoctagon, + fillcolor="#f08080", + style=filled, + ]; + + # 1 Switch for eBGP Peers + s1 [ + label="s1\n10.0.1.0/24", + shape=oval, + fillcolor="#d0e0d0", + style=filled, + ]; + + # 1 ExaBGP Peers AS 101 + peer1 [ + label="eBGP peer1\nAS101\nrtr-id 10.0.1.101/32", + shape=rectangle, + fillcolor="#eee3d3", + style=filled, + ]; + + # Connections + r1 -- s1 [label="eth0\n.1"]; + + peer1 -- s1 [label="eth0\n.101"]; + + # Arrange network to make cleaner diagram + { rank=same peer1 } -- s1 -- { rank=same r1 } [style=invis] +} diff --git a/tests/topotests/bgp_vrf_netns/bgp-vrf-netns-topo.pdf b/tests/topotests/bgp_vrf_netns/bgp-vrf-netns-topo.pdf new file mode 100644 index 0000000000..6da228898e Binary files /dev/null and b/tests/topotests/bgp_vrf_netns/bgp-vrf-netns-topo.pdf differ diff --git a/tests/topotests/bgp_vrf_netns/exabgp.env b/tests/topotests/bgp_vrf_netns/exabgp.env new file mode 100644 index 0000000000..a328e04962 --- /dev/null +++ b/tests/topotests/bgp_vrf_netns/exabgp.env @@ -0,0 +1,54 @@ + +[exabgp.api] +encoder = text +highres = false +respawn = false +socket = '' + +[exabgp.bgp] +openwait = 60 + +[exabgp.cache] +attributes = true +nexthops = true + +[exabgp.daemon] +daemonize = true +pid = '/var/run/exabgp/exabgp.pid' +user = 'exabgp' +##daemonize = false + +[exabgp.log] +all = false +configuration = true +daemon = true +destination = '/var/log/exabgp.log' +enable = true +level = INFO +message = false +network = true +packets = false +parser = false +processes = true +reactor = true +rib = false +routes = false +short = false +timers = false + +[exabgp.pdb] +enable = false + +[exabgp.profile] +enable = false +file = '' + +[exabgp.reactor] +speed = 1.0 + +[exabgp.tcp] +acl = false +bind = '' +delay = 0 +once = false +port = 179 diff --git a/tests/topotests/bgp_vrf_netns/peer1/exa-receive.py b/tests/topotests/bgp_vrf_netns/peer1/exa-receive.py new file mode 100755 index 0000000000..5334ea5369 --- /dev/null +++ b/tests/topotests/bgp_vrf_netns/peer1/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin,argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open('/tmp/peer%s-received.log' % peer, 'w') + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime('%Y%m%d_%H:%M:%S - ') + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp_vrf_netns/peer1/exa-send.py b/tests/topotests/bgp_vrf_netns/peer1/exa-send.py new file mode 100755 index 0000000000..9a2a201c57 --- /dev/null +++ b/tests/topotests/bgp_vrf_netns/peer1/exa-send.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python + +""" +exa-send.py: Send a few testroutes with ExaBGP +""" + +from sys import stdout,argv +from time import sleep + +sleep(5) + +# 1st arg is peer number +# 2nd arg is number of routes to send +peer = int(argv[1]) +numRoutes = int(argv[2]) +asnum = 99 + +# Announce numRoutes equal routes per PE - different neighbor AS +for i in range(0, numRoutes): + stdout.write('announce route 10.201.%s.0/24 med 100 community %i:1 next-hop 10.0.%i.%i\n' % (i, i, (((peer-1) / 5) + 1), peer+100)) + stdout.flush() + +#Loop endlessly to allow ExaBGP to continue running +while True: + sleep(1) + diff --git a/tests/topotests/bgp_vrf_netns/peer1/exabgp.cfg b/tests/topotests/bgp_vrf_netns/peer1/exabgp.cfg new file mode 100644 index 0000000000..2d0ca89f0f --- /dev/null +++ b/tests/topotests/bgp_vrf_netns/peer1/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa-send.py 1 10"; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 1"; + receive-routes; + encoder text; + } + + neighbor 10.0.1.1 { + router-id 10.0.1.101; + local-address 10.0.1.101; + local-as 99; + peer-as 100; + graceful-restart; + } + +} diff --git a/tests/topotests/bgp_vrf_netns/r1/bgpd.conf b/tests/topotests/bgp_vrf_netns/r1/bgpd.conf new file mode 100644 index 0000000000..e3f158d7b3 --- /dev/null +++ b/tests/topotests/bgp_vrf_netns/r1/bgpd.conf @@ -0,0 +1,8 @@ +! +router bgp 100 vrf r1-cust1 + bgp router-id 10.0.1.1 + bgp bestpath as-path multipath-relax + neighbor 10.0.1.101 remote-as 99 + ! +! + diff --git a/tests/topotests/bgp_vrf_netns/r1/summary.txt b/tests/topotests/bgp_vrf_netns/r1/summary.txt new file mode 100644 index 0000000000..7473fa2151 --- /dev/null +++ b/tests/topotests/bgp_vrf_netns/r1/summary.txt @@ -0,0 +1,17 @@ +{ +"ipv4Unicast":{ + "routerId":"10.0.1.1", + "as":100, + "vrfName":"r1-cust1", + "peerCount":1, + "peers":{ + "10.0.1.101":{ + "outq":0, + "inq":0, + "prefixReceivedCount":10, + "state":"Established" + } + }, + "totalPeers":1 +} +} diff --git a/tests/topotests/bgp_vrf_netns/r1/summary20.txt b/tests/topotests/bgp_vrf_netns/r1/summary20.txt new file mode 100644 index 0000000000..18318e07a8 --- /dev/null +++ b/tests/topotests/bgp_vrf_netns/r1/summary20.txt @@ -0,0 +1,15 @@ +{ + "routerId":"10.0.1.1", + "as":100, + "vrfName":"re1-cust1", + "peerCount":1, + "peers":{ + "10.0.1.101":{ + "outq":0, + "inq":0, + "prefixReceivedCount":10, + "state":"Established" + } + }, + "totalPeers":1 +} diff --git a/tests/topotests/bgp_vrf_netns/r1/zebra.conf b/tests/topotests/bgp_vrf_netns/r1/zebra.conf new file mode 100644 index 0000000000..817d9544d3 --- /dev/null +++ b/tests/topotests/bgp_vrf_netns/r1/zebra.conf @@ -0,0 +1,7 @@ +! +interface r1-eth0 vrf r1-cust1 + ip address 10.0.1.1/24 +! +line vty +! +debug vrf diff --git a/tests/topotests/bgp_vrf_netns/test_bgp_vrf_netns_topo.py b/tests/topotests/bgp_vrf_netns/test_bgp_vrf_netns_topo.py new file mode 100755 index 0000000000..a5590bcaf6 --- /dev/null +++ b/tests/topotests/bgp_vrf_netns/test_bgp_vrf_netns_topo.py @@ -0,0 +1,225 @@ +#!/usr/bin/env python + +# +# test_bgp_vrf_netns_topo1.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2018 by 6WIND +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_bgp_vrf_netns_topo1.py: Test BGP topology with EBGP on NETNS VRF +""" + +import json +import os +import sys +import functools +import pytest + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, '../')) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. +from mininet.topo import Topo + +total_ebgp_peers = 1 +CustomizeVrfWithNetns = True + +##################################################### +## +## Network Topology Definition +## +##################################################### + +class BGPVRFNETNSTopo1(Topo): + "BGP EBGP VRF NETNS Topology 1" + + def build(self, **_opts): + tgen = get_topogen(self) + + # Setup Routers + tgen.add_router('r1') + + # Setup Switches + switch = tgen.add_switch('s1') + switch.add_link(tgen.gears['r1']) + + # Add eBGP ExaBGP neighbors + peer_ip = '10.0.1.101' + peer_route = 'via 10.0.1.1' + peer = tgen.add_exabgp_peer('peer1', + ip=peer_ip, defaultRoute=peer_route) + switch = tgen.gears['s1'] + switch.add_link(peer) + + +##################################################### +## +## Tests starting +## +##################################################### + +def setup_module(module): + tgen = Topogen(BGPVRFNETNSTopo1, module.__name__) + tgen.start_topology() + + # Get r1 reference + router = tgen.gears['r1'] + + # check for zebra capability + if CustomizeVrfWithNetns == True: + if router.check_capability( + TopoRouter.RD_ZEBRA, + '--vrfwnetns' + ) == False: + return pytest.skip('Skipping BGP VRF NETNS Test. VRF NETNS backend not available on FRR') + if os.system('ip netns list') != 0: + return pytest.skip('Skipping BGP VRF NETNS Test. NETNS not available on System') + # retrieve VRF backend kind + if CustomizeVrfWithNetns == True: + logger.info('Testing with VRF Namespace support') + + # create VRF r1-cust1 + # move r1-eth0 to VRF r1-cust1 + cmds = ['if [ -e /var/run/netns/{0}-cust1 ] ; then ip netns del {0}-cust1 ; fi', + 'ip netns add {0}-cust1', + 'ip link set dev {0}-eth0 netns {0}-cust1', + 'ip netns exec {0}-cust1 ifconfig {0}-eth0 up'] + for cmd in cmds: + cmd = cmd.format('r1') + logger.info('cmd: '+cmd); + output = router.run(cmd.format('r1')) + if output != None and len(output) > 0: + logger.info('Aborting due to unexpected output: cmd="{}" output=\n{}'.format(cmd, output)) + return pytest.skip('Skipping BGP VRF NETNS Test. Unexpected output to command: '+cmd) + #run daemons + router.load_config( + TopoRouter.RD_ZEBRA, + os.path.join(CWD, '{}/zebra.conf'.format('r1')), + '--vrfwnetns' + ) + router.load_config( + TopoRouter.RD_BGP, + os.path.join(CWD, '{}/bgpd.conf'.format('r1')) + ) + + logger.info('Launching BGP and ZEBRA') + # BGP and ZEBRA start without underlying VRF + router.start() + # Starting Hosts and init ExaBGP on each of them + logger.info('starting exaBGP on peer1') + peer_list = tgen.exabgp_peers() + for pname, peer in peer_list.iteritems(): + peer_dir = os.path.join(CWD, pname) + env_file = os.path.join(CWD, 'exabgp.env') + logger.info('Running ExaBGP peer') + peer.start(peer_dir, env_file) + logger.info(pname) + +def teardown_module(module): + tgen = get_topogen() + # move back r1-eth0 to default VRF + # delete VRF r1-cust1 + cmds = ['ip netns exec {0}-cust1 ip link set {0}-eth0 netns 1', + 'ip netns delete {0}-cust1'] + for cmd in cmds: + tgen.net['r1'].cmd(cmd.format('r1')) + + tgen.stop_topology() + +def test_bgp_vrf_learn(): + "Test daemon learnt VRF context" + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Expected result + output = tgen.gears['r1'].vtysh_cmd("show vrf", isjson=False) + logger.info('output is: {}'.format(output)) + + output = tgen.gears['r1'].vtysh_cmd("show bgp vrfs", isjson=False) + logger.info('output is: {}'.format(output)) + + +def test_bgp_convergence(): + "Test for BGP topology convergence" + tgen = get_topogen() + + # uncomment if you want to troubleshoot + # tgen.mininet_cli() + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info('waiting for bgp convergence') + + # Expected result + router = tgen.gears['r1'] + if router.has_version('<', '3.0'): + reffile = os.path.join(CWD, 'r1/summary20.txt') + else: + reffile = os.path.join(CWD, 'r1/summary.txt') + + expected = json.loads(open(reffile).read()) + + test_func = functools.partial(topotest.router_json_cmp, + router, 'show bgp vrf r1-cust1 summary json', expected) + _, res = topotest.run_and_expect(test_func, None, count=90, wait=0.5) + assertmsg = 'BGP router network did not converge' + assert res is None, assertmsg + +def test_bgp_vrf_netns(): + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + expect = { + 'routerId': '10.0.1.1', + 'routes': { + }, + } + + for subnet in range(0, 10): + netkey = '10.201.{}.0/24'.format(subnet) + expect['routes'][netkey] = [] + peer = {'valid': True} + expect['routes'][netkey].append(peer) + + test_func = functools.partial(topotest.router_json_cmp, + tgen.gears['r1'], 'show ip bgp vrf r1-cust1 ipv4 json', expect) + _, res = topotest.run_and_expect(test_func, None, count=12, wait=0.5) + assertmsg = 'expected routes in "show ip bgp vrf r1-cust1 ipv4" output' + assert res is None, assertmsg + +if __name__ == '__main__': + + args = ["-s"] + sys.argv[1:] + ret = pytest.main(args) + + sys.exit(ret) diff --git a/tests/topotests/conftest.py b/tests/topotests/conftest.py new file mode 100755 index 0000000000..327e4625f2 --- /dev/null +++ b/tests/topotests/conftest.py @@ -0,0 +1,68 @@ +""" +Topotest conftest.py file. +""" + +from lib.topogen import get_topogen, diagnose_env +from lib.topotest import json_cmp_result +from lib.topolog import logger +import pytest + +def pytest_addoption(parser): + """ + Add topology-only option to the topology tester. This option makes pytest + only run the setup_module() to setup the topology without running any tests. + """ + parser.addoption('--topology-only', action='store_true', + help='Only set up this topology, don\'t run tests') + +def pytest_runtest_call(): + """ + This function must be run after setup_module(), it does standarized post + setup routines. It is only being used for the 'topology-only' option. + """ + # pylint: disable=E1101 + # Trust me, 'config' exists. + if pytest.config.getoption('--topology-only'): + tgen = get_topogen() + if tgen is not None: + # Allow user to play with the setup. + tgen.mininet_cli() + + pytest.exit('the topology executed successfully') + +def pytest_assertrepr_compare(op, left, right): + """ + Show proper assertion error message for json_cmp results. + """ + json_result = left + if not isinstance(json_result, json_cmp_result): + json_result = right + if not isinstance(json_result, json_cmp_result): + return None + + return json_result.errors + +def pytest_configure(config): + "Assert that the environment is correctly configured." + if not diagnose_env(): + pytest.exit('enviroment has errors, please read the logs') + +def pytest_runtest_makereport(item, call): + "Log all assert messages to default logger with error level" + # Nothing happened + if call.excinfo is None: + return + + parent = item.parent + modname = parent.module.__name__ + + # Treat skips as non errors + if call.excinfo.typename != 'AssertionError': + logger.info('assert skipped at "{}/{}": {}'.format( + modname, item.name, call.excinfo.value)) + return + + # Handle assert failures + parent._previousfailed = item + logger.error('assert failed at "{}/{}": {}'.format( + modname, item.name, call.excinfo.value)) diff --git a/tests/topotests/eigrp-topo1/r1/eigrpd.conf b/tests/topotests/eigrp-topo1/r1/eigrpd.conf new file mode 100644 index 0000000000..6c800abd9b --- /dev/null +++ b/tests/topotests/eigrp-topo1/r1/eigrpd.conf @@ -0,0 +1,8 @@ +log file eigrpd.log +! +router eigrp 1 + network 0.0.0.0/0 +! +line vty +! + diff --git a/tests/topotests/eigrp-topo1/r1/show_ip_eigrp.json b/tests/topotests/eigrp-topo1/r1/show_ip_eigrp.json new file mode 100644 index 0000000000..be0fdcfed9 --- /dev/null +++ b/tests/topotests/eigrp-topo1/r1/show_ip_eigrp.json @@ -0,0 +1,32 @@ +{ + "P": { + "192.168.1.0/24": { + "fd": "28160", + "interface": " r1-eth0", + "serno": "0", + "successors": "1", + "via": "Connected" + }, + "192.168.3.0/24": { + "fd": "33280", + "interface": " r1-eth1", + "serno": "0", + "successors": "1", + "via": "193.1.1.2 (33280/30720)" + }, + "193.1.1.0/26": { + "fd": "28160", + "interface": " r1-eth1", + "serno": "0", + "successors": "1", + "via": "Connected" + }, + "193.1.2.0/24": { + "fd": "30720", + "interface": " r1-eth1", + "serno": "0", + "successors": "1", + "via": "193.1.1.2 (30720/28160)" + } + } +} diff --git a/tests/topotests/eigrp-topo1/r1/show_ip_eigrp.ref b/tests/topotests/eigrp-topo1/r1/show_ip_eigrp.ref new file mode 100644 index 0000000000..a2d7b3307d --- /dev/null +++ b/tests/topotests/eigrp-topo1/r1/show_ip_eigrp.ref @@ -0,0 +1,14 @@ + +EIGRP Topology Table for AS(1)/ID(193.1.1.1) + +Codes: P - Passive, A - Active, U - Update, Q - Query, R - Reply + r - reply Status, s - sia Status + +P 193.1.1.0/26, 1 successors, FD is 28160, serno: 0 + via Connected, r1-eth1 +P 192.168.1.0/24, 1 successors, FD is 28160, serno: 0 + via Connected, r1-eth0 +P 193.1.2.0/24, 1 successors, FD is 30720, serno: 0 + via 193.1.1.2 (30720/28160), r1-eth1 +P 192.168.3.0/24, 1 successors, FD is 33280, serno: 0 + via 193.1.1.2 (33280/30720), r1-eth1 diff --git a/tests/topotests/eigrp-topo1/r1/show_ip_route.json_ref b/tests/topotests/eigrp-topo1/r1/show_ip_route.json_ref new file mode 100644 index 0000000000..36dd5da597 --- /dev/null +++ b/tests/topotests/eigrp-topo1/r1/show_ip_route.json_ref @@ -0,0 +1,90 @@ +{ + "192.168.1.0/24":[ + { + "prefix":"192.168.1.0/24", + "protocol":"eigrp", + "metric":0, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"r1-eth0", + "active":true + } + ] + }, + { + "prefix":"192.168.1.0/24", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"r1-eth0", + "active":true + } + ] + } + ], + "192.168.3.0/24":[ + { + "prefix":"192.168.3.0/24", + "protocol":"eigrp", + "selected":true, + "metric":0, + "nexthops":[ + { + "fib":true, + "ip":"193.1.1.2", + "afi":"ipv4", + "interfaceName":"r1-eth1", + "active":true + } + ] + } + ], + "193.1.1.0/26":[ + { + "prefix":"193.1.1.0/26", + "protocol":"eigrp", + "metric":0, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"r1-eth1", + "active":true + } + ] + }, + { + "prefix":"193.1.1.0/26", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"r1-eth1", + "active":true + } + ] + } + ], + "193.1.2.0/24":[ + { + "prefix":"193.1.2.0/24", + "protocol":"eigrp", + "selected":true, + "metric":0, + "nexthops":[ + { + "fib":true, + "ip":"193.1.1.2", + "afi":"ipv4", + "interfaceName":"r1-eth1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/eigrp-topo1/r1/zebra.conf b/tests/topotests/eigrp-topo1/r1/zebra.conf new file mode 100644 index 0000000000..8537f6dd80 --- /dev/null +++ b/tests/topotests/eigrp-topo1/r1/zebra.conf @@ -0,0 +1,19 @@ +log file zebra.log +! +hostname r1 +! +interface r1-eth0 + ip address 192.168.1.1/24 +! +interface r1-eth1 + description to sw2 - RIPv2 interface + ip address 193.1.1.1/26 + no link-detect +! +ip forwarding +ipv6 forwarding +! +! +line vty +! + diff --git a/tests/topotests/eigrp-topo1/r2/eigrpd.conf b/tests/topotests/eigrp-topo1/r2/eigrpd.conf new file mode 100644 index 0000000000..56c747d97c --- /dev/null +++ b/tests/topotests/eigrp-topo1/r2/eigrpd.conf @@ -0,0 +1,7 @@ +log file eigrpd.log +! +! +router eigrp 1 + network 193.1.1.0/26 + network 193.1.2.0/24 + diff --git a/tests/topotests/eigrp-topo1/r2/show_ip_eigrp.json b/tests/topotests/eigrp-topo1/r2/show_ip_eigrp.json new file mode 100644 index 0000000000..ae9f441a38 --- /dev/null +++ b/tests/topotests/eigrp-topo1/r2/show_ip_eigrp.json @@ -0,0 +1,32 @@ +{ + "P": { + "192.168.1.0/24": { + "fd": "30720", + "interface": " r2-eth0", + "serno": "0", + "successors": "1", + "via": "193.1.1.1 (30720/28160)" + }, + "192.168.3.0/24": { + "fd": "30720", + "interface": " r2-eth1", + "serno": "0", + "successors": "1", + "via": "193.1.2.2 (30720/28160)" + }, + "193.1.1.0/26": { + "fd": "28160", + "interface": " r2-eth0", + "serno": "0", + "successors": "1", + "via": "Connected" + }, + "193.1.2.0/24": { + "fd": "28160", + "interface": " r2-eth1", + "serno": "0", + "successors": "1", + "via": "Connected" + } + } +} diff --git a/tests/topotests/eigrp-topo1/r2/show_ip_eigrp.ref b/tests/topotests/eigrp-topo1/r2/show_ip_eigrp.ref new file mode 100644 index 0000000000..cce49cda07 --- /dev/null +++ b/tests/topotests/eigrp-topo1/r2/show_ip_eigrp.ref @@ -0,0 +1,14 @@ + +EIGRP Topology Table for AS(1)/ID(193.1.2.1) + +Codes: P - Passive, A - Active, U - Update, Q - Query, R - Reply + r - reply Status, s - sia Status + +P 193.1.1.0/26, 1 successors, FD is 28160, serno: 0 + via Connected, r2-eth0 +P 192.168.1.0/24, 1 successors, FD is 30720, serno: 0 + via 193.1.1.1 (30720/28160), r2-eth0 +P 193.1.2.0/24, 1 successors, FD is 28160, serno: 0 + via Connected, r2-eth1 +P 192.168.3.0/24, 1 successors, FD is 30720, serno: 0 + via 193.1.2.2 (30720/28160), r2-eth1 diff --git a/tests/topotests/eigrp-topo1/r2/show_ip_route.json_ref b/tests/topotests/eigrp-topo1/r2/show_ip_route.json_ref new file mode 100644 index 0000000000..44903ce3ff --- /dev/null +++ b/tests/topotests/eigrp-topo1/r2/show_ip_route.json_ref @@ -0,0 +1,90 @@ +{ + "192.168.1.0/24":[ + { + "prefix":"192.168.1.0/24", + "protocol":"eigrp", + "selected":true, + "metric":0, + "nexthops":[ + { + "fib":true, + "ip":"193.1.1.1", + "afi":"ipv4", + "interfaceName":"r2-eth0", + "active":true + } + ] + } + ], + "192.168.3.0/24":[ + { + "prefix":"192.168.3.0/24", + "protocol":"eigrp", + "selected":true, + "metric":0, + "nexthops":[ + { + "fib":true, + "ip":"193.1.2.2", + "afi":"ipv4", + "interfaceName":"r2-eth1", + "active":true + } + ] + } + ], + "193.1.1.0/26":[ + { + "prefix":"193.1.1.0/26", + "protocol":"eigrp", + "metric":0, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"r2-eth0", + "active":true + } + ] + }, + { + "prefix":"193.1.1.0/26", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"r2-eth0", + "active":true + } + ] + } + ], + "193.1.2.0/24":[ + { + "prefix":"193.1.2.0/24", + "protocol":"eigrp", + "metric":0, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"r2-eth1", + "active":true + } + ] + }, + { + "prefix":"193.1.2.0/24", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"r2-eth1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/eigrp-topo1/r2/zebra.conf b/tests/topotests/eigrp-topo1/r2/zebra.conf new file mode 100644 index 0000000000..c440f3a350 --- /dev/null +++ b/tests/topotests/eigrp-topo1/r2/zebra.conf @@ -0,0 +1,21 @@ +log file zebra.log +! +hostname r2 +! +interface r2-eth0 + description to sw2 - RIPv2 interface + ip address 193.1.1.2/26 + no link-detect +! +interface r2-eth1 + description to sw3 - RIPv1 interface + ip address 193.1.2.1/24 + no link-detect +! +ip forwarding +ipv6 forwarding +! +! +line vty +! + diff --git a/tests/topotests/eigrp-topo1/r3/eigrpd.conf b/tests/topotests/eigrp-topo1/r3/eigrpd.conf new file mode 100644 index 0000000000..53ad1bb6a1 --- /dev/null +++ b/tests/topotests/eigrp-topo1/r3/eigrpd.conf @@ -0,0 +1,6 @@ +log file eigrpd.log +! +! +router eigrp 1 + network 0.0.0.0/0 + diff --git a/tests/topotests/eigrp-topo1/r3/show_ip_eigrp.json b/tests/topotests/eigrp-topo1/r3/show_ip_eigrp.json new file mode 100644 index 0000000000..83db66c8c8 --- /dev/null +++ b/tests/topotests/eigrp-topo1/r3/show_ip_eigrp.json @@ -0,0 +1,32 @@ +{ + "P": { + "192.168.1.0/24": { + "fd": "33280", + "interface": " r3-eth1", + "serno": "0", + "successors": "1", + "via": "193.1.2.1 (33280/30720)" + }, + "192.168.3.0/24": { + "fd": "28160", + "interface": " r3-eth0", + "serno": "0", + "successors": "1", + "via": "Connected" + }, + "193.1.1.0/26": { + "fd": "30720", + "interface": " r3-eth1", + "serno": "0", + "successors": "1", + "via": "193.1.2.1 (30720/28160)" + }, + "193.1.2.0/24": { + "fd": "28160", + "interface": " r3-eth1", + "serno": "0", + "successors": "1", + "via": "Connected" + } + } +} diff --git a/tests/topotests/eigrp-topo1/r3/show_ip_eigrp.ref b/tests/topotests/eigrp-topo1/r3/show_ip_eigrp.ref new file mode 100644 index 0000000000..70f3d3f98b --- /dev/null +++ b/tests/topotests/eigrp-topo1/r3/show_ip_eigrp.ref @@ -0,0 +1,14 @@ + +EIGRP Topology Table for AS(1)/ID(193.1.2.2) + +Codes: P - Passive, A - Active, U - Update, Q - Query, R - Reply + r - reply Status, s - sia Status + +P 193.1.1.0/26, 1 successors, FD is 30720, serno: 0 + via 193.1.2.1 (30720/28160), r3-eth1 +P 192.168.1.0/24, 1 successors, FD is 33280, serno: 0 + via 193.1.2.1 (33280/30720), r3-eth1 +P 193.1.2.0/24, 1 successors, FD is 28160, serno: 0 + via Connected, r3-eth1 +P 192.168.3.0/24, 1 successors, FD is 28160, serno: 0 + via Connected, r3-eth0 diff --git a/tests/topotests/eigrp-topo1/r3/show_ip_route.json_ref b/tests/topotests/eigrp-topo1/r3/show_ip_route.json_ref new file mode 100644 index 0000000000..d80e1d97e6 --- /dev/null +++ b/tests/topotests/eigrp-topo1/r3/show_ip_route.json_ref @@ -0,0 +1,108 @@ +{ + "192.168.1.0/24":[ + { + "prefix":"192.168.1.0/24", + "protocol":"eigrp", + "selected":true, + "metric":0, + "nexthops":[ + { + "fib":true, + "ip":"193.1.2.1", + "afi":"ipv4", + "interfaceName":"r3-eth1", + "active":true + } + ] + } + ], + "192.168.2.0/24":[ + { + "prefix":"192.168.2.0/24", + "protocol":"static", + "selected":true, + "distance":1, + "metric":0, + "nexthops":[ + { + "fib":true, + "ip":"192.168.3.10", + "afi":"ipv4", + "interfaceName":"r3-eth0", + "active":true + } + ] + } + ], + "192.168.3.0/24":[ + { + "prefix":"192.168.3.0/24", + "protocol":"eigrp", + "metric":0, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"r3-eth0", + "active":true + } + ] + }, + { + "prefix":"192.168.3.0/24", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"r3-eth0", + "active":true + } + ] + } + ], + "193.1.1.0/26":[ + { + "prefix":"193.1.1.0/26", + "protocol":"eigrp", + "selected":true, + "metric":0, + "nexthops":[ + { + "fib":true, + "ip":"193.1.2.1", + "afi":"ipv4", + "interfaceName":"r3-eth1", + "active":true + } + ] + } + ], + "193.1.2.0/24":[ + { + "prefix":"193.1.2.0/24", + "protocol":"eigrp", + "metric":0, + "nexthops":[ + { + "directlyConnected":true, + "interfaceName":"r3-eth1", + "active":true + } + ] + }, + { + "prefix":"193.1.2.0/24", + "protocol":"connected", + "selected":true, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"r3-eth1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/eigrp-topo1/r3/zebra.conf b/tests/topotests/eigrp-topo1/r3/zebra.conf new file mode 100644 index 0000000000..7f145b4583 --- /dev/null +++ b/tests/topotests/eigrp-topo1/r3/zebra.conf @@ -0,0 +1,22 @@ +log file zebra.log +! +hostname r3 +! +interface r3-eth0 + description to sw4 - Stub interface + ip address 192.168.3.1/24 + no link-detect +! +interface r3-eth1 + description to sw3 - RIPv2 interface + ip address 193.1.2.2/24 + no link-detect +! +ip route 192.168.2.0/24 192.168.3.10 +! +ip forwarding +ipv6 forwarding +! +! +line vty +! diff --git a/tests/topotests/eigrp-topo1/test_eigrp_topo1.dot b/tests/topotests/eigrp-topo1/test_eigrp_topo1.dot new file mode 100644 index 0000000000..ca3a0fe5b9 --- /dev/null +++ b/tests/topotests/eigrp-topo1/test_eigrp_topo1.dot @@ -0,0 +1,62 @@ +## GraphViz file for test_eigrp_topo1 +## +## Color coding: +######################### +## Main FRR: #f08080 red +## Switches: #d0e0d0 gray +## RIP: #19e3d9 Cyan +## RIPng: #fcb314 dark yellow +## EIGRP: #696969 +## OSPFv2: #32b835 Green +## OSPFv3: #19e3d9 Cyan +## ISIS IPv4 #fcb314 dark yellow +## ISIS IPv6 #9a81ec purple +## BGP IPv4 #eee3d3 beige +## BGP IPv6 #fdff00 yellow +##### Colors (see http://www.color-hex.com/) + +graph test_eigrp_topo1 { + overlap=false; + constraint=false; + + // title + labelloc="t"; + label="Test Topologoy EIGRP Topo1"; + + ###################### + # Routers + ###################### + + # Main FRR Router with all protocols + R1 [shape=doubleoctagon, label="R1 FRR\nMain Router", fillcolor="#f08080", style=filled]; + + # EIGRP Routers + R2 [shape=doubleoctagon, label="R2 FRR\nEIGRP Router", fillcolor="#19e3d9", style=filled]; + R3 [shape=doubleoctagon, label="R3 FRR\nEIGRP Router", fillcolor="#19e3d9", style=filled]; + + ###################### + # Network Lists + ###################### + + SW1_R1_stub [label="SW1\n192.168.1.0/24", fillcolor="#d0e0d0", style=filled]; + + # EIGRP Networks + SW2_R1_R2 [label="SW2\nEIGRPv2\n193.1.1.0/26", fillcolor="#d0e0d0", style=filled]; + SW3_R2_R3 [label="SW3\nEIGRPv1\n193.1.2.0/24", fillcolor="#d0e0d0", style=filled]; + SW4_R3 [label="SW4\n192.168.3.0/24", fillcolor="#d0e0d0", style=filled]; + Net_R3_remote [label="Static Net\n192.168.2.0/24"]; + + ###################### + # Network Connections + ###################### + R1 -- SW1_R1_stub [label = "eth0\n.1\n::1"]; + + # EIGRP Network + R1 -- SW2_R1_R2 [label = "eth1\n.1"]; + SW2_R1_R2 -- R2 [label = "eth0\n.2"]; + R2 -- SW3_R2_R3 [label = "eth1\n.1"]; + SW3_R2_R3 -- R3 [label = "eth1\n.2"]; + R3 -- SW4_R3 [label = "eth0\n.1"]; + SW4_R3 -- Net_R3_remote [label = ".10"]; + +} diff --git a/tests/topotests/eigrp-topo1/test_eigrp_topo1.py b/tests/topotests/eigrp-topo1/test_eigrp_topo1.py new file mode 100755 index 0000000000..de8cb81f8f --- /dev/null +++ b/tests/topotests/eigrp-topo1/test_eigrp_topo1.py @@ -0,0 +1,286 @@ +#!/usr/bin/env python + +# +# test_eigrp_topo1.py +# +# Copyright (c) 2017 by +# Cumulus Networks, Inc. +# Donald Sharp +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_eigrp_topo1.py: Testing EIGRP + +""" + +import os +import re +import sys +import pytest +import json + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, '../')) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. +from mininet.topo import Topo + +##################################################### +## +## Network Topology Definition +## +##################################################### + +class NetworkTopo(Topo): + "EIGRP Topology 1" + + def build(self, **_opts): + "Build function" + + tgen = get_topogen(self) + + for routern in range(1, 4): + tgen.add_router('r{}'.format(routern)) + + # On main router + # First switch is for a dummy interface (for local network) + switch = tgen.add_switch('sw1') + switch.add_link(tgen.gears['r1']) + + # Switches for EIGRP + # switch 2 switch is for connection to EIGRP router + switch = tgen.add_switch('sw2') + switch.add_link(tgen.gears['r1']) + switch.add_link(tgen.gears['r2']) + + # switch 4 is stub on remote EIGRP router + switch = tgen.add_switch('sw4') + switch.add_link(tgen.gears['r3']) + + # switch 3 is between EIGRP routers + switch = tgen.add_switch('sw3') + switch.add_link(tgen.gears['r2']) + switch.add_link(tgen.gears['r3']) + + +##################################################### +## +## Tests starting +## +##################################################### + +def setup_module(module): + "Setup topology" + tgen = Topogen(NetworkTopo, module.__name__) + tgen.start_topology() + + # This is a sample of configuration loading. + router_list = tgen.routers() + for rname, router in router_list.iteritems(): + router.load_config( + TopoRouter.RD_ZEBRA, + os.path.join(CWD, '{}/zebra.conf'.format(rname)) + ) + router.load_config( + TopoRouter.RD_EIGRP, + os.path.join(CWD, '{}/eigrpd.conf'.format(rname)) + ) + + tgen.start_router() + + +def teardown_module(_mod): + "Teardown the pytest environment" + tgen = get_topogen() + + # This function tears down the whole topology. + tgen.stop_topology() + + +def test_converge_protocols(): + "Wait for protocol convergence" + + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + topotest.sleep(5, 'Waiting for EIGRP convergence') + + +def test_eigrp_routes(): + "Test EIGRP 'show ip eigrp'" + + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Verify EIGRP Status + logger.info("Verifying EIGRP routes") + + router_list = tgen.routers().values() + for router in router_list: + refTableFile = '{}/{}/show_ip_eigrp.json'.format(CWD, router.name) + + # Read expected result from file + expected = json.loads(open(refTableFile).read()) + + # Actual output from router + actual = ip_eigrp_topo(router) + + assertmsg = '"show ip eigrp topo" mismatches on {}'.format(router.name) + assert topotest.json_cmp(actual, expected) is None, assertmsg + + +def test_zebra_ipv4_routingTable(): + "Test 'show ip route'" + + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + failures = 0 + router_list = tgen.routers().values() + for router in router_list: + output = router.vtysh_cmd('show ip route json', isjson=True) + refTableFile = '{}/{}/show_ip_route.json_ref'.format(CWD, router.name) + expected = json.loads(open(refTableFile).read()) + + assertmsg = 'Zebra IPv4 Routing Table verification failed for router {}'.format(router.name) + assert topotest.json_cmp(output, expected) is None, assertmsg + + +def test_shutdown_check_stderr(): + if os.environ.get('TOPOTESTS_CHECK_STDERR') is None: + pytest.skip('Skipping test for Stderr output and memory leaks') + + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Verifying unexpected STDERR output from daemons") + + router_list = tgen.routers().values() + for router in router_list: + router.stop() + + log = tgen.net[router.name].getStdErr('eigrpd') + if log: + logger.error('EIGRPd StdErr Log:' + log) + log = tgen.net[router.name].getStdErr('zebra') + if log: + logger.error('Zebra StdErr Log:' + log) + + +if __name__ == '__main__': + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) + +# +# Auxiliary Functions +# +def ip_eigrp_topo(node): + """ + Parse 'show ip eigrp topo' from `node` and returns a dict with the + result. + + Example: + { + 'P': { + '192.168.1.0/24': { + 'sucessors': 1, + 'fd': 112233, + 'serno': 0, + 'via': 'Connected', + 'interface': 'eth0', + }, + '192.168.2.0/24': { + 'sucessors': 1, + 'fd': 112234, + 'serno': 0, + 'via': 'Connected', + 'interface': 'eth1', + } + } + } + """ + output = topotest.normalize_text(node.vtysh_cmd('show ip eigrp topo')).splitlines() + result = {} + for idx, line in enumerate(output): + columns = line.split(' ', 1) + + # Parse the following format into python dicts + # code A.B.C.D/E, X successors, FD is Y, serno: Z + # via FOO, interface-name + code = columns[0] + if code not in ['P', 'A', 'U', 'Q', 'R', 'r', 's']: + continue + + if not result.has_key(code): + result[code] = {} + + # Split network from the rest + columns = columns[1].split(',') + + # Parse first line data + network = columns[0] + result[code][network] = {} + for column in columns: + # Skip the network column + if column == columns[0]: + continue + + match = re.search(r'(\d+) successors', column) + if match is not None: + result[code][network]['successors'] = match.group(1) + continue + + match = re.search(r'FD is (\d+)', column) + if match is not None: + result[code][network]['fd'] = match.group(1) + continue + + match = re.search(r'serno: (\d+)', column) + if match is not None: + result[code][network]['serno'] = match.group(1) + continue + + # Parse second line data + nextline = output[idx + 1] + columns = topotest.normalize_text(nextline).split(',') + for column in columns: + match = re.search(r'via (.+)', column) + if match is not None: + result[code][network]['via'] = match.group(1) + continue + + match = re.search(r'(.+)', column) + if match is not None: + result[code][network]['interface'] = match.group(1) + continue + + return result diff --git a/tests/topotests/example-test/__init__.py b/tests/topotests/example-test/__init__.py new file mode 100755 index 0000000000..e69de29bb2 diff --git a/tests/topotests/example-test/test_example.py b/tests/topotests/example-test/test_example.py new file mode 100755 index 0000000000..8e37ad11d4 --- /dev/null +++ b/tests/topotests/example-test/test_example.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python + +import subprocess +import sys +import os +import time + +import pytest + +fatal_error = "" + +def setup_module(module): + print ("setup_module module:%s" % module.__name__) + +def teardown_module(module): + print ("teardown_module module:%s" % module.__name__) + +def setup_function(function): + print ("setup_function function:%s" % function.__name__) + +def teardown_function(function): + print ("teardown_function function:%s" % function.__name__) + +def test_numbers_compare(): + a = 12 + print ("Dummy Output") + assert( a == 12 ) + +def test_fail_example(): + assert True, "Some Text with explaination in case of failure" + +def test_ls_exits_zero(): + "Tests for ls command on invalid file" + + global fatal_error + + proc = subprocess.Popen( + ["ls", "/some/nonexistant/file"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + stdout, stderr = proc.communicate() + + if (proc.returncode != 0): + # Mark this as a fatal error which skips some other tests on failure + fatal_error = "test_fail_example failed" + assert proc.returncode == 0, "Return Code is non-Zero:\n%s" % stderr + +def test_skipped_on_fatalerror(): + global fatal_error + + # Skip if previous fatal error condition is raised + if (fatal_error != ""): + pytest.skip(fatal_error) + + assert True, "Some Text with explaination in case of failure" + +if __name__ == '__main__': + retval = pytest.main(["-s"]) + sys.exit(retval) diff --git a/tests/topotests/example-test/test_template.dot b/tests/topotests/example-test/test_template.dot new file mode 100644 index 0000000000..b5e12020ce --- /dev/null +++ b/tests/topotests/example-test/test_template.dot @@ -0,0 +1,51 @@ +## Color coding: +######################### +## Main FRR: #f08080 red +## Switches: #d0e0d0 gray +## RIP: #19e3d9 Cyan +## RIPng: #fcb314 dark yellow +## OSPFv2: #32b835 Green +## OSPFv3: #19e3d9 Cyan +## ISIS IPv4 #fcb314 dark yellow +## ISIS IPv6 #9a81ec purple +## BGP IPv4 #eee3d3 beige +## BGP IPv6 #fdff00 yellow +##### Colors (see http://www.color-hex.com/) + +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"]; +} diff --git a/tests/topotests/example-test/test_template.jpg b/tests/topotests/example-test/test_template.jpg new file mode 100644 index 0000000000..b01ef73f5a Binary files /dev/null and b/tests/topotests/example-test/test_template.jpg differ diff --git a/tests/topotests/example-test/test_template.py b/tests/topotests/example-test/test_template.py new file mode 100755 index 0000000000..4e35ce8b9f --- /dev/null +++ b/tests/topotests/example-test/test_template.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python + +# +#