diff options
Diffstat (limited to 'tests')
167 files changed, 8848 insertions, 1359 deletions
diff --git a/tests/lib/test_printfrr.c b/tests/lib/test_printfrr.c index 24de3fa88d..21b3a916b8 100644 --- a/tests/lib/test_printfrr.c +++ b/tests/lib/test_printfrr.c @@ -59,21 +59,88 @@ static void printcmp(const char *fmt, ...) errors++; } -static void printchk(const char *ref, const char *fmt, ...) PRINTFRR(2, 3); -static void printchk(const char *ref, const char *fmt, ...) +static int printchk(const char *ref, const char *fmt, ...) PRINTFRR(2, 3); +static int printchk(const char *ref, const char *fmt, ...) { va_list ap; char bufrr[256]; + bool truncfail = false; + size_t i; + size_t expectlen; + memset(bufrr, 0xcc, sizeof(bufrr)); va_start(ap, fmt); - vsnprintfrr(bufrr, sizeof(bufrr), fmt, ap); + expectlen = vsnprintfrr(NULL, 0, fmt, ap); + va_end(ap); + + va_start(ap, fmt); + vsnprintfrr(bufrr, 7, fmt, ap); va_end(ap); - printf("fmt: \"%s\"\nref: \"%s\"\nfrr: \"%s\"\n%s\n\n", + if (strnlen(bufrr, 7) == 7) + truncfail = true; + if (strnlen(bufrr, 7) < 7 && strncmp(ref, bufrr, 6) != 0) + truncfail = true; + for (i = 7; i < sizeof(bufrr); i++) + if (bufrr[i] != (char)0xcc) { + truncfail = true; + break; + } + + if (truncfail) { + printf("truncation test FAILED:\n" + "fmt: \"%s\"\nref: \"%s\"\nfrr[:7]: \"%s\"\n%s\n\n", + fmt, ref, bufrr, strcmp(ref, bufrr) ? "ERROR" : "ok"); + errors++; + } + + struct fmt_outpos outpos[16]; + struct fbuf fb = { + .buf = bufrr, + .pos = bufrr, + .len = sizeof(bufrr) - 1, + .outpos = outpos, + .outpos_n = array_size(outpos), + }; + + va_start(ap, fmt); + vbprintfrr(&fb, fmt, ap); + fb.pos[0] = '\0'; + va_end(ap); + + printf("fmt: \"%s\"\nref: \"%s\"\nfrr: \"%s\"\n%s\n", fmt, ref, bufrr, strcmp(ref, bufrr) ? "ERROR" : "ok"); if (strcmp(ref, bufrr)) errors++; + if (strlen(bufrr) != expectlen) { + printf("return value <> length mismatch\n"); + errors++; + } + + for (size_t i = 0; i < fb.outpos_i; i++) + printf("\t[%zu: %u..%u] = \"%.*s\"\n", i, + outpos[i].off_start, + outpos[i].off_end, + (int)(outpos[i].off_end - outpos[i].off_start), + bufrr + outpos[i].off_start); + printf("\n"); + return 0; +} + +static void test_va(const char *ref, const char *fmt, ...) PRINTFRR(2, 3); +static void test_va(const char *ref, const char *fmt, ...) +{ + struct va_format vaf; + va_list ap; + + va_start(ap, fmt); + vaf.fmt = fmt; + vaf.va = ≈ + + printchk(ref, "VA [%pVA] %s", &vaf, "--"); + + va_end(ap); } int main(int argc, char **argv) @@ -112,9 +179,12 @@ int main(int argc, char **argv) inet_aton("192.168.1.2", &ip); printchk("192.168.1.2", "%pI4", &ip); printchk(" 192.168.1.2", "%20pI4", &ip); + printchk("192.168.1.2 ", "%-20pI4", &ip); printcmp("%p", &ip); + test_va("VA [192.168.1.2 1234] --", "%pI4 %u", &ip, 1234); + snprintfrr(buf, sizeof(buf), "test%s", "#1"); csnprintfrr(buf, sizeof(buf), "test%s", "#2"); assert(strcmp(buf, "test#1test#2") == 0); @@ -146,5 +216,42 @@ int main(int argc, char **argv) sg.src.s_addr = INADDR_ANY; printchk("(*,224.1.2.3)", "%pSG4", &sg); + uint8_t randhex[] = { 0x12, 0x34, 0x00, 0xca, 0xfe, 0x00, 0xaa, 0x55 }; + + FMT_NSTD(printchk("12 34 00 ca fe 00 aa 55", "%.8pHX", randhex)); + FMT_NSTD(printchk("12 34 00 ca fe 00 aa 55", "%.*pHX", + (int)sizeof(randhex), randhex)); + FMT_NSTD(printchk("12 34 00 ca", "%.4pHX", randhex)); + + printchk("12 34 00 ca fe 00 aa 55", "%8pHX", randhex); + printchk("12 34 00 ca fe 00 aa 55", "%*pHX", + (int)sizeof(randhex), randhex); + printchk("12 34 00 ca", "%4pHX", randhex); + + printchk("", "%pHX", randhex); + + printchk("12:34:00:ca:fe:00:aa:55", "%8pHXc", randhex); + printchk("123400cafe00aa55", "%8pHXn", randhex); + + printchk("/test/pa\\ th/\\~spe\\ncial\\x01/file.name", "%pSE", + "/test/pa th/~spe\ncial\x01/file.name"); + printchk("/test/pa\\ th/\\~spe\\n", "%17pSE", + "/test/pa th/~spe\ncial\x01/file.name"); + + char nulltest[] = { 'n', 'u', 0, 'l', 'l' }; + + printchk("nu\\x00ll", "%5pSE", nulltest); + printchk("nu\\x00ll", "%*pSE", 5, nulltest); + + printchk("bl\\\"ah\\x01te[st\\nab]c", "%pSQ", + "bl\"ah\x01te[st\nab]c"); + printchk("\"bl\\\"ah\\x01te[st\\nab]c\"", "%pSQq", + "bl\"ah\x01te[st\nab]c"); + printchk("\"bl\\\"ah\\x01te[st\\x0aab\\]c\"", "%pSQqs", + "bl\"ah\x01te[st\nab]c"); + printchk("\"\"", "%pSQqn", ""); + printchk("\"\"", "%pSQqn", (char *)NULL); + printchk("(null)", "%pSQq", (char *)NULL); + return !!errors; } diff --git a/tests/lib/test_table.c b/tests/lib/test_table.c index 290657bd56..9b6539e3bc 100644 --- a/tests/lib/test_table.c +++ b/tests/lib/test_table.c @@ -20,7 +20,7 @@ */ #include <zebra.h> - +#include "printfrr.h" #include "prefix.h" #include "table.h" @@ -113,7 +113,7 @@ static void print_subtree(struct route_node *rn, const char *legend, printf(" "); } - printf("%s: %pFX", legend, &rn->p); + printfrr("%s: %pFX", legend, &rn->p); if (!rn->info) { printf(" (internal)"); } 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 index 6cc23a465c..b38701a53d 100644 --- 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 @@ -3,6 +3,7 @@ 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 +RPKI validation codes: V valid, I invalid, N Not found 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 index 2f348a7b77..82b64c0d98 100644 --- 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 @@ -3,6 +3,7 @@ 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 +RPKI validation codes: V valid, I invalid, N Not found 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-post6.1.ref b/tests/topotests/all-protocol-startup/r1/show_bgp_ipv4-post6.1.ref index d36d045397..fd333b3084 100644 --- a/tests/topotests/all-protocol-startup/r1/show_bgp_ipv4-post6.1.ref +++ b/tests/topotests/all-protocol-startup/r1/show_bgp_ipv4-post6.1.ref @@ -4,6 +4,7 @@ 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 +RPKI validation codes: V valid, I invalid, N Not found 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_ipv6-post4.1.ref b/tests/topotests/all-protocol-startup/r1/show_bgp_ipv6-post4.1.ref index 8bb5da72be..20034b7408 100644 --- 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 @@ -3,6 +3,7 @@ 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 +RPKI validation codes: V valid, I invalid, N Not found Network Next Hop Metric LocPrf Weight Path *> fc00::/64 :: 0 32768 i diff --git a/tests/topotests/all-protocol-startup/r1/show_bgp_ipv6_post6.1.ref b/tests/topotests/all-protocol-startup/r1/show_bgp_ipv6_post6.1.ref index de91b247d8..5b5f8596cf 100644 --- a/tests/topotests/all-protocol-startup/r1/show_bgp_ipv6_post6.1.ref +++ b/tests/topotests/all-protocol-startup/r1/show_bgp_ipv6_post6.1.ref @@ -4,6 +4,7 @@ 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 +RPKI validation codes: V valid, I invalid, N Not found Network Next Hop Metric LocPrf Weight Path *> fc00::/64 :: 0 32768 i diff --git a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py index c858571254..c10e32ad0a 100644 --- a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py +++ b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py @@ -346,9 +346,9 @@ def test_converge_protocols(): print("Show that v4 routes are right\n") v4_routesFile = "%s/r%s/ipv4_routes.ref" % (thisDir, i) - expected = net["r%s" % i].cmd( - "sort {} 2> /dev/null".format(v4_routesFile) - ).rstrip() + expected = ( + net["r%s" % i].cmd("sort {} 2> /dev/null".format(v4_routesFile)).rstrip() + ) expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1) actual = ( @@ -379,9 +379,9 @@ def test_converge_protocols(): print("Show that v6 routes are right\n") v6_routesFile = "%s/r%s/ipv6_routes.ref" % (thisDir, i) - expected = net["r%s" % i].cmd( - "sort {} 2> /dev/null".format(v6_routesFile) - ).rstrip() + expected = ( + net["r%s" % i].cmd("sort {} 2> /dev/null".format(v6_routesFile)).rstrip() + ) expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1) actual = ( diff --git a/tests/topotests/bfd-profiles-topo1/r1/bfd-peers-initial.json b/tests/topotests/bfd-profiles-topo1/r1/bfd-peers-initial.json index bab24c4fa0..86a7e5139c 100644 --- a/tests/topotests/bfd-profiles-topo1/r1/bfd-peers-initial.json +++ b/tests/topotests/bfd-profiles-topo1/r1/bfd-peers-initial.json @@ -6,14 +6,14 @@ "interface": "r1-eth1", "multihop": false, "peer": "172.16.100.2", - "receive-interval": 300, + "receive-interval": 800, "remote-detect-multiplier": 3, "remote-diagnostic": "ok", "remote-id": "*", "remote-receive-interval": 300, "remote-transmit-interval": 300, "status": "up", - "transmit-interval": 300, + "transmit-interval": 800, "uptime": "*", "vrf": "default" }, diff --git a/tests/topotests/bfd-profiles-topo1/r1/ospfd.conf b/tests/topotests/bfd-profiles-topo1/r1/ospfd.conf index 4798d17c40..fcea5d48fc 100644 --- a/tests/topotests/bfd-profiles-topo1/r1/ospfd.conf +++ b/tests/topotests/bfd-profiles-topo1/r1/ospfd.conf @@ -2,7 +2,7 @@ interface r1-eth1 ip ospf area 0 ip ospf hello-interval 2 ip ospf dead-interval 10 - ip ospf bfd + ip ospf bfd profile slowtx ! router ospf ospf router-id 10.254.254.1 diff --git a/tests/topotests/bfd-profiles-topo1/r6/bfd-peers-initial.json b/tests/topotests/bfd-profiles-topo1/r6/bfd-peers-initial.json index 4e6fa869ba..ec973eb365 100644 --- a/tests/topotests/bfd-profiles-topo1/r6/bfd-peers-initial.json +++ b/tests/topotests/bfd-profiles-topo1/r6/bfd-peers-initial.json @@ -10,8 +10,8 @@ "remote-detect-multiplier": 3, "remote-diagnostic": "ok", "remote-id": "*", - "remote-receive-interval": 300, - "remote-transmit-interval": 300, + "remote-receive-interval": 800, + "remote-transmit-interval": 800, "status": "up", "transmit-interval": 300, "uptime": "*", diff --git a/tests/topotests/bgp-default-ipv4-ipv6-unicast/__init__.py b/tests/topotests/bgp-default-ipv4-ipv6-unicast/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp-default-ipv4-ipv6-unicast/__init__.py diff --git a/tests/topotests/bgp-default-ipv4-ipv6-unicast/r1/bgpd.conf b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r1/bgpd.conf new file mode 100644 index 0000000000..bf39152ea8 --- /dev/null +++ b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r1/bgpd.conf @@ -0,0 +1,3 @@ +! +router bgp 65001 +! diff --git a/tests/topotests/bgp-default-ipv4-ipv6-unicast/r1/zebra.conf b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r1/zebra.conf new file mode 100644 index 0000000000..697765168d --- /dev/null +++ b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r1/zebra.conf @@ -0,0 +1,7 @@ +! +interface r1-eth0 + ip address 192.168.255.1/24 +! +ip forwarding +! + diff --git a/tests/topotests/bgp-default-ipv4-ipv6-unicast/r2/bgpd.conf b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r2/bgpd.conf new file mode 100644 index 0000000000..abbd1b86fa --- /dev/null +++ b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r2/bgpd.conf @@ -0,0 +1,5 @@ +! +router bgp 65001 + no bgp default ipv4-unicast + bgp default ipv6-unicast +! diff --git a/tests/topotests/bgp-default-ipv4-ipv6-unicast/r2/zebra.conf b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r2/zebra.conf new file mode 100644 index 0000000000..606c17bec9 --- /dev/null +++ b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r2/zebra.conf @@ -0,0 +1,6 @@ +! +interface r2-eth0 + ip address 192.168.255.2/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp-default-ipv4-ipv6-unicast/r3/bgpd.conf b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r3/bgpd.conf new file mode 100644 index 0000000000..a405c047ca --- /dev/null +++ b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r3/bgpd.conf @@ -0,0 +1,4 @@ +! +router bgp 65001 + bgp default ipv6-unicast +! diff --git a/tests/topotests/bgp-default-ipv4-ipv6-unicast/r3/zebra.conf b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r3/zebra.conf new file mode 100644 index 0000000000..e9fdfb70c5 --- /dev/null +++ b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r3/zebra.conf @@ -0,0 +1,6 @@ +! +interface r3-eth0 + ip address 192.168.255.3/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp-default-ipv4-ipv6-unicast/test_bgp-default-ipv4-ipv6-unicast.py b/tests/topotests/bgp-default-ipv4-ipv6-unicast/test_bgp-default-ipv4-ipv6-unicast.py new file mode 100644 index 0000000000..c1dbf0ebec --- /dev/null +++ b/tests/topotests/bgp-default-ipv4-ipv6-unicast/test_bgp-default-ipv4-ipv6-unicast.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python + +# +# Copyright (c) 2021 by +# Donatas Abraitis <donatas.abraitis@gmail.com> +# +# 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 if `bgp default ipv4-unicast` and `bgp default ipv6-unicast` +commands work as expected. + +STEP 1: 'Check if neighbor 192.168.255.254 is enabled for ipv4 address-family only' +STEP 2: 'Check if neighbor 192.168.255.254 is enabled for ipv6 address-family only' +STEP 3: 'Check if neighbor 192.168.255.254 is enabled for ipv4 and ipv6 address-families' +""" + +import os +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger +from mininet.topo import Topo +from lib.common_config import step + + +class TemplateTopo(Topo): + def build(self, *_args, **_opts): + tgen = get_topogen(self) + + 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.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["r4"]) + + +def setup_module(mod): + tgen = Topogen(TemplateTopo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for i, (rname, router) in enumerate(router_list.items(), 1): + 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)) + ) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_default_ipv4_ipv6_unicast(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + step("Check if neighbor 192.168.255.254 is enabled for ipv4 address-family only") + + def _bgp_neighbor_ipv4_af_only(): + tgen.gears["r1"].vtysh_cmd( + "conf t\nrouter bgp\nneighbor 192.168.255.254 remote-as external" + ) + + output = json.loads(tgen.gears["r1"].vtysh_cmd("show bgp summary json")) + + if "ipv4Unicast" in output and "ipv6Unicast" not in output: + return True + return False + + assert _bgp_neighbor_ipv4_af_only() == True + + step("Check if neighbor 192.168.255.254 is enabled for ipv6 address-family only") + + def _bgp_neighbor_ipv6_af_only(): + tgen.gears["r2"].vtysh_cmd( + "conf t\nrouter bgp\nneighbor 192.168.255.254 remote-as external" + ) + + output = json.loads(tgen.gears["r2"].vtysh_cmd("show bgp summary json")) + + if "ipv4Unicast" not in output and "ipv6Unicast" in output: + return True + return False + + assert _bgp_neighbor_ipv6_af_only() == True + + step( + "Check if neighbor 192.168.255.254 is enabled for ipv4 and ipv6 address-families" + ) + + def _bgp_neighbor_ipv4_and_ipv6_af(): + tgen.gears["r3"].vtysh_cmd( + "conf t\nrouter bgp\nneighbor 192.168.255.254 remote-as external" + ) + + output = json.loads(tgen.gears["r3"].vtysh_cmd("show bgp summary json")) + + if "ipv4Unicast" in output and "ipv6Unicast" in output: + return True + return False + + assert _bgp_neighbor_ipv4_and_ipv6_af() == True + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp-ebgp-common-subnet-nexthop-unchanged/__init__.py b/tests/topotests/bgp-ebgp-common-subnet-nexthop-unchanged/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp-ebgp-common-subnet-nexthop-unchanged/__init__.py diff --git a/tests/topotests/bgp-ebgp-common-subnet-nexthop-unchanged/r1/bgpd.conf b/tests/topotests/bgp-ebgp-common-subnet-nexthop-unchanged/r1/bgpd.conf new file mode 100644 index 0000000000..c320bb5d11 --- /dev/null +++ b/tests/topotests/bgp-ebgp-common-subnet-nexthop-unchanged/r1/bgpd.conf @@ -0,0 +1,7 @@ +router bgp 65001 + no bgp ebgp-requires-policy + neighbor 192.168.1.101 remote-as external + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/bgp-ebgp-common-subnet-nexthop-unchanged/r1/zebra.conf b/tests/topotests/bgp-ebgp-common-subnet-nexthop-unchanged/r1/zebra.conf new file mode 100644 index 0000000000..1782edc2a5 --- /dev/null +++ b/tests/topotests/bgp-ebgp-common-subnet-nexthop-unchanged/r1/zebra.conf @@ -0,0 +1,7 @@ +! +int lo + ip address 172.16.1.1/32 +! +int r1-eth0 + ip address 192.168.1.1/24 +! diff --git a/tests/topotests/bgp-ebgp-common-subnet-nexthop-unchanged/r2/bgpd.conf b/tests/topotests/bgp-ebgp-common-subnet-nexthop-unchanged/r2/bgpd.conf new file mode 100644 index 0000000000..cb712e9a8d --- /dev/null +++ b/tests/topotests/bgp-ebgp-common-subnet-nexthop-unchanged/r2/bgpd.conf @@ -0,0 +1,3 @@ +router bgp 65103 + no bgp ebgp-requires-policy + neighbor 192.168.1.101 remote-as external diff --git a/tests/topotests/bgp-ebgp-common-subnet-nexthop-unchanged/r2/zebra.conf b/tests/topotests/bgp-ebgp-common-subnet-nexthop-unchanged/r2/zebra.conf new file mode 100644 index 0000000000..968171e7b9 --- /dev/null +++ b/tests/topotests/bgp-ebgp-common-subnet-nexthop-unchanged/r2/zebra.conf @@ -0,0 +1,4 @@ +! +int r2-eth0 + ip address 192.168.1.103/24 +! diff --git a/tests/topotests/bgp-ebgp-common-subnet-nexthop-unchanged/r3/bgpd.conf b/tests/topotests/bgp-ebgp-common-subnet-nexthop-unchanged/r3/bgpd.conf new file mode 100644 index 0000000000..a6e3260d15 --- /dev/null +++ b/tests/topotests/bgp-ebgp-common-subnet-nexthop-unchanged/r3/bgpd.conf @@ -0,0 +1,5 @@ +router bgp 65000 + bgp router-id 192.168.1.101 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as external + neighbor 192.168.1.103 remote-as external diff --git a/tests/topotests/bgp-ebgp-common-subnet-nexthop-unchanged/r3/zebra.conf b/tests/topotests/bgp-ebgp-common-subnet-nexthop-unchanged/r3/zebra.conf new file mode 100644 index 0000000000..ddcf862132 --- /dev/null +++ b/tests/topotests/bgp-ebgp-common-subnet-nexthop-unchanged/r3/zebra.conf @@ -0,0 +1,4 @@ +! +int r3-eth0 + ip address 192.168.1.101/24 +! diff --git a/tests/topotests/bgp-ebgp-common-subnet-nexthop-unchanged/test_bgp-ebgp-common-subnet-nexthop-unchanged.py b/tests/topotests/bgp-ebgp-common-subnet-nexthop-unchanged/test_bgp-ebgp-common-subnet-nexthop-unchanged.py new file mode 100644 index 0000000000..19c4c5f87d --- /dev/null +++ b/tests/topotests/bgp-ebgp-common-subnet-nexthop-unchanged/test_bgp-ebgp-common-subnet-nexthop-unchanged.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python + +# Copyright (c) 2021 by +# Donatas Abraitis <donatas.abraitis@gmail.com> +# +# 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. +# + +""" +https://tools.ietf.org/html/rfc4271 + +Check if NEXT_HOP attribute is not changed if peer X shares a +common subnet with this address. + +- Otherwise, if the route being announced was learned from an + external peer, the speaker can use an IP address of any + adjacent router (known from the received NEXT_HOP attribute) + that the speaker itself uses for local route calculation in + the NEXT_HOP attribute, provided that peer X shares a common + subnet with this address. This is a second form of "third + party" NEXT_HOP attribute. +""" + +import os +import sys +import json +import time +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger +from mininet.topo import Topo + + +class TemplateTopo(Topo): + def build(self, *_args, **_opts): + tgen = get_topogen(self) + + for routern in range(1, 4): + tgen.add_router("r{}".format(routern)) + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["r3"]) + + +def setup_module(mod): + tgen = Topogen(TemplateTopo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for i, (rname, router) in enumerate(router_list.items(), 1): + 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)) + ) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_ebgp_common_subnet_nh_unchanged(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r2 = tgen.gears["r2"] + r3 = tgen.gears["r3"] + + def _bgp_converge(router): + output = json.loads(router.vtysh_cmd("show ip bgp summary json")) + expected = { + "ipv4Unicast": { + "peers": { + "192.168.1.1": {"state": "Established"}, + "192.168.1.103": {"state": "Established"}, + } + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_converge, r3) + success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + + assert result is None, 'Failed bgp convergence in "{}"'.format(r3) + + def _bgp_nh_unchanged(router): + output = json.loads(router.vtysh_cmd("show ip bgp 172.16.1.1/32 json")) + expected = {"paths": [{"nexthops": [{"ip": "192.168.1.1"}]}]} + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_nh_unchanged, r2) + success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + + assert result is None, 'Wrong next-hop in "{}"'.format(r2) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp-ecmp-topo1/test_bgp_ecmp_topo1.py b/tests/topotests/bgp-ecmp-topo1/test_bgp_ecmp_topo1.py index 400e7e9bf5..75506d1a51 100644 --- a/tests/topotests/bgp-ecmp-topo1/test_bgp_ecmp_topo1.py +++ b/tests/topotests/bgp-ecmp-topo1/test_bgp_ecmp_topo1.py @@ -45,6 +45,10 @@ from lib.topolog import logger # Required to instantiate the topology builder class. from mininet.topo import Topo + +pytestmark = [pytest.mark.bgpd] + + total_ebgp_peers = 20 ##################################################### diff --git a/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py b/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py index dfe6a8074d..fffcbbd0ef 100644 --- a/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py +++ b/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py @@ -67,6 +67,10 @@ from lib.topolog import logger from lib.bgp import verify_bgp_convergence, create_router_bgp, clear_bgp from lib.topojson import build_topo_from_json, build_config_from_json + +pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] + + # Reading the data from JSON File for topology and configuration creation jsonFile = "{}/ebgp_ecmp_topo2.json".format(CWD) diff --git a/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py b/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py index 2bde52af1d..342a0a4b2f 100644 --- a/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py +++ b/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py @@ -67,6 +67,10 @@ from lib.topolog import logger from lib.bgp import verify_bgp_convergence, create_router_bgp, clear_bgp from lib.topojson import build_topo_from_json, build_config_from_json + +pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] + + # Reading the data from JSON File for topology and configuration creation jsonFile = "{}/ibgp_ecmp_topo2.json".format(CWD) diff --git a/tests/topotests/bgp-evpn-mh/test_evpn_mh.py b/tests/topotests/bgp-evpn-mh/test_evpn_mh.py index 2744920272..f389632b1e 100644 --- a/tests/topotests/bgp-evpn-mh/test_evpn_mh.py +++ b/tests/topotests/bgp-evpn-mh/test_evpn_mh.py @@ -35,7 +35,7 @@ import json import platform from functools import partial -pytestmark = [pytest.mark.pimd] +pytestmark = [pytest.mark.bgpd, pytest.mark.pimd] # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) diff --git a/tests/topotests/bgp-snmp-mplsl3vpn/test_bgp_snmp_mplsvpn.py b/tests/topotests/bgp-snmp-mplsl3vpn/test_bgp_snmp_mplsvpn.py index db4eab9d3d..b830e16b9a 100755 --- a/tests/topotests/bgp-snmp-mplsl3vpn/test_bgp_snmp_mplsvpn.py +++ b/tests/topotests/bgp-snmp-mplsl3vpn/test_bgp_snmp_mplsvpn.py @@ -505,8 +505,10 @@ def test_r1_mplsvpn_VrfTable(): associated_int = r1_snmp.get( "mplsL3VpnVrfAssociatedInterfaces.{}".format(snmp_str_to_oid("VRF-a")) ) - assertmsg = "mplsL3VpnVrfAssociatedInterfaces incorrect should be 3 value {}".format( - associated_int + assertmsg = ( + "mplsL3VpnVrfAssociatedInterfaces incorrect should be 3 value {}".format( + associated_int + ) ) assert associated_int == "3", assertmsg diff --git a/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py b/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py index 222478f12d..320e6d430c 100644 --- a/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py +++ b/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py @@ -42,13 +42,11 @@ sys.path.append(os.path.join(CWD, "../")) from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger +from lib.common_config import adjust_router_l3mdev # Required to instantiate the topology builder class. from mininet.topo import Topo -l3mdev_accept = 0 -krel = "" - class BGPEVPNTopo(Topo): "Test topology builder" @@ -73,8 +71,6 @@ class BGPEVPNTopo(Topo): def setup_module(mod): "Sets up the pytest environment" - global l3mdev_accept - global krel tgen = Topogen(BGPEVPNTopo, mod.__name__) tgen.start_topology() @@ -90,18 +86,13 @@ def setup_module(mod): ) return pytest.skip("Skipping BGP EVPN RT5 NETNS Test. Kernel not supported") - l3mdev_accept = 1 - logger.info("setting net.ipv4.tcp_l3mdev_accept={}".format(l3mdev_accept)) - # create VRF vrf-101 on R1 and R2 # create loop101 cmds_vrflite = [ - "sysctl -w net.ipv4.tcp_l3mdev_accept={}".format(l3mdev_accept), "ip link add {}-vrf-101 type vrf table 101", "ip ru add oif {}-vrf-101 table 101", "ip ru add iif {}-vrf-101 table 101", "ip link set dev {}-vrf-101 up", - "sysctl -w net.ipv4.tcp_l3mdev_accept={}".format(l3mdev_accept), "ip link add loop101 type dummy", "ip link set dev loop101 master {}-vrf-101", "ip link set dev loop101 up", @@ -139,6 +130,7 @@ def setup_module(mod): logger.info("result: " + output) router = tgen.gears["r2"] + adjust_router_l3mdev(tgen, "r2") for cmd in cmds_vrflite: logger.info("cmd to r2: " + cmd.format("r2")) output = router.run(cmd.format("r2")) diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py index a6338d0c70..b70626fcce 100644 --- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py +++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py @@ -258,10 +258,12 @@ def configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut, peer): assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) for addr_type in ADDR_TYPES: - clear_bgp(tgen, addr_type, dut) + neighbor = topo["routers"][peer]["links"]["r1-link1"][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, dut, neighbor=neighbor) for addr_type in ADDR_TYPES: - clear_bgp(tgen, addr_type, peer) + neighbor = topo["routers"][dut]["links"]["r2-link1"][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, peer, neighbor=neighbor) result = verify_bgp_convergence_from_running_config(tgen) assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) @@ -551,7 +553,7 @@ def test_BGP_GR_TC_46_p1(request): write_test_footer(tc_name) -def test_BGP_GR_TC_50_p1(request): +def BGP_GR_TC_50_p1(request): """ Test Objective : Transition from Peer-level helper to Global inherit helper Global Mode : None @@ -613,9 +615,6 @@ def test_BGP_GR_TC_50_p1(request): configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") - result = verify_bgp_convergence_from_running_config(tgen) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - step("Verify on R2 that R1 advertises GR capabilities as a helper node") for addr_type in ADDR_TYPES: @@ -721,7 +720,12 @@ def test_BGP_GR_TC_50_p1(request): } } - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + for addr_type in ADDR_TYPES: + neighbor = topo["routers"]["r2"]["links"]["r1-link1"][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, "r1", neighbor=neighbor) result = verify_bgp_convergence_from_running_config(tgen) assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) @@ -979,7 +983,15 @@ def test_BGP_GR_TC_51_p1(request): } } - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + for addr_type in ADDR_TYPES: + neighbor = topo["routers"]["r2"]["links"]["r1-link1"][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, "r1", neighbor=neighbor) + + result = verify_bgp_convergence_from_running_config(tgen) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step("Verify on R2 that R1 advertises GR capabilities as a helper node") @@ -1317,20 +1329,22 @@ def test_BGP_GR_TC_4_p0(request): result = verify_bgp_rib( tgen, addr_type, dut, input_topo, next_hop, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) logger.info(" Expected behavior: {}".format(result)) logger.info("[Phase 5] : R2 is about to come up now ") @@ -1695,10 +1709,10 @@ def test_BGP_GR_TC_6_1_2_p1(request): assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) for addr_type in ADDR_TYPES: - clear_bgp(tgen, addr_type, "r1") - clear_bgp(tgen, addr_type, "r2") + neighbor = topo["routers"]["r2"]["links"]["r1-link1"][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, "r1", neighbor=neighbor) - result = verify_bgp_convergence_from_running_config(tgen, topo) + result = verify_bgp_convergence_from_running_config(tgen) assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) # Verify GR stats @@ -1790,10 +1804,11 @@ def test_BGP_GR_TC_6_1_2_p1(request): result = verify_r_bit( tgen, topo, addr_type, input_dict, dut="r2", peer="r1", expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r2: R-bit is set to True\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r2: R-bit is set to True\n Error: {}".format( tc_name, result - )) + ) logger.info("Restart BGPd on R2 ") kill_router_daemons(tgen, "r2", ["bgpd"]) @@ -1811,10 +1826,11 @@ def test_BGP_GR_TC_6_1_2_p1(request): result = verify_r_bit( tgen, topo, addr_type, input_dict, dut="r2", peer="r1", expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r2: R-bit is set to True\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r2: R-bit is set to True\n Error: {}".format( tc_name, result - )) + ) write_test_footer(tc_name) @@ -2096,20 +2112,22 @@ def test_BGP_GR_TC_17_p1(request): result = verify_bgp_rib( tgen, addr_type, dut, input_topo, next_hop, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) logger.info(" Expected behavior: {}".format(result)) logger.info("[Phase 5] : R2 is about to come up now ") @@ -2128,10 +2146,11 @@ def test_BGP_GR_TC_17_p1(request): result = verify_r_bit( tgen, topo, addr_type, input_dict, dut="r1", peer="r2", expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: R-bit is set to True\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: R-bit is set to True\n Error: {}".format( tc_name, result - )) + ) # Verifying BGP RIB routes next_hop = next_hop_per_address_family( @@ -2457,20 +2476,22 @@ def test_BGP_GR_TC_20_p1(request): result = verify_bgp_rib( tgen, addr_type, dut, input_topo, next_hop, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) logger.info(" Expected behavior: {}".format(result)) logger.info("[Phase 5] : R2 is about to come up now ") @@ -2651,10 +2672,10 @@ def test_BGP_GR_TC_31_1_p1(request): assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) for addr_type in ADDR_TYPES: - clear_bgp(tgen, addr_type, "r1") - clear_bgp(tgen, addr_type, "r2") + neighbor = topo["routers"]["r2"]["links"]["r1-link1"][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, "r1", neighbor=neighbor) - result = verify_bgp_convergence_from_running_config(tgen, topo) + result = verify_bgp_convergence_from_running_config(tgen) assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) # Verify GR stats @@ -2743,10 +2764,10 @@ def test_BGP_GR_TC_31_1_p1(request): result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) logger.info("[Phase 4] : R1 is about to come up now ") start_router_daemons(tgen, "r1", ["bgpd"]) @@ -2932,10 +2953,10 @@ def test_BGP_GR_TC_31_2_p1(request): assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) for addr_type in ADDR_TYPES: - clear_bgp(tgen, addr_type, "r1") - clear_bgp(tgen, addr_type, "r2") + neighbor = topo["routers"]["r2"]["links"]["r1-link1"][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, "r1", neighbor=neighbor) - result = verify_bgp_convergence_from_running_config(tgen, topo) + result = verify_bgp_convergence_from_running_config(tgen) assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) # Verify GR stats @@ -3225,10 +3246,12 @@ def test_BGP_GR_TC_9_p1(request): result = verify_bgp_rib( tgen, addr_type, dut, input_topo, next_hop, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes @@ -3236,10 +3259,10 @@ def test_BGP_GR_TC_9_p1(request): result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) logger.info(" Expected behavior: {}".format(result)) logger.info("[Phase 5] : R2 is about to come up now ") @@ -3269,10 +3292,11 @@ def test_BGP_GR_TC_9_p1(request): result = verify_f_bit( tgen, topo, addr_type, input_dict, dut="r1", peer="r2", expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: F-bit is set to True\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: F-bit is set to True\n Error: {}".format( tc_name, result - )) + ) write_test_footer(tc_name) @@ -3404,10 +3428,12 @@ def test_BGP_GR_TC_17_p1(request): result = verify_bgp_rib( tgen, addr_type, dut, input_topo, next_hop, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes @@ -3415,10 +3441,10 @@ def test_BGP_GR_TC_17_p1(request): result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) logger.info(" Expected behavior: {}".format(result)) logger.info("[Phase 5] : R2 is about to come up now ") @@ -3440,10 +3466,11 @@ def test_BGP_GR_TC_17_p1(request): result = verify_r_bit( tgen, topo, addr_type, input_dict, dut="r1", peer="r2", expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: R-bit is set to True\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: R-bit is set to True\n Error: {}".format( tc_name, result - )) + ) # Verifying BGP RIB routes next_hop = next_hop_per_address_family( @@ -3663,10 +3690,12 @@ def test_BGP_GR_TC_43_p1(request): result = verify_bgp_rib( tgen, addr_type, dut, input_topo, next_hop, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r2: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) protocol = "bgp" result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False @@ -3971,10 +4000,12 @@ def test_BGP_GR_TC_44_p1(request): result = verify_bgp_rib( tgen, addr_type, dut, input_topo, next_hop, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False ) @@ -4999,10 +5030,10 @@ def test_BGP_GR_TC_48_p1(request): result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) dut = "r2" peer = "r1" @@ -5013,17 +5044,19 @@ def test_BGP_GR_TC_48_p1(request): result = verify_bgp_rib( tgen, addr_type, dut, input_topo, next_hop, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r2: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r2: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r2: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) step("Bring up BGP on R1 and remove Peer-level GR config from R1") @@ -5258,7 +5291,7 @@ def test_BGP_GR_TC_49_p1(request): write_test_footer(tc_name) -def test_BGP_GR_TC_52_p1(request): +def BGP_GR_TC_52_p1(request): """ Test Objective : Transition from Peer-level disbale to Global inherit helper Global Mode : None @@ -5382,17 +5415,19 @@ def test_BGP_GR_TC_52_p1(request): result = verify_bgp_rib( tgen, addr_type, dut, input_topo, next_hop, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) result = verify_rib( tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) step("Bring up BGP on R2 and remove Peer-level GR config from R1") diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py index 2c5dd92f54..9438b90ef8 100644 --- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py +++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py @@ -251,12 +251,14 @@ def configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut, peer): assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) for addr_type in ADDR_TYPES: - clear_bgp(tgen, addr_type, dut) + neighbor = topo["routers"][peer]["links"][dut][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, dut, neighbor=neighbor) for addr_type in ADDR_TYPES: - clear_bgp(tgen, addr_type, peer) + neighbor = topo["routers"][dut]["links"][peer][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, peer, neighbor=neighbor) - result = verify_bgp_convergence_from_running_config(tgen, topo) + result = verify_bgp_convergence_from_running_config(tgen) assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) return True @@ -555,10 +557,11 @@ def test_BGP_GR_TC_3_p0(request): result = verify_eor( tgen, topo, addr_type, input_dict, dut="r2", peer="r1", expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r2: EOR is set to True\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r2: EOR is set to True\n Error: {}".format( tc_name, result - )) + ) logger.info( "Waiting for selection deferral timer({} sec)..".format(GR_SELECT_DEFER_TIMER) @@ -701,10 +704,11 @@ def test_BGP_GR_TC_11_p0(request): result = verify_eor( tgen, topo, addr_type, input_dict, dut="r1", peer="r3", expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: EOR is set to True\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: EOR is set to True\n Error: {}".format( tc_name, result - )) + ) logger.info( "Waiting for selection deferral timer({} sec).. ".format( @@ -731,10 +735,11 @@ def test_BGP_GR_TC_11_p0(request): result = verify_eor( tgen, topo, addr_type, input_dict, dut="r3", peer="r1", expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r3: EOR is set to True\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r3: EOR is set to True\n Error: {}".format( tc_name, result - )) + ) write_test_footer(tc_name) @@ -930,7 +935,7 @@ def test_BGP_GR_10_p2(request): write_test_footer(tc_name) -def test_BGP_GR_16_p2(request): +def BGP_GR_16_p2(request): """ Test Objective : Verify BGP-GR feature when restarting node is a transit router for it's iBGP peers. @@ -1468,35 +1473,39 @@ def test_BGP_GR_18_p1(request): dut = "r6" input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r6: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes before shutting down BGPd daemon result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r6: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r6: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying BGP RIB routes dut = "r2" result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r2: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes before shutting down BGPd daemon result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r6: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r6: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) logger.info(" Expected behavior: {}".format(result)) write_test_footer(tc_name) @@ -1957,18 +1966,20 @@ def test_BGP_GR_chaos_29_p1(request): # Verifying BGP RIB routes before shutting down BGPd daemon input_dict = {key: topo["routers"][key] for key in ["r1"]} result = verify_bgp_rib(tgen, addr_type, dut, input_dict, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes before shutting down BGPd daemon result = verify_rib(tgen, addr_type, dut, input_dict, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r3: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r3: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) logger.info(" Expected behavior: {}".format(result)) logger.info("[Step 4] : Start BGPd daemon on R1..") @@ -2210,10 +2221,12 @@ def test_BGP_GR_chaos_33_p1(request): result = verify_rib( tgen, addr_type, dut, input_dict_2, next_hop_4, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info(" Expected behavior: {}".format(result)) if addr_type == "ipv6": @@ -2225,10 +2238,12 @@ def test_BGP_GR_chaos_33_p1(request): result = verify_rib( tgen, addr_type, dut, input_dict_2, next_hop_6, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info(" Expected behavior: {}".format(result)) logger.info("[Step 4] : Start BGPd daemon on R1 and R4..") @@ -2409,27 +2424,30 @@ def test_BGP_GR_chaos_34_2_p1(request): result = verify_f_bit( tgen, topo, addr_type, input_dict, "r3", "r1", expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r3: F-bit is set to True\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r3: F-bit is set to True\n Error: {}".format( tc_name, result - )) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying BGP RIB routes after starting BGPd daemon input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r3: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r3: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) logger.info(" Expected behavior: {}".format(result)) write_test_footer(tc_name) @@ -2566,10 +2584,11 @@ def test_BGP_GR_chaos_34_1_p1(request): result = verify_f_bit( tgen, topo, addr_type, input_dict_2, "r3", "r1", expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r3: F-bit is set to True\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r3: F-bit is set to True\n Error: {}".format( tc_name, result - )) + ) logger.info(" Expected behavior: {}".format(result)) logger.info("[Step 3] : Kill BGPd daemon on R1..") @@ -2585,18 +2604,20 @@ def test_BGP_GR_chaos_34_1_p1(request): # Verifying BGP RIB routes input_dict = {key: topo["routers"][key] for key in ["r1"]} result = verify_bgp_rib(tgen, addr_type, dut, input_dict, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes result = verify_rib(tgen, addr_type, dut, input_dict, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r3: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r3: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) logger.info(" Expected behavior: {}".format(result)) # Start BGPd daemon on R1 @@ -2770,27 +2791,30 @@ def test_BGP_GR_chaos_32_p1(request): result = verify_eor( tgen, topo, addr_type, input_dict_3, dut="r5", peer="r1", expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r5: EOR is set to TRUE\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r5: EOR is set to TRUE\n Error: {}".format( tc_name, result - )) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying BGP RIB routes after starting BGPd daemon input_dict_1 = {key: topo["routers"][key] for key in ["r5"]} result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r3: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r3: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) logger.info(" Expected behavior: {}".format(result)) write_test_footer(tc_name) @@ -2896,10 +2920,11 @@ def test_BGP_GR_chaos_37_p1(request): result = verify_eor( tgen, topo, addr_type, input_dict, dut="r3", peer="r1", expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r3: EOR is set to True\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r3: EOR is set to True\n Error: {}".format( tc_name, result - )) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying BGP RIB routes after starting BGPd daemon @@ -2962,10 +2987,11 @@ def test_BGP_GR_chaos_37_p1(request): result = verify_eor( tgen, topo, addr_type, input_dict_3, dut="r1", peer="r3", expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: EOR is set to True\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: EOR is set to True\n Error: {}".format( tc_name, result - )) + ) write_test_footer(tc_name) @@ -3117,18 +3143,20 @@ def test_BGP_GR_chaos_30_p1(request): # Verifying BGP RIB routes before shutting down BGPd daemon input_dict = {key: topo["routers"][key] for key in ["r3"]} result = verify_bgp_rib(tgen, addr_type, dut, input_dict, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes before shutting down BGPd daemon result = verify_rib(tgen, addr_type, dut, input_dict, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) logger.info(" Expected behavior: {}".format(result)) write_test_footer(tc_name) @@ -3530,10 +3558,10 @@ def BGP_GR_TC_7_p1(request): dut = "r1" input_dict_1 = {key: topo["routers"][key] for key in ["r3"]} result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) write_test_footer(tc_name) @@ -3707,10 +3735,11 @@ def test_BGP_GR_TC_23_p1(request): result = verify_eor( tgen, topo, addr_type, input_dict, dut="r1", peer="r2", expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: EOR is set to True\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: EOR is set to True\n Error: {}".format( tc_name, result - )) + ) # Verifying BGP RIB routes received from router R1 dut = "r1" @@ -3831,18 +3860,20 @@ def test_BGP_GR_20_p1(request): dut = "r3" input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info(" Expected behavior: {}".format(result)) # Verifying RIB routes before shutting down BGPd daemon result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r3: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r3: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) logger.info(" Expected behavior: {}".format(result)) # Start BGPd daemon on R1 diff --git a/tests/topotests/bgp_instance_del_test/test_bgp_instance_del_test.py b/tests/topotests/bgp_instance_del_test/test_bgp_instance_del_test.py index 47cc0eb39d..0c7e84a5a3 100755 --- a/tests/topotests/bgp_instance_del_test/test_bgp_instance_del_test.py +++ b/tests/topotests/bgp_instance_del_test/test_bgp_instance_del_test.py @@ -30,6 +30,9 @@ sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../") from lib.ltemplate import * +pytestmark = [pytest.mark.bgpd, pytest.mark.ldpd, pytest.mark.ospfd] + + def test_check_linux_vrf(): CliOnFail = None # For debugging, uncomment the next line diff --git a/tests/topotests/bgp_ipv6_rtadv/test_bgp_ipv6_rtadv.py b/tests/topotests/bgp_ipv6_rtadv/test_bgp_ipv6_rtadv.py index 783e746418..cd845be296 100644 --- a/tests/topotests/bgp_ipv6_rtadv/test_bgp_ipv6_rtadv.py +++ b/tests/topotests/bgp_ipv6_rtadv/test_bgp_ipv6_rtadv.py @@ -46,6 +46,9 @@ from lib.topolog import logger from mininet.topo import Topo +pytestmark = [pytest.mark.bgpd] + + class BGPIPV6RTADVTopo(Topo): "Test topology builder" diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py index 1c3c51f68e..5d97537bd0 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py @@ -84,6 +84,7 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger from lib.ltemplate import ltemplateRtrCmd +from lib.common_config import adjust_router_l3mdev # Required to instantiate the topology builder class. from mininet.topo import Topo @@ -145,26 +146,12 @@ class ThisTestTopo(Topo): switch[1].add_link(tgen.gears["r3"], nodeif="r3-eth1") -l3mdev_accept = 0 - - def ltemplatePreRouterStartHook(): - global l3mdev_accept cc = ltemplateRtrCmd() krel = platform.release() tgen = get_topogen() logger.info("pre router-start hook, kernel=" + krel) - if ( - topotest.version_cmp(krel, "4.15") >= 0 - and topotest.version_cmp(krel, "4.18") <= 0 - ): - l3mdev_accept = 1 - - if topotest.version_cmp(krel, "5.0") >= 0: - l3mdev_accept = 1 - - 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") @@ -187,10 +174,11 @@ def ltemplatePreRouterStartHook(): "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.tcp_l3mdev_accept={}".format(l3mdev_accept), ] for rtr in rtrs: - router = tgen.gears[rtr] + # adjust handling of VRF traffic + adjust_router_l3mdev(tgen, 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)) @@ -229,9 +217,11 @@ def ltemplatePreRouterStartHook(): "ip ru add oif {0}-cust2 table 20", "ip ru add iif {0}-cust2 table 20", "ip link set dev {0}-cust2 up", - "sysctl -w net.ipv4.tcp_l3mdev_accept={}".format(l3mdev_accept), ] for rtr in rtrs: + # adjust handling of VRF traffic + adjust_router_l3mdev(tgen, rtr) + for cmd in cmds: cc.doCmd(tgen, rtr, cmd.format(rtr)) cc.doCmd(tgen, rtr, "ip link set dev {0}-eth0 master {0}-cust2".format(rtr)) 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 index 7c154ecd15..650ba20b8c 100644 --- 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 @@ -1,6 +1,7 @@ from lib.lutil import luCommand -from customize import l3mdev_accept +from lib.common_config import kernel_requires_l3mdev_adjustment +l3mdev_accept = kernel_requires_l3mdev_adjustment() l3mdev_rtrs = ["r1", "r3", "r4", "ce4"] for rtr in l3mdev_rtrs: luCommand(rtr, "sysctl net.ipv4.tcp_l3mdev_accept", " = \d*", "none", "") diff --git a/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py index 8e5ffe10be..84d9c48f35 100644 --- a/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py +++ b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py @@ -598,10 +598,12 @@ def test_large_community_lists_with_rmap_apply_and_remove(request): result = verify_bgp_community( tgen, adt, dut, NETWORKS[adt], input_dict_4, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "largeCommunity is still present after deleting route-map \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) write_test_footer(tc_name) @@ -899,10 +901,10 @@ def test_large_community_lists_with_rmap_set_none(request): dut = "r6" for adt in ADDR_TYPES: result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt], expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "Community-list is still present \n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "Community-list is still present \n Error: {}".format(tc_name, result) + ) write_test_footer(tc_name) @@ -2238,10 +2240,10 @@ def test_large_community_lists_with_rmap_match_regex(request): result = verify_bgp_community( tgen, adt, dut, NETWORKS[adt], input_dict_7, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "largeCommunity is still present \n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "largeCommunity is still present \n Error: {}".format(tc_name, result) + ) write_test_footer(tc_name) diff --git a/tests/topotests/bgp_lu_topo1/test_bgp_lu.py b/tests/topotests/bgp_lu_topo1/test_bgp_lu.py index d550c38a2f..d1745674f0 100644 --- a/tests/topotests/bgp_lu_topo1/test_bgp_lu.py +++ b/tests/topotests/bgp_lu_topo1/test_bgp_lu.py @@ -45,6 +45,10 @@ from lib.topolog import logger # Required to instantiate the topology builder class. from mininet.topo import Topo + +pytestmark = [pytest.mark.bgpd] + + # Basic scenario for BGP-LU. Nodes are directly connected. # Node 3 is advertising many routes to 2, which advertises them # as BGP-LU to 1; this way we get routes with actual labels, as diff --git a/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py b/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py index ac7ee44b25..5ecaee2ece 100644 --- a/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py +++ b/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py @@ -115,7 +115,7 @@ sys.path.append(os.path.join(CWD, "../lib/")) # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen from mininet.topo import Topo - +from lib.topotest import iproute2_is_vrf_capable from lib.common_config import ( step, verify_rib, @@ -215,6 +215,10 @@ def setup_module(mod): if result is not True: pytest.skip("Kernel requirements are not met") + # iproute2 needs to support VRFs for this suite to run. + if not iproute2_is_vrf_capable(): + pytest.skip("Installed iproute2 version does not support VRFs") + testsuite_run_time = time.asctime(time.localtime(time.time())) logger.info("Testsuite start time: {}".format(testsuite_run_time)) logger.info("=" * 40) @@ -504,10 +508,10 @@ def test_ambiguous_overlapping_addresses_in_different_vrfs_p0(request): ) result = verify_rib(tgen, addr_type, dut, input_dict_1, tag=500, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "Routes are present with tag value 500 \n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "Routes are present with tag value 500 \n Error: {}".format(tc_name, result) + ) logger.info("Expected Behavior: {}".format(result)) step( @@ -1143,10 +1147,12 @@ def test_prefixes_leaking_p0(request): result = verify_rib( tgen, addr_type, dut, input_dict_1, metric=123, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "Routes are present with metric value 123 \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info("Expected Behavior: {}".format(result)) result = verify_rib(tgen, addr_type, dut, input_dict_2, metric=123) @@ -1157,10 +1163,12 @@ def test_prefixes_leaking_p0(request): result = verify_rib( tgen, addr_type, dut, input_dict_2, metric=0, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "Routes are present with metric value 0 \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info("Expected Behavior: {}".format(result)) write_test_footer(tc_name) diff --git a/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py index c6e1792e84..c8d1330122 100644 --- a/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py +++ b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py @@ -71,7 +71,7 @@ sys.path.append(os.path.join(CWD, "../lib/")) # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen from mininet.topo import Topo - +from lib.topotest import iproute2_is_vrf_capable from lib.common_config import ( step, verify_rib, @@ -102,6 +102,10 @@ from lib.topolog import logger from lib.bgp import clear_bgp, verify_bgp_rib, create_router_bgp, verify_bgp_convergence from lib.topojson import build_config_from_json, build_topo_from_json + +pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] + + # Reading the data from JSON File for topology creation jsonFile = "{}/bgp_multi_vrf_topo2.json".format(CWD) @@ -164,6 +168,10 @@ def setup_module(mod): if result is not True: pytest.skip("Kernel requirements are not met") + # iproute2 needs to support VRFs for this suite to run. + if not iproute2_is_vrf_capable(): + pytest.skip("Installed iproute2 version does not support VRFs") + testsuite_run_time = time.asctime(time.localtime(time.time())) logger.info("Testsuite start time: {}".format(testsuite_run_time)) logger.info("=" * 40) @@ -2214,16 +2222,20 @@ def test_restart_bgpd_daemon_p1(request): } result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "Routes are still present in VRF RED_A and RED_B \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) result = verify_rib(tgen, addr_type, dut, input_dict_2, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "Routes are still present in VRF BLUE_A and BLUE_B \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("Bring up BGPd daemon on R1.") start_router_daemons(tgen, "r1", ["bgpd"]) 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 index 9e30bf2ef0..6b20e1df5a 100644 --- 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 @@ -3,6 +3,7 @@ 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 +RPKI validation codes: V valid, I invalid, N Not found Network Next Hop Metric LocPrf Weight Path * 10.0.1.0/24 172.16.1.5 0 65005 i diff --git a/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_1-post6.1.ref b/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_1-post6.1.ref index 2cf87487ab..5469eaa1cc 100644 --- a/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_1-post6.1.ref +++ b/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_1-post6.1.ref @@ -4,6 +4,7 @@ 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 +RPKI validation codes: V valid, I invalid, N Not found Network Next Hop Metric LocPrf Weight Path * 10.0.1.0/24 172.16.1.5 0 65005 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 index 39eb3134be..a64927c92d 100644 --- 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 @@ -3,6 +3,7 @@ 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 +RPKI validation codes: V valid, I invalid, N Not found Network Next Hop Metric LocPrf Weight Path * 10.0.1.0/24 172.16.1.4 0 65004 i diff --git a/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_2-post6.1.ref b/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_2-post6.1.ref index 9d1b948b5c..8d4a843b84 100644 --- a/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_2-post6.1.ref +++ b/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_2-post6.1.ref @@ -4,6 +4,7 @@ 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 +RPKI validation codes: V valid, I invalid, N Not found Network Next Hop Metric LocPrf Weight Path * 10.0.1.0/24 172.16.1.4 0 65004 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 index fa53d79e88..a3b9ef0888 100644 --- 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 @@ -3,6 +3,7 @@ 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 +RPKI validation codes: V valid, I invalid, N Not found Network Next Hop Metric LocPrf Weight Path * 10.0.1.0/24 172.16.1.8 0 65008 i diff --git a/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_3-post6.1.ref b/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_3-post6.1.ref index 8b66fa67ec..117e48847a 100644 --- a/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_3-post6.1.ref +++ b/tests/topotests/bgp_multiview_topo1/r1/show_ip_bgp_view_3-post6.1.ref @@ -4,6 +4,7 @@ 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 +RPKI validation codes: V valid, I invalid, N Not found Network Next Hop Metric LocPrf Weight Path * 10.0.1.0/24 172.16.1.8 0 65008 i diff --git a/tests/topotests/bgp_peer-group/test_bgp_peer-group.py b/tests/topotests/bgp_peer-group/test_bgp_peer-group.py index 7c7a8b87ed..21dc725793 100644 --- a/tests/topotests/bgp_peer-group/test_bgp_peer-group.py +++ b/tests/topotests/bgp_peer-group/test_bgp_peer-group.py @@ -39,6 +39,9 @@ from lib.topolog import logger from mininet.topo import Topo +pytestmark = [pytest.mark.bgpd] + + class TemplateTopo(Topo): def build(self, *_args, **_opts): tgen = get_topogen(self) diff --git a/tests/topotests/bgp_peer-type_multipath-relax/exabgp.env b/tests/topotests/bgp_peer-type_multipath-relax/exabgp.env new file mode 100644 index 0000000000..6c554f5fa8 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/exabgp.env @@ -0,0 +1,53 @@ + +[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' + +[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_peer-type_multipath-relax/peer1/exa-receive.py b/tests/topotests/bgp_peer-type_multipath-relax/peer1/exa-receive.py new file mode 100755 index 0000000000..031ff455ca --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/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_peer-type_multipath-relax/peer1/exa_readpipe.py b/tests/topotests/bgp_peer-type_multipath-relax/peer1/exa_readpipe.py new file mode 100644 index 0000000000..9e689a27e3 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/peer1/exa_readpipe.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +"Helper script to read api commands from a pipe and feed them to ExaBGP" + +import sys + +if len(sys.argv) != 2: + sys.exit(1) +fifo = sys.argv[1] + +while True: + pipe = open(fifo, "r") + with pipe: + line = pipe.readline().strip() + if line != "": + sys.stdout.write("{}\n".format(line)) + sys.stdout.flush() + pipe.close() + +sys.exit(0) diff --git a/tests/topotests/bgp_peer-type_multipath-relax/peer1/exabgp.cfg b/tests/topotests/bgp_peer-type_multipath-relax/peer1/exabgp.cfg new file mode 100644 index 0000000000..4a7dc48126 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/peer1/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa_readpipe.py /var/run/exabgp_peer1.in"; + encoder text; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 1"; + receive-routes; + encoder text; + } + + neighbor 10.0.1.1 { + router-id 10.0.1.2; + local-address 10.0.1.2; + local-as 64510; + peer-as 64510; + } + +} diff --git a/tests/topotests/bgp_peer-type_multipath-relax/peer2/exa-receive.py b/tests/topotests/bgp_peer-type_multipath-relax/peer2/exa-receive.py new file mode 100755 index 0000000000..031ff455ca --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/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_peer-type_multipath-relax/peer2/exa_readpipe.py b/tests/topotests/bgp_peer-type_multipath-relax/peer2/exa_readpipe.py new file mode 100644 index 0000000000..9e689a27e3 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/peer2/exa_readpipe.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +"Helper script to read api commands from a pipe and feed them to ExaBGP" + +import sys + +if len(sys.argv) != 2: + sys.exit(1) +fifo = sys.argv[1] + +while True: + pipe = open(fifo, "r") + with pipe: + line = pipe.readline().strip() + if line != "": + sys.stdout.write("{}\n".format(line)) + sys.stdout.flush() + pipe.close() + +sys.exit(0) diff --git a/tests/topotests/bgp_peer-type_multipath-relax/peer2/exabgp.cfg b/tests/topotests/bgp_peer-type_multipath-relax/peer2/exabgp.cfg new file mode 100644 index 0000000000..b53b054550 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/peer2/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa_readpipe.py /var/run/exabgp_peer2.in"; + encoder text; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 2"; + receive-routes; + encoder text; + } + + neighbor 10.0.2.1 { + router-id 10.0.2.2; + local-address 10.0.2.2; + local-as 64511; + peer-as 64511; + } + +} diff --git a/tests/topotests/bgp_peer-type_multipath-relax/peer3/exa-receive.py b/tests/topotests/bgp_peer-type_multipath-relax/peer3/exa-receive.py new file mode 100755 index 0000000000..031ff455ca --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/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_peer-type_multipath-relax/peer3/exa_readpipe.py b/tests/topotests/bgp_peer-type_multipath-relax/peer3/exa_readpipe.py new file mode 100644 index 0000000000..9e689a27e3 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/peer3/exa_readpipe.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +"Helper script to read api commands from a pipe and feed them to ExaBGP" + +import sys + +if len(sys.argv) != 2: + sys.exit(1) +fifo = sys.argv[1] + +while True: + pipe = open(fifo, "r") + with pipe: + line = pipe.readline().strip() + if line != "": + sys.stdout.write("{}\n".format(line)) + sys.stdout.flush() + pipe.close() + +sys.exit(0) diff --git a/tests/topotests/bgp_peer-type_multipath-relax/peer3/exabgp.cfg b/tests/topotests/bgp_peer-type_multipath-relax/peer3/exabgp.cfg new file mode 100644 index 0000000000..6a1cc2fb3f --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/peer3/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa_readpipe.py /var/run/exabgp_peer3.in"; + encoder text; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 3"; + receive-routes; + encoder text; + } + + neighbor 10.0.3.1 { + router-id 10.0.3.2; + local-address 10.0.3.2; + local-as 64502; + peer-as 64501; + } + +} diff --git a/tests/topotests/bgp_peer-type_multipath-relax/peer4/exa-receive.py b/tests/topotests/bgp_peer-type_multipath-relax/peer4/exa-receive.py new file mode 100755 index 0000000000..031ff455ca --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/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_peer-type_multipath-relax/peer4/exa_readpipe.py b/tests/topotests/bgp_peer-type_multipath-relax/peer4/exa_readpipe.py new file mode 100644 index 0000000000..9e689a27e3 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/peer4/exa_readpipe.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +"Helper script to read api commands from a pipe and feed them to ExaBGP" + +import sys + +if len(sys.argv) != 2: + sys.exit(1) +fifo = sys.argv[1] + +while True: + pipe = open(fifo, "r") + with pipe: + line = pipe.readline().strip() + if line != "": + sys.stdout.write("{}\n".format(line)) + sys.stdout.flush() + pipe.close() + +sys.exit(0) diff --git a/tests/topotests/bgp_peer-type_multipath-relax/peer4/exabgp.cfg b/tests/topotests/bgp_peer-type_multipath-relax/peer4/exabgp.cfg new file mode 100644 index 0000000000..2cc26cb80f --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/peer4/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa_readpipe.py /var/run/exabgp_peer4.in"; + encoder text; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 4"; + receive-routes; + encoder text; + } + + neighbor 10.0.4.1 { + router-id 10.0.4.2; + local-address 10.0.4.2; + local-as 64503; + peer-as 64501; + } + +} diff --git a/tests/topotests/bgp_peer-type_multipath-relax/r1/bgpd.conf b/tests/topotests/bgp_peer-type_multipath-relax/r1/bgpd.conf new file mode 100644 index 0000000000..038f108aa8 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/r1/bgpd.conf @@ -0,0 +1,16 @@ +! +router bgp 64510 + bgp router-id 10.0.1.1 + no bgp ebgp-requires-policy + bgp confederation identifier 64501 + bgp confederation peers 64511 + bgp bestpath as-path multipath-relax + bgp bestpath compare-routerid + bgp bestpath peer-type multipath-relax + neighbor 10.0.1.2 remote-as 64510 + neighbor 10.0.3.2 remote-as 64502 + neighbor 10.0.4.2 remote-as 64503 + neighbor 10.0.5.2 remote-as 64511 +! +line vty +! diff --git a/tests/topotests/bgp_peer-type_multipath-relax/r1/multipath.json b/tests/topotests/bgp_peer-type_multipath-relax/r1/multipath.json new file mode 100644 index 0000000000..11dad786f2 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/r1/multipath.json @@ -0,0 +1,50 @@ +{ + "routes": { "203.0.113.0/30": [ + { + "valid":true, + "multipath":true, + "pathFrom":"external", + "peerId":"10.0.5.2" + }, + { + "valid":true, + "bestpath":true, + "selectionReason":"Peer Type", + "pathFrom":"external", + "peerId":"10.0.4.2" + }, + { + "valid":true, + "multipath":true, + "pathFrom":"internal", + "peerId":"10.0.1.2" + } +],"203.0.113.4/30": [ + { + "valid":true, + "bestpath":true, + "selectionReason":"Confed Peer Type", + "pathFrom":"external", + "peerId":"10.0.5.2" + }, + { + "valid":true, + "multipath":true, + "pathFrom":"internal", + "peerId":"10.0.1.2" + } +],"203.0.113.8/30": [ + { + "valid":true, + "multipath":true, + "pathFrom":"external", + "peerId":"10.0.4.2" + }, + { + "valid":true, + "bestpath":true, + "selectionReason":"Router ID", + "pathFrom":"external", + "peerId":"10.0.3.2" + } +] } } diff --git a/tests/topotests/bgp_peer-type_multipath-relax/r1/not-multipath.json b/tests/topotests/bgp_peer-type_multipath-relax/r1/not-multipath.json new file mode 100644 index 0000000000..c621832157 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/r1/not-multipath.json @@ -0,0 +1,50 @@ +{ + "routes": { "203.0.113.0/30": [ + { + "valid":true, + "multipath":null, + "pathFrom":"external", + "peerId":"10.0.5.2" + }, + { + "valid":true, + "bestpath":true, + "selectionReason":"Peer Type", + "pathFrom":"external", + "peerId":"10.0.4.2" + }, + { + "valid":true, + "multipath":null, + "pathFrom":"internal", + "peerId":"10.0.1.2" + } +],"203.0.113.4/30": [ + { + "valid":true, + "bestpath":true, + "selectionReason":"Confed Peer Type", + "pathFrom":"external", + "peerId":"10.0.5.2" + }, + { + "valid":true, + "multipath":null, + "pathFrom":"internal", + "peerId":"10.0.1.2" + } +],"203.0.113.8/30": [ + { + "valid":true, + "multipath":true, + "pathFrom":"external", + "peerId":"10.0.4.2" + }, + { + "valid":true, + "bestpath":true, + "selectionReason":"Router ID", + "pathFrom":"external", + "peerId":"10.0.3.2" + } +] } } diff --git a/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix1-eBGP-confed.json b/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix1-eBGP-confed.json new file mode 100644 index 0000000000..22ec2c298b --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix1-eBGP-confed.json @@ -0,0 +1,33 @@ +{ + "203.0.113.0\/30":[ + { + "prefix":"203.0.113.0\/30", + "protocol":"bgp", + "installed":true, + "internalNextHopNum":4, + "internalNextHopActiveNum":4, + "nexthops":[ + { + "ip":"198.51.100.2", + "active":true, + "recursive":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "active":true + }, + { + "ip":"198.51.100.10", + "active":true, + "recursive":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix1-eBGP-iBGP.json b/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix1-eBGP-iBGP.json new file mode 100644 index 0000000000..facddcda46 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix1-eBGP-iBGP.json @@ -0,0 +1,33 @@ +{ + "203.0.113.0\/30":[ + { + "prefix":"203.0.113.0\/30", + "protocol":"bgp", + "installed":true, + "internalNextHopNum":4, + "internalNextHopActiveNum":4, + "nexthops":[ + { + "ip":"198.51.100.1", + "active":true, + "recursive":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "active":true + }, + { + "ip":"198.51.100.10", + "active":true, + "recursive":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix1-no-recursive.json b/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix1-no-recursive.json new file mode 100644 index 0000000000..5399ceefcc --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix1-no-recursive.json @@ -0,0 +1,35 @@ +{ + "prefix":"203.0.113.0\/30", + "paths":[ + { + "valid":false, + "peer":{ + "peerId":"10.0.4.2", + "routerId":"10.0.4.2", + "type":"external" + } + }, + { + "valid":true, + "multipath":true, + "bestpath":{ + "overall":true, + "selectionReason":"Confed Peer Type" + }, + "peer":{ + "peerId":"10.0.5.2", + "routerId":"10.0.5.2", + "type":"confed-external" + } + }, + { + "valid":true, + "multipath":true, + "peer":{ + "peerId":"10.0.1.2", + "routerId":"10.0.1.2", + "type":"confed-internal" + } + } + ] +} diff --git a/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix1-recursive.json b/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix1-recursive.json new file mode 100644 index 0000000000..7da95aed1c --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix1-recursive.json @@ -0,0 +1,36 @@ +{ + "prefix":"203.0.113.0\/30", + "paths":[ + { + "valid":true, + "multipath":true, + "bestpath":{ + "overall":true, + "selectionReason":"Peer Type" + }, + "peer":{ + "peerId":"10.0.4.2", + "routerId":"10.0.4.2", + "type":"external" + } + }, + { + "valid":true, + "multipath":true, + "peer":{ + "peerId":"10.0.5.2", + "routerId":"10.0.5.2", + "type":"confed-external" + } + }, + { + "valid":true, + "multipath":true, + "peer":{ + "peerId":"10.0.1.2", + "routerId":"10.0.1.2", + "type":"confed-internal" + } + } + ] +} diff --git a/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix1.json b/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix1.json new file mode 100644 index 0000000000..a90669a474 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix1.json @@ -0,0 +1,33 @@ +{ + "prefix":"203.0.113.0\/30", + "paths":[ + { + "multipath":true, + "peer":{ + "peerId":"10.0.5.2", + "routerId":"10.0.5.2", + "type":"confed-external" + } + }, + { + "multipath":true, + "bestpath":{ + "overall":true, + "selectionReason":"Peer Type" + }, + "peer":{ + "peerId":"10.0.4.2", + "routerId":"10.0.4.2", + "type":"external" + } + }, + { + "multipath":true, + "peer":{ + "peerId":"10.0.1.2", + "routerId":"10.0.1.2", + "type":"confed-internal" + } + } + ] +} diff --git a/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix3-ip-route.json b/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix3-ip-route.json new file mode 100644 index 0000000000..1bf38efcc5 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix3-ip-route.json @@ -0,0 +1,23 @@ +{ + "203.0.113.8\/30":[ + { + "prefix":"203.0.113.8\/30", + "protocol":"bgp", + "installed":true, + "internalNextHopNum":2, + "internalNextHopActiveNum":1, + "nexthops":[ + { + "fib":true, + "ip":"10.0.3.2", + "active":true + }, + { + "fib":null, + "ip":"198.51.100.10", + "active":null + } + ] + } + ] +} diff --git a/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix3-no-recursive.json b/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix3-no-recursive.json new file mode 100644 index 0000000000..33d0f2d1ce --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix3-no-recursive.json @@ -0,0 +1,21 @@ +{ + "prefix":"203.0.113.8\/30", + "paths":[ + { + "valid":false, + "peer":{ + "peerId":"10.0.4.2", + "routerId":"10.0.4.2", + "type":"external" + } + }, + { + "valid":true, + "peer":{ + "peerId":"10.0.3.2", + "routerId":"10.0.3.2", + "type":"external" + } + } + ] +} diff --git a/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix3-recursive.json b/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix3-recursive.json new file mode 100644 index 0000000000..6ac2512a60 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix3-recursive.json @@ -0,0 +1,23 @@ +{ + "prefix":"203.0.113.8\/30", + "paths":[ + { + "valid":true, + "multipath":true, + "peer":{ + "peerId":"10.0.4.2", + "routerId":"10.0.4.2", + "type":"external" + } + }, + { + "valid":true, + "multipath":true, + "peer":{ + "peerId":"10.0.3.2", + "routerId":"10.0.3.2", + "type":"external" + } + } + ] +} diff --git a/tests/topotests/bgp_peer-type_multipath-relax/r1/zebra.conf b/tests/topotests/bgp_peer-type_multipath-relax/r1/zebra.conf new file mode 100644 index 0000000000..911aa1c39d --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/r1/zebra.conf @@ -0,0 +1,27 @@ +! +hostname r1 +! +interface r1-eth0 + description ExaBGP iBGP peer1 + ip address 10.0.1.1/24 + no link-detect +! +interface r1-eth1 + description ExaBGP peer3 + ip address 10.0.3.1/24 + no link-detect +! +interface r1-eth2 + description ExaBGP peer4 + ip address 10.0.4.1/24 + no link-detect +! +interface r1-eth3 + description r2 confed peer + ip address 10.0.5.1/24 + no link-detect +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/bgp_peer-type_multipath-relax/r2/bgpd.conf b/tests/topotests/bgp_peer-type_multipath-relax/r2/bgpd.conf new file mode 100644 index 0000000000..2362a19f26 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/r2/bgpd.conf @@ -0,0 +1,19 @@ +! +!log file bgpd.log +! +router bgp 64511 + bgp confederation identifier 64501 + bgp confederation peers 64510 + bgp router-id 10.0.5.2 + no bgp ebgp-requires-policy + neighbor 10.0.2.2 remote-as 64511 + neighbor 10.0.5.1 remote-as 64510 + ! + address-family ipv4 unicast + neighbor 10.0.5.1 route-map dropall in + exit-address-family +! +route-map dropall deny 10 +! +line vty +! diff --git a/tests/topotests/bgp_peer-type_multipath-relax/r2/staticd.conf b/tests/topotests/bgp_peer-type_multipath-relax/r2/staticd.conf new file mode 100644 index 0000000000..35ebe0dc66 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/r2/staticd.conf @@ -0,0 +1,4 @@ +hostname r2 +! +ip route 198.51.100.0/24 10.0.2.2 +! diff --git a/tests/topotests/bgp_peer-type_multipath-relax/r2/zebra.conf b/tests/topotests/bgp_peer-type_multipath-relax/r2/zebra.conf new file mode 100644 index 0000000000..900e7d4fbc --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/r2/zebra.conf @@ -0,0 +1,19 @@ +! +! +hostname r2 +! +interface r2-eth0 + description ExaBGP peer + ip address 10.0.2.1/24 + no link-detect +! +interface r2-eth1 + description r1 confed peer + ip address 10.0.5.2/24 + no link-detect +! +ip forwarding +! +! +line vty +! diff --git a/tests/topotests/bgp_peer-type_multipath-relax/test_bgp_peer-type_multipath-relax.py b/tests/topotests/bgp_peer-type_multipath-relax/test_bgp_peer-type_multipath-relax.py new file mode 100755 index 0000000000..39a0beeb11 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/test_bgp_peer-type_multipath-relax.py @@ -0,0 +1,386 @@ +#!/usr/bin/env python + +# +# Part of NetDEF Topology Tests +# +# Copyright (c) 2021 Arista Networks, Inc. +# +# 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 Arista Networks 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_peer-type_multipath-relax.py: + +Test the effects of the "bgp bestpath peer-type multipath-relax" command + +- enabling the command allows eBGP, iBGP, and confed routes to be multipath +- the choice of best path is not affected +- disabling the command removes iBGP/confed routes from multipath +- enabling the command does not forgive eBGP routes of the requirement + (when enabled) that next hops resolve over connected routes +- a mixed-type multipath next hop, when published to zebra, does not + require resolving next hops over connected routes +- with the command enabled, an all-eBGP multipath next hop still requires + resolving next hops over connected routes when published to zebra + +Topology used by the test: + + eBGP +------+ iBGP + peer1 ---- | r1 | ---- peer3 + | | +peer2 ---- r2 ---- | | ---- peer4 + iBGP confed +------+ eBGP + +r2 is present in this topology because ExaBGP does not currently support +confederations so we use FRR to advertise the required AS_CONFED_SEQUENCE. + +Routes are advertised from different peers to form interesting multipaths. + + peer1 peer2 peer3 peer4 multipath on r1 + +203.0.113.0/30 x x x all 3 +203.0.113.4/30 x x confed-iBGP +203.0.113.8/30 x x eBGP-only + +There is also a BGP-advertised route used only for recursively resolving +next hops. +""" + +import functools +import json +import os +import pytest +import sys + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger +from mininet.topo import Topo + + +class PeerTypeRelaxTopo(Topo): + def build(self, *_args, **_opts): + "Build function" + tgen = get_topogen(self) + + # Set up routers + tgen.add_router("r1") # DUT + tgen.add_router("r2") + + # Set up peers + for peern in range(1, 5): + peer = tgen.add_exabgp_peer( + "peer{}".format(peern), + ip="10.0.{}.2/24".format(peern), + defaultRoute="via 10.0.{}.1".format(peern), + ) + if peern == 2: + tgen.add_link(tgen.gears["r2"], peer) + else: + tgen.add_link(tgen.gears["r1"], peer) + tgen.add_link(tgen.gears["r1"], tgen.gears["r2"]) + + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(PeerTypeRelaxTopo, mod.__name__) + tgen.start_topology() + + # For all registered routers, load the zebra configuration file + for rname, router in tgen.routers().items(): + router.run("/bin/bash {}/setup_vrfs".format(CWD)) + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_STATIC, os.path.join(CWD, "{}/staticd.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + + # After loading the configurations, this function loads configured daemons. + tgen.start_router() + + # Start up exabgp peers + peers = tgen.exabgp_peers() + for peer in peers: + fifo_in = "/var/run/exabgp_{}.in".format(peer) + if os.path.exists(fifo_in): + os.remove(fifo_in) + os.mkfifo(fifo_in, 0o777) + logger.info("Starting ExaBGP on peer {}".format(peer)) + peer_dir = os.path.join(CWD, peer) + env_file = os.path.join(CWD, "exabgp.env") + peers[peer].start(peer_dir, env_file) + + +def teardown_module(mod): + "Teardown the pytest environment" + tgen = get_topogen() + + # This function tears down the whole topology. + tgen.stop_topology() + + +def test_bgp_peer_type_multipath_relax(): + tgen = get_topogen() + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + def exabgp_cmd(peer, cmd): + pipe = open("/run/exabgp_{}.in".format(peer), "w") + with pipe: + pipe.write(cmd) + pipe.close() + + # Prefixes used in the test + prefix1 = "203.0.113.0/30" + prefix2 = "203.0.113.4/30" + prefix3 = "203.0.113.8/30" + # Next hops used for iBGP/confed routes + resolved_nh1 = "198.51.100.1" + resolved_nh2 = "198.51.100.2" + # BGP route used for recursive resolution + bgp_resolving_prefix = "198.51.100.0/24" + # Next hop that will require non-connected recursive resolution + ebgp_resolved_nh = "198.51.100.10" + + # Send a non-connected route to resolve others + exabgp_cmd( + "peer3", "announce route {} next-hop self\n".format(bgp_resolving_prefix) + ) + router = tgen.gears["r1"] + + # It seems that if you write to the exabgp socket too quickly in + # succession, requests get lost. So verify prefix1 now instead of + # after all the prefixes are advertised. + logger.info("Create and verify mixed-type multipaths") + exabgp_cmd( + "peer1", + "announce route {} next-hop {} as-path [ 64499 ]\n".format( + prefix1, resolved_nh1 + ), + ) + exabgp_cmd( + "peer2", + "announce route {} next-hop {} as-path [ 64499 ]\n".format( + prefix1, resolved_nh2 + ), + ) + exabgp_cmd("peer4", "announce route {} next-hop self\n".format(prefix1)) + reffile = os.path.join(CWD, "r1/prefix1.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show ip bgp {} json".format(prefix1), + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=10, wait=1) + assertMsg = "Mixed-type multipath not found" + assert res is None, assertMsg + + logger.info("Create and verify eBGP and iBGP+confed multipaths") + exabgp_cmd( + "peer1", + "announce route {} next-hop {} as-path [ 64499 ]\n".format( + prefix2, resolved_nh1 + ), + ) + exabgp_cmd( + "peer2", + "announce route {} next-hop {} as-path [ 64499 ]\n".format( + prefix2, resolved_nh2 + ), + ) + exabgp_cmd("peer3", "announce route {} next-hop self".format(prefix3)) + exabgp_cmd("peer4", "announce route {} next-hop self".format(prefix3)) + reffile = os.path.join(CWD, "r1/multipath.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, router, "show ip bgp json", expected + ) + _, res = topotest.run_and_expect(test_func, None, count=10, wait=1) + assertMsg = "Not all expected multipaths found" + assert res is None, assertMsg + + logger.info("Toggle peer-type multipath-relax and verify the changes") + router.vtysh_cmd( + "conf\n router bgp 64510\n no bgp bestpath peer-type multipath-relax\n" + ) + # This file verifies "multipath" is not set + reffile = os.path.join(CWD, "r1/not-multipath.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, router, "show ip bgp json", expected + ) + _, res = topotest.run_and_expect(test_func, None, count=10, wait=1) + assertMsg = "Disabling peer-type multipath-relax did not take effect" + assert res is None, assertMsg + + router.vtysh_cmd( + "conf\n router bgp 64510\n bgp bestpath peer-type multipath-relax\n" + ) + reffile = os.path.join(CWD, "r1/multipath.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, router, "show ip bgp json", expected + ) + _, res = topotest.run_and_expect(test_func, None, count=10, wait=1) + assertMsg = "Reenabling peer-type multipath-relax did not take effect" + assert res is None, assertMsg + + logger.info("Check recursive resolution of eBGP next hops is not affected") + # eBGP next hop resolution rejects recursively resolved next hops by + # default, even with peer-type multipath-relax + exabgp_cmd( + "peer4", "announce route {} next-hop {}\n".format(prefix3, ebgp_resolved_nh) + ) + reffile = os.path.join(CWD, "r1/prefix3-no-recursive.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show ip bgp {} json".format(prefix3), + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=10, wait=1) + assertMsg = "Recursive eBGP next hop not as expected for {}".format(prefix3) + assert res is None, assertMsg + + exabgp_cmd( + "peer4", "announce route {} next-hop {}\n".format(prefix1, ebgp_resolved_nh) + ) + reffile = os.path.join(CWD, "r1/prefix1-no-recursive.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show ip bgp {} json".format(prefix1), + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=10, wait=1) + assertMsg = "Recursive eBGP next hop not as expected for {}".format(prefix1) + assert res is None, assertMsg + + # When other config allows recursively resolved eBGP next hops, + # such next hops in all-eBGP multipaths should be valid + router.vtysh_cmd("conf\n router bgp 64510\n neighbor 10.0.4.2 ebgp-multihop\n") + reffile = os.path.join(CWD, "r1/prefix3-recursive.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show ip bgp {} json".format(prefix3), + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=10, wait=1) + assertMsg = "Recursive eBGP next hop not as expected for {}".format(prefix3) + assert res is None, assertMsg + + reffile = os.path.join(CWD, "r1/prefix1-recursive.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show ip bgp {} json".format(prefix1), + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=10, wait=1) + assertMsg = "Recursive eBGP next hop not as expected for {}".format(prefix1) + assert res is None, assertMsg + + logger.info("Check mixed-type multipath next hop recursive resolution in FIB") + # There are now two eBGP-learned routes with a recursively resolved next; + # hop; one is all-eBGP multipath, and the other is iBGP/eBGP/ + # confed-external. The peer-type multipath-relax feature only enables + # recursive resolution in FIB if any next hop is iBGP/confed-learned. The + # all-eBGP multipath will have only one valid next hop in the FIB. + reffile = os.path.join(CWD, "r1/prefix3-ip-route.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show ip route {} json".format(prefix3), + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=10, wait=1) + assertMsg = "FIB next hops mismatch for all-eBGP multipath" + assert res is None, assertMsg + + # check confed-external enables recursively resolved next hops by itself + exabgp_cmd( + "peer1", + "withdraw route {} next-hop {} as-path [ 64499 ]\n".format( + prefix1, resolved_nh1 + ), + ) + reffile = os.path.join(CWD, "r1/prefix1-eBGP-confed.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show ip route {} json".format(prefix1), + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=10, wait=1) + assertMsg = "FIB next hops mismatch for eBGP+confed-external multipath" + assert res is None, assertMsg + + # check iBGP by itself + exabgp_cmd( + "peer1", + "announce route {} next-hop {} as-path [ 64499 ]\n".format( + prefix1, resolved_nh1 + ), + ) + exabgp_cmd( + "peer2", + "withdraw route {} next-hop {} as-path [ 64499 ]\n".format( + prefix1, resolved_nh2 + ), + ) + reffile = os.path.join(CWD, "r1/prefix1-eBGP-iBGP.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show ip route {} json".format(prefix1), + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=10, wait=1) + assertMsg = "FIB next hops mismatch for eBGP+iBGP multipath" + 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_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py b/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py index 4764ff8945..2a98cb341d 100644 --- a/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py +++ b/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py @@ -86,6 +86,10 @@ from lib.bgp import ( ) from lib.topojson import build_topo_from_json, build_config_from_json + +pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] + + # Reading the data from JSON File for topology and configuration creation jsonFile = "{}/bgp_recursive_route_ebgp_multi_hop.json".format(CWD) try: @@ -365,10 +369,11 @@ def test_recursive_routes_iBGP_peer_p1(request): protocol="bgp", expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " - "Routes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "Routes are still present \n Error: {}".format( tc_name, result - )) + ) step("Reconfigure the same static route on R2 again") dut = "r2" @@ -486,10 +491,11 @@ def test_recursive_routes_iBGP_peer_p1(request): result = verify_rib( tgen, addr_type, "r2", input_dict_4, protocol="bgp", expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "Routes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "Routes are still present \n Error: {}".format( tc_name, result - )) + ) write_test_footer(tc_name) @@ -598,10 +604,11 @@ def test_next_hop_as_self_ip_p1(request): next_hop=topo["routers"]["r2"]["links"]["r4"][addr_type].split("/")[0], expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " - "Routes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "Routes are still present \n Error: {}".format( tc_name, result - )) + ) step("Shut interface on R2 that has IP from the subnet as BGP next-hop") intf_r2_r4 = topo["routers"]["r2"]["links"]["r4"]["interface"] @@ -676,10 +683,11 @@ def test_next_hop_as_self_ip_p1(request): next_hop=topo["routers"]["r2"]["links"]["r4"][addr_type].split("/")[0], expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " - "Routes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "Routes are still present \n Error: {}".format( tc_name, result - )) + ) write_test_footer(tc_name) @@ -1622,10 +1630,11 @@ def test_BGP_peering_bw_loopback_and_physical_p1(request): step("Verify that once eBGP multi-hop is removed, BGP session goes down") result = verify_bgp_convergence_from_running_config(tgen, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "BGP is converged \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "BGP is converged \n Error: {}".format( tc_name, result - )) + ) step("Add ebgp-multihop command on R3 again") for addr_type in ADDR_TYPES: @@ -1663,10 +1672,11 @@ def test_BGP_peering_bw_loopback_and_physical_p1(request): step("Verify that BGP session goes down, when update-source is removed") result = verify_bgp_convergence_from_running_config(tgen, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "BGP is converged \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "BGP is converged \n Error: {}".format( tc_name, result - )) + ) step("Add update-source command on R1 again") for addr_type in ADDR_TYPES: @@ -1715,18 +1725,20 @@ def test_BGP_peering_bw_loopback_and_physical_p1(request): next_hop=topo["routers"]["r1"]["links"]["r3"][addr_type].split("/")[0], expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " - "Routes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "Routes are still present \n Error: {}".format( tc_name, result - )) + ) sleep(3) step("Verify that BGP session goes down, when static route is removed") result = verify_bgp_convergence_from_running_config(tgen, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "BGP is converged \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "BGP is converged \n Error: {}".format( tc_name, result - )) + ) step("Add static route on R3 again") for addr_type in ADDR_TYPES: @@ -1768,10 +1780,11 @@ def test_BGP_peering_bw_loopback_and_physical_p1(request): sleep(3) step("Verify that BGP neighborship between R1 and R3 goes down") result = verify_bgp_convergence_from_running_config(tgen, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "BGP is converged \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "BGP is converged \n Error: {}".format( tc_name, result - )) + ) intf_r1_r3 = topo["routers"]["r1"]["links"]["r3"]["interface"] shutdown_bringup_interface(tgen, "r1", intf_r1_r3, True) @@ -2087,10 +2100,11 @@ def test_BGP_active_standby_preemption_and_ecmp_p1(request): ], expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " - "Routes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "Routes are still present \n Error: {}".format( tc_name, result - )) + ) step("Reconfigure multipath-relax command on R4") result = create_router_bgp(tgen, topo, maxpath_relax) @@ -2147,10 +2161,11 @@ def test_BGP_active_standby_preemption_and_ecmp_p1(request): ], expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " - "Routes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "Routes are still present \n Error: {}".format( tc_name, result - )) + ) step("Re-configure maximum-path 2 command on R4") input_dict_8 = { @@ -2338,10 +2353,11 @@ def test_password_authentication_for_eBGP_and_iBGP_peers_p1(request): "configured but not peer routers" ) result = verify_bgp_convergence(tgen, topo, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "BGP is converged \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "BGP is converged \n Error: {}".format( tc_name, result - )) + ) step("configure same password on R2 and R3") for routerN in ["r2", "r3"]: @@ -2368,10 +2384,11 @@ def test_password_authentication_for_eBGP_and_iBGP_peers_p1(request): "strings are in CAPs on R2 and R3" ) result = verify_bgp_convergence(tgen, topo, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "BGP is converged \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "BGP is converged \n Error: {}".format( tc_name, result - )) + ) step("Configure same password on R2 and R3 without CAPs") for routerN in ["r2", "r3"]: @@ -2395,10 +2412,11 @@ def test_password_authentication_for_eBGP_and_iBGP_peers_p1(request): step("Verify if password is removed from R1, both sessions go down again") result = verify_bgp_convergence(tgen, topo, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "BGP is converged \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "BGP is converged \n Error: {}".format( tc_name, result - )) + ) step("Configure alphanumeric password on R1 and peer routers R2,R3") for bgp_neighbor in ["r2", "r3"]: diff --git a/tests/topotests/bgp_sender-as-path-loop-detection/test_bgp_sender-as-path-loop-detection.py b/tests/topotests/bgp_sender-as-path-loop-detection/test_bgp_sender-as-path-loop-detection.py index 88935ae4d1..dffe24f3a0 100644 --- a/tests/topotests/bgp_sender-as-path-loop-detection/test_bgp_sender-as-path-loop-detection.py +++ b/tests/topotests/bgp_sender-as-path-loop-detection/test_bgp_sender-as-path-loop-detection.py @@ -44,6 +44,9 @@ from lib.topolog import logger from mininet.topo import Topo +pytestmark = [pytest.mark.bgpd] + + class TemplateTopo(Topo): def build(self, *_args, **_opts): tgen = get_topogen(self) diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py index b99f1a7418..291a6e7c3a 100644 --- a/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py +++ b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py @@ -498,6 +498,7 @@ def disable_route_map_to_prefer_global_next_hop(tgen, topo): # ##################################################### + def test_dynamic_imported_routes_advertised_to_iBGP_peer_p0(request): """ TC5_FUNC_5: @@ -762,9 +763,7 @@ def test_dynamic_imported_routes_advertised_to_iBGP_peer_p0(request): for addr_type in ADDR_TYPES: - step( - "On router R1 delete static routes in vrf ISR to LOOPBACK_1" - ) + step("On router R1 delete static routes in vrf ISR to LOOPBACK_1") input_routes_r1 = { "r1": { @@ -772,7 +771,7 @@ def test_dynamic_imported_routes_advertised_to_iBGP_peer_p0(request): { "network": [NETWORK1_3[addr_type], NETWORK1_4[addr_type]], "next_hop": (intf_r2_r1[addr_type]).split("/")[0], - "delete": True + "delete": True, } ] } diff --git a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.py b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.py index 97d98415db..92ee8513e1 100644 --- a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.py +++ b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.py @@ -42,6 +42,7 @@ sys.path.append(os.path.join(CWD, "../")) from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger +from lib.common_config import adjust_router_l3mdev # Required to instantiate the topology builder class. from mininet.topo import Topo @@ -71,22 +72,6 @@ def setup_module(mod): router_list = tgen.routers() logger.info("Testing with VRF Lite support") - krel = platform.release() - - # May need to adjust handling of vrf traffic depending on kernel version - l3mdev_accept = 0 - if ( - topotest.version_cmp(krel, "4.15") >= 0 - and topotest.version_cmp(krel, "4.18") <= 0 - ): - l3mdev_accept = 1 - - if topotest.version_cmp(krel, "5.0") >= 0: - l3mdev_accept = 1 - - logger.info( - "krel '{0}' setting net.ipv4.tcp_l3mdev_accept={1}".format(krel, l3mdev_accept) - ) cmds = [ "ip link add {0}-cust1 type vrf table 1001", @@ -99,15 +84,8 @@ def setup_module(mod): for cmd in cmds: output = tgen.net[rname].cmd(cmd.format(rname)) - output = tgen.net[rname].cmd("sysctl -n net.ipv4.tcp_l3mdev_accept") - logger.info( - "router {0}: existing tcp_l3mdev_accept was {1}".format(rname, output) - ) - - if l3mdev_accept: - output = tgen.net[rname].cmd( - "sysctl -w net.ipv4.tcp_l3mdev_accept={}".format(l3mdev_accept) - ) + # adjust handling of vrf traffic + adjust_router_l3mdev(tgen, rname) for rname, router in router_list.items(): router.load_config( diff --git a/tests/topotests/conftest.py b/tests/topotests/conftest.py index 04e9961f10..cf64956bfd 100755 --- a/tests/topotests/conftest.py +++ b/tests/topotests/conftest.py @@ -2,12 +2,14 @@ Topotest conftest.py file. """ +import os +import pdb +import pytest + from lib.topogen import get_topogen, diagnose_env from lib.topotest import json_cmp_result +from lib.topotest import g_extra_config as topotest_extra_config from lib.topolog import logger -import pytest - -topology_only = False def pytest_addoption(parser): @@ -16,20 +18,72 @@ def pytest_addoption(parser): only run the setup_module() to setup the topology without running any tests. """ parser.addoption( + "--gdb-breakpoints", + metavar="SYMBOL[,SYMBOL...]", + help="Comma-separated list of functions to set gdb breakpoints on", + ) + + parser.addoption( + "--gdb-daemons", + metavar="DAEMON[,DAEMON...]", + help="Comma-separated list of daemons to spawn gdb on, or 'all'", + ) + + parser.addoption( + "--gdb-routers", + metavar="ROUTER[,ROUTER...]", + help="Comma-separated list of routers to spawn gdb on, or 'all'", + ) + + parser.addoption( + "--mininet-on-error", + action="store_true", + help="Mininet cli on test failure", + ) + + parser.addoption( + "--pause-after", + action="store_true", + help="Pause after each test", + ) + + parser.addoption( + "--shell", + metavar="ROUTER[,ROUTER...]", + help="Comma-separated list of routers to spawn shell on, or 'all'", + ) + + parser.addoption( + "--shell-on-error", + action="store_true", + help="Spawn shell on all routers on test failure", + ) + + parser.addoption( "--topology-only", action="store_true", help="Only set up this topology, don't run tests", ) + parser.addoption( + "--vtysh", + metavar="ROUTER[,ROUTER...]", + help="Comma-separated list of routers to spawn vtysh on, or 'all'", + ) + + parser.addoption( + "--vtysh-on-error", + action="store_true", + help="Spawn vtysh on all routers on test failure", + ) + 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. """ - global topology_only - - if topology_only: + if topotest_extra_config["topology_only"]: tgen = get_topogen() if tgen is not None: # Allow user to play with the setup. @@ -42,6 +96,8 @@ def pytest_assertrepr_compare(op, left, right): """ Show proper assertion error message for json_cmp results. """ + del op + json_result = left if not isinstance(json_result, json_cmp_result): json_result = right @@ -52,43 +108,104 @@ def pytest_assertrepr_compare(op, left, right): def pytest_configure(config): - "Assert that the environment is correctly configured." - - global topology_only + """ + Assert that the environment is correctly configured, and get extra config. + """ if not diagnose_env(): - pytest.exit("enviroment has errors, please read the logs") + pytest.exit("environment has errors, please read the logs") + + gdb_routers = config.getoption("--gdb-routers") + gdb_routers = gdb_routers.split(",") if gdb_routers else [] + topotest_extra_config["gdb_routers"] = gdb_routers + + gdb_daemons = config.getoption("--gdb-daemons") + gdb_daemons = gdb_daemons.split(",") if gdb_daemons else [] + topotest_extra_config["gdb_daemons"] = gdb_daemons + + gdb_breakpoints = config.getoption("--gdb-breakpoints") + gdb_breakpoints = gdb_breakpoints.split(",") if gdb_breakpoints else [] + topotest_extra_config["gdb_breakpoints"] = gdb_breakpoints - if config.getoption("--topology-only"): - topology_only = True + mincli_on_error = config.getoption("--mininet-on-error") + topotest_extra_config["mininet_on_error"] = mincli_on_error + + shell = config.getoption("--shell") + topotest_extra_config["shell"] = shell.split(",") if shell else [] + + pause_after = config.getoption("--pause-after") + + shell_on_error = config.getoption("--shell-on-error") + topotest_extra_config["shell_on_error"] = shell_on_error + + vtysh = config.getoption("--vtysh") + topotest_extra_config["vtysh"] = vtysh.split(",") if vtysh else [] + + vtysh_on_error = config.getoption("--vtysh-on-error") + topotest_extra_config["vtysh_on_error"] = vtysh_on_error + + topotest_extra_config["pause_after"] = pause_after or shell or vtysh + + topotest_extra_config["topology_only"] = config.getoption("--topology-only") 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__ + # Nothing happened + if call.when == "call": + pause = topotest_extra_config["pause_after"] + else: + pause = False - # Treat skips as non errors - if call.excinfo.typename != "AssertionError": - logger.info( - 'assert skipped at "{}/{}": {}'.format( - modname, item.name, call.excinfo.value + if call.excinfo is None: + error = False + else: + parent = item.parent + modname = parent.module.__name__ + + # Treat skips as non errors, don't pause after + if call.excinfo.typename != "AssertionError": + pause = False + error = False + logger.info( + 'assert skipped at "{}/{}": {}'.format( + modname, item.name, call.excinfo.value + ) + ) + else: + error = True + # Handle assert failures + parent._previousfailed = item # pylint: disable=W0212 + logger.error( + 'assert failed 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) - ) - # (topogen) Set topology error to avoid advancing in the test. - tgen = get_topogen() - if tgen is not None: - # This will cause topogen to report error on `routers_have_failure`. - tgen.set_error("{}/{}".format(modname, item.name)) + # (topogen) Set topology error to avoid advancing in the test. + tgen = get_topogen() + if tgen is not None: + # This will cause topogen to report error on `routers_have_failure`. + tgen.set_error("{}/{}".format(modname, item.name)) + + if error and topotest_extra_config["shell_on_error"]: + for router in tgen.routers(): + pause = True + tgen.net[router].runInWindow(os.getenv("SHELL", "bash")) + + if error and topotest_extra_config["vtysh_on_error"]: + for router in tgen.routers(): + pause = True + tgen.net[router].runInWindow("vtysh") + + if error and topotest_extra_config["mininet_on_error"]: + tgen.mininet_cli() + + if pause: + try: + user = raw_input('Testing paused, "pdb" to debug, "Enter" to continue: ') + except NameError: + user = input('Testing paused, "pdb" to debug, "Enter" to continue: ') + if user.strip() == "pdb": + pdb.set_trace() diff --git a/tests/topotests/isis-snmp/test_isis_snmp.py b/tests/topotests/isis-snmp/test_isis_snmp.py index 1bcd0eefc6..07f3335e23 100755 --- a/tests/topotests/isis-snmp/test_isis_snmp.py +++ b/tests/topotests/isis-snmp/test_isis_snmp.py @@ -124,7 +124,6 @@ class TemplateTopo(Topo): switch.add_link(tgen.gears["r3"]) - def setup_module(mod): "Sets up the pytest environment" @@ -148,20 +147,24 @@ def setup_module(mod): # Don't start the following in the CE nodes if router.name[0] == "r": router.load_config( - TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname)), + TopoRouter.RD_ISIS, + os.path.join(CWD, "{}/isisd.conf".format(rname)), "-M snmp", ) router.load_config( - TopoRouter.RD_LDP, os.path.join(CWD, "{}/ldpd.conf".format(rname)), + TopoRouter.RD_LDP, + os.path.join(CWD, "{}/ldpd.conf".format(rname)), ) router.load_config( - TopoRouter.RD_SNMP, os.path.join(CWD, "{}/snmpd.conf".format(rname)), + TopoRouter.RD_SNMP, + os.path.join(CWD, "{}/snmpd.conf".format(rname)), "-Le -Ivacm_conf,usmConf,iquery -V -DAgentX,trap", ) # After loading the configurations, this function loads configured daemons. tgen.start_router() + def teardown_module(mod): "Teardown the pytest environment" tgen = get_topogen() @@ -169,6 +172,7 @@ def teardown_module(mod): # This function tears down the whole topology. tgen.stop_topology() + def router_compare_json_output(rname, command, reference): "Compare router JSON output" @@ -184,6 +188,7 @@ def router_compare_json_output(rname, command, reference): assertmsg = '"{}" JSON output mismatches the expected result'.format(rname) assert diff is None, assertmsg + def generate_oid(numoids, index1, index2): if numoids == 1: oid = "{}".format(index1) @@ -200,7 +205,9 @@ def test_isis_convergence(): router_compare_json_output( rname, "show yang operational-data /frr-interface:lib isisd", - "show_yang_interface_isis_adjacencies.ref") + "show_yang_interface_isis_adjacencies.ref", + ) + def test_r1_scalar_snmp(): "Wait for protocol convergence" @@ -213,26 +220,26 @@ def test_r1_scalar_snmp(): r1 = tgen.net.get("r1") r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") - assert r1_snmp.test_oid('isisSysVersion', "one(1)") - assert r1_snmp.test_oid('isisSysLevelType', "level1and2(3)") - assert r1_snmp.test_oid('isisSysID',"00 00 00 00 00 01") - assert r1_snmp.test_oid('isisSysMaxPathSplits',"32") - assert r1_snmp.test_oid('isisSysMaxLSPGenInt',"900 seconds") - assert r1_snmp.test_oid('isisSysAdminState',"on(1)") - assert r1_snmp.test_oid('isisSysMaxAge',"1200 seconds") - assert r1_snmp.test_oid('isisSysProtSupported',"07 5 6 7") + assert r1_snmp.test_oid("isisSysVersion", "one(1)") + assert r1_snmp.test_oid("isisSysLevelType", "level1and2(3)") + assert r1_snmp.test_oid("isisSysID", "00 00 00 00 00 01") + assert r1_snmp.test_oid("isisSysMaxPathSplits", "32") + assert r1_snmp.test_oid("isisSysMaxLSPGenInt", "900 seconds") + assert r1_snmp.test_oid("isisSysAdminState", "on(1)") + assert r1_snmp.test_oid("isisSysMaxAge", "1200 seconds") + assert r1_snmp.test_oid("isisSysProtSupported", "07 5 6 7") r2 = tgen.net.get("r2") r2_snmp = SnmpTester(r2, "2.2.2.2", "public", "2c") - - assert r2_snmp.test_oid('isisSysVersion', "one(1)") - assert r2_snmp.test_oid('isisSysLevelType', "level1and2(3)") - assert r2_snmp.test_oid('isisSysID',"00 00 00 00 00 02") - assert r2_snmp.test_oid('isisSysMaxPathSplits',"32") - assert r2_snmp.test_oid('isisSysMaxLSPGenInt',"900 seconds") - assert r2_snmp.test_oid('isisSysAdminState',"on(1)") - assert r2_snmp.test_oid('isisSysMaxAge',"1200 seconds") - assert r2_snmp.test_oid('isisSysProtSupported',"07 5 6 7") + + assert r2_snmp.test_oid("isisSysVersion", "one(1)") + assert r2_snmp.test_oid("isisSysLevelType", "level1and2(3)") + assert r2_snmp.test_oid("isisSysID", "00 00 00 00 00 02") + assert r2_snmp.test_oid("isisSysMaxPathSplits", "32") + assert r2_snmp.test_oid("isisSysMaxLSPGenInt", "900 seconds") + assert r2_snmp.test_oid("isisSysAdminState", "on(1)") + assert r2_snmp.test_oid("isisSysMaxAge", "1200 seconds") + assert r2_snmp.test_oid("isisSysProtSupported", "07 5 6 7") circtable_test = { @@ -245,7 +252,8 @@ circtable_test = { "isisCircMeshGroupEnabled": ["inactive(1)", "inactive(1)", "inactive(1)"], "isisCircSmallHellos": ["false(2)", "false(2)", "false(2)"], "isisCirc3WayEnabled": ["false(2)", "false(2)", "false(2)"], - } +} + def test_r1_isisCircTable(): tgen = get_topogen() @@ -256,9 +264,9 @@ def test_r1_isisCircTable(): r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") oids = [] - oids.append(generate_oid(1,1,0)) - oids.append(generate_oid(1,2,0)) - oids.append(generate_oid(1,3,0)) + oids.append(generate_oid(1, 1, 0)) + oids.append(generate_oid(1, 2, 0)) + oids.append(generate_oid(1, 3, 0)) # check items for item in circtable_test.keys(): @@ -267,14 +275,26 @@ def test_r1_isisCircTable(): ) assert r1_snmp.test_oid_walk(item, circtable_test[item], oids), assertmsg + circleveltable_test = { "isisCircLevelMetric": ["10", "10", "10", "10"], "isisCircLevelWideMetric": ["10", "10", "0", "0"], "isisCircLevelISPriority": ["64", "64", "64", "64"], "isisCircLevelHelloMultiplier": ["10", "10", "10", "10"], - "isisCircLevelHelloTimer": ["3000 milliseconds", "3000 milliseconds", "3000 milliseconds", "3000 milliseconds"], - "isisCircLevelMinLSPRetransInt": ["1 seconds", "1 seconds", "0 seconds", "0 seconds"], - } + "isisCircLevelHelloTimer": [ + "3000 milliseconds", + "3000 milliseconds", + "3000 milliseconds", + "3000 milliseconds", + ], + "isisCircLevelMinLSPRetransInt": [ + "1 seconds", + "1 seconds", + "0 seconds", + "0 seconds", + ], +} + def test_r1_isislevelCircTable(): tgen = get_topogen() @@ -285,10 +305,10 @@ def test_r1_isislevelCircTable(): r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") oids = [] - oids.append(generate_oid(2,1,"area")) - oids.append(generate_oid(2,2,"area")) - oids.append(generate_oid(2,3,"area")) - oids.append(generate_oid(2,3,"domain")) + oids.append(generate_oid(2, 1, "area")) + oids.append(generate_oid(2, 2, "area")) + oids.append(generate_oid(2, 3, "area")) + oids.append(generate_oid(2, 3, "domain")) # check items for item in circleveltable_test.keys(): @@ -316,6 +336,7 @@ adjtable_down_test = { "isisISAdjNeighPriority": ["64"], } + def test_r1_isisAdjTable(): "check ISIS Adjacency Table" tgen = get_topogen() @@ -324,11 +345,11 @@ def test_r1_isisAdjTable(): r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") oids = [] - oids.append(generate_oid(2,1,1)) - oids.append(generate_oid(2,2,1)) + oids.append(generate_oid(2, 1, 1)) + oids.append(generate_oid(2, 2, 1)) oids_down = [] - oids_down.append(generate_oid(2,1,1)) + oids_down.append(generate_oid(2, 1, 1)) # check items for item in adjtable_test.keys(): @@ -337,7 +358,6 @@ def test_r1_isisAdjTable(): ) assert r1_snmp.test_oid_walk(item, adjtable_test[item], oids), assertmsg - # shutdown interface and one adjacency should be removed "check ISIS adjacency is removed when interface is shutdown" r1_cmd.vtysh_cmd("conf t\ninterface r1-eth1\nshutdown") @@ -347,7 +367,9 @@ def test_r1_isisAdjTable(): assertmsg = "{} should be {} oids {} full dict {}:".format( item, adjtable_down_test[item], oids_down, r1_snmp.walk(item) ) - assert r1_snmp.test_oid_walk(item, adjtable_down_test[item], oids_down), assertmsg + assert r1_snmp.test_oid_walk( + item, adjtable_down_test[item], oids_down + ), assertmsg # no shutdown interface and adjacency should be restored r1_cmd.vtysh_cmd("conf t\ninterface r1-eth1\nno shutdown") diff --git a/tests/topotests/isis-topo1-vrf/r1/r1_topology.json b/tests/topotests/isis-topo1-vrf/r1/r1_topology.json index 8e3cdc7bd6..1a6fe6d5c6 100644 --- a/tests/topotests/isis-topo1-vrf/r1/r1_topology.json +++ b/tests/topotests/isis-topo1-vrf/r1/r1_topology.json @@ -5,73 +5,73 @@ { "vertex": "r1" } - ], + ], "ipv6": [ { "vertex": "r1" } ] - }, + }, "level-2": { "ipv4": [ { "vertex": "r1" - }, + }, { - "metric": "internal", - "parent": "0", - "type": "IP", + "metric": "0", + "parent": "r1(4)", + "type": "IP internal", "vertex": "10.0.20.0/24" - }, + }, { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r1(4)", - "type": "TE-IS", + "interface": "r1-eth0", + "metric": "10", + "next-hop": "r3", + "parent": "r1(4)", + "type": "TE-IS", "vertex": "r3" - }, + }, { - "interface": "r3", - "metric": "TE", - "next-hop": "20", - "parent": "r1-eth0", - "type": "IP", + "interface": "r1-eth0", + "metric": "20", + "next-hop": "r3", + "parent": "r3(4)", + "type": "IP TE", "vertex": "10.0.20.0/24" - }, + }, { - "interface": "r3", - "metric": "TE", - "next-hop": "20", - "parent": "r1-eth0", - "type": "IP", + "interface": "r1-eth0", + "metric": "20", + "next-hop": "r3", + "parent": "r3(4)", + "type": "IP TE", "vertex": "10.0.10.0/24" } - ], + ], "ipv6": [ { "vertex": "r1" - }, + }, { - "metric": "internal", - "parent": "0", - "type": "IP6", + "metric": "0", + "parent": "r1(4)", + "type": "IP6 internal", "vertex": "2001:db8:1:1::/64" - }, + }, { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r1(4)", - "type": "TE-IS", + "interface": "r1-eth0", + "metric": "10", + "next-hop": "r3", + "parent": "r1(4)", + "type": "TE-IS", "vertex": "r3" - }, + }, { - "interface": "r3", - "metric": "internal", - "next-hop": "20", - "parent": "r1-eth0", - "type": "IP6", + "interface": "r1-eth0", + "metric": "20", + "next-hop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", "vertex": "2001:db8:2:1::/64" } ] diff --git a/tests/topotests/isis-topo1-vrf/r2/r2_topology.json b/tests/topotests/isis-topo1-vrf/r2/r2_topology.json index 72022a8167..a77f7977f9 100644 --- a/tests/topotests/isis-topo1-vrf/r2/r2_topology.json +++ b/tests/topotests/isis-topo1-vrf/r2/r2_topology.json @@ -5,76 +5,76 @@ { "vertex": "r2" } - ], + ], "ipv6": [ { "vertex": "r2" } ] - }, + }, "level-2": { "ipv4": [ { "vertex": "r2" - }, + }, { - "metric": "internal", - "parent": "0", - "type": "IP", + "metric": "0", + "parent": "r2(4)", + "type": "IP internal", "vertex": "10.0.21.0/24" - }, + }, { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r2(4)", - "type": "TE-IS", + "interface": "r2-eth0", + "metric": "10", + "next-hop": "r4", + "parent": "r2(4)", + "type": "TE-IS", "vertex": "r4" - }, + }, { - "interface": "r4", - "metric": "TE", - "next-hop": "20", - "parent": "r2-eth0", - "type": "IP", + "interface": "r2-eth0", + "metric": "20", + "next-hop": "r4", + "parent": "r4(4)", + "type": "IP TE", "vertex": "10.0.21.0/24" - }, + }, { - "interface": "r4", - "metric": "TE", - "next-hop": "20", - "parent": "r2-eth0", - "type": "IP", + "interface": "r2-eth0", + "metric": "20", + "next-hop": "r4", + "parent": "r4(4)", + "type": "IP TE", "vertex": "10.0.11.0/24" } - ], + ], "ipv6": [ { "vertex": "r2" - }, + }, { - "metric": "internal", - "parent": "0", - "type": "IP6", + "metric": "0", + "parent": "r2(4)", + "type": "IP6 internal", "vertex": "2001:db8:1:2::/64" - }, + }, { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r2(4)", - "type": "TE-IS", + "interface": "r2-eth0", + "metric": "10", + "next-hop": "r4", + "parent": "r2(4)", + "type": "TE-IS", "vertex": "r4" - }, + }, { - "interface": "r4", - "metric": "internal", - "next-hop": "20", - "parent": "r2-eth0", - "type": "IP6", + "interface": "r2-eth0", + "metric": "20", + "next-hop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", "vertex": "2001:db8:2:2::/64" } ] } } -}
\ No newline at end of file +} diff --git a/tests/topotests/isis-topo1-vrf/r3/r3_topology.json b/tests/topotests/isis-topo1-vrf/r3/r3_topology.json index 62b895766e..1e5d331965 100644 --- a/tests/topotests/isis-topo1-vrf/r3/r3_topology.json +++ b/tests/topotests/isis-topo1-vrf/r3/r3_topology.json @@ -4,126 +4,126 @@ "ipv4": [ { "vertex": "r3" - }, + }, { - "metric": "internal", - "parent": "0", - "type": "IP", + "metric": "0", + "parent": "r3(4)", + "type": "IP internal", "vertex": "10.0.10.0/24" - }, + }, { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r3(4)", - "type": "TE-IS", + "interface": "r3-eth1", + "metric": "10", + "next-hop": "r5", + "parent": "r3(4)", + "type": "TE-IS", "vertex": "r5" - }, + }, { - "interface": "r5", - "metric": "TE", - "next-hop": "20", - "parent": "r3-eth1", - "type": "IP", + "interface": "r3-eth1", + "metric": "20", + "next-hop": "r5", + "parent": "r5(4)", + "type": "IP TE", "vertex": "10.0.10.0/24" - }, + }, { - "interface": "r5", - "metric": "TE", - "next-hop": "20", - "parent": "r3-eth1", - "type": "IP", + "interface": "r3-eth1", + "metric": "20", + "next-hop": "r5", + "parent": "r5(4)", + "type": "IP TE", "vertex": "10.0.11.0/24" - }, + }, { - "interface": "r5", - "metric": "TE", - "next-hop": "30", - "parent": "r3-eth1", - "type": "IP", + "interface": "r3-eth1", + "metric": "30", + "next-hop": "r5", + "parent": "r4(4)", + "type": "IP TE", "vertex": "10.0.21.0/24" } - ], + ], "ipv6": [ { "vertex": "r3" - }, + }, { - "metric": "internal", - "parent": "0", - "type": "IP6", + "metric": "0", + "parent": "r3(4)", + "type": "IP6 internal", "vertex": "2001:db8:2:1::/64" - }, + }, { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r3(4)", - "type": "TE-IS", + "interface": "r3-eth1", + "metric": "10", + "next-hop": "r5", + "parent": "r3(4)", + "type": "TE-IS", "vertex": "r5" - }, + }, { - "interface": "r5", - "metric": "internal", - "next-hop": "20", - "parent": "r3-eth1", - "type": "IP6", + "interface": "r3-eth1", + "metric": "20", + "next-hop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", "vertex": "2001:db8:2:2::/64" - }, + }, { - "interface": "r5", - "metric": "internal", - "next-hop": "30", - "parent": "r3-eth1", - "type": "IP6", + "interface": "r3-eth1", + "metric": "30", + "next-hop": "r5", + "parent": "r4(4)", + "type": "IP6 internal", "vertex": "2001:db8:1:2::/64" } ] - }, + }, "level-2": { "ipv4": [ { "vertex": "r3" - }, + }, { - "metric": "internal", - "parent": "0", - "type": "IP", + "metric": "0", + "parent": "r3(4)", + "type": "IP internal", "vertex": "10.0.20.0/24" - }, + }, { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "TE-IS", + "interface": "r3-eth0", + "metric": "10", + "next-hop": "r3", + "parent": "r3(4)", + "type": "TE-IS", "vertex": "r3" - }, + }, { - "interface": "r3", - "metric": "TE", - "next-hop": "20", - "parent": "r3-eth0", - "type": "IP", + "interface": "r3-eth0", + "metric": "20", + "next-hop": "r3", + "parent": "r3(4)", + "type": "IP TE", "vertex": "10.0.20.0/24" } - ], + ], "ipv6": [ { "vertex": "r3" - }, + }, { - "metric": "internal", - "parent": "0", - "type": "IP6", + "metric": "0", + "parent": "r3(4)", + "type": "IP6 internal", "vertex": "2001:db8:1:1::/64" - }, + }, { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "TE-IS", + "interface": "r3-eth0", + "metric": "10", + "next-hop": "r3", + "parent": "r3(4)", + "type": "TE-IS", "vertex": "r3" } ] diff --git a/tests/topotests/isis-topo1-vrf/r4/r4_topology.json b/tests/topotests/isis-topo1-vrf/r4/r4_topology.json index 0d69550cad..34f5ac9ca4 100644 --- a/tests/topotests/isis-topo1-vrf/r4/r4_topology.json +++ b/tests/topotests/isis-topo1-vrf/r4/r4_topology.json @@ -4,126 +4,126 @@ "ipv4": [ { "vertex": "r4" - }, + }, { - "metric": "internal", - "parent": "0", - "type": "IP", + "metric": "0", + "parent": "r4(4)", + "type": "IP internal", "vertex": "10.0.11.0/24" - }, + }, { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r4(4)", - "type": "TE-IS", + "interface": "r4-eth1", + "metric": "10", + "next-hop": "r5", + "parent": "r4(4)", + "type": "TE-IS", "vertex": "r5" - }, + }, { - "interface": "r5", - "metric": "TE", - "next-hop": "20", - "parent": "r4-eth1", - "type": "IP", + "interface": "r4-eth1", + "metric": "20", + "next-hop": "r5", + "parent": "r5(4)", + "type": "IP TE", "vertex": "10.0.10.0/24" - }, + }, { - "interface": "r5", - "metric": "TE", - "next-hop": "20", - "parent": "r4-eth1", - "type": "IP", + "interface": "r4-eth1", + "metric": "20", + "next-hop": "r5", + "parent": "r5(4)", + "type": "IP TE", "vertex": "10.0.11.0/24" - }, + }, { - "interface": "r5", - "metric": "TE", - "next-hop": "30", - "parent": "r4-eth1", - "type": "IP", + "interface": "r4-eth1", + "metric": "30", + "next-hop": "r5", + "parent": "r3(4)", + "type": "IP TE", "vertex": "10.0.20.0/24" } - ], + ], "ipv6": [ { "vertex": "r4" - }, + }, { - "metric": "internal", - "parent": "0", - "type": "IP6", + "metric": "0", + "parent": "r4(4)", + "type": "IP6 internal", "vertex": "2001:db8:2:2::/64" - }, + }, { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r4(4)", - "type": "TE-IS", + "interface": "r4-eth1", + "metric": "10", + "next-hop": "r5", + "parent": "r4(4)", + "type": "TE-IS", "vertex": "r5" - }, + }, { - "interface": "r5", - "metric": "internal", - "next-hop": "20", - "parent": "r4-eth1", - "type": "IP6", + "interface": "r4-eth1", + "metric": "20", + "next-hop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", "vertex": "2001:db8:2:1::/64" - }, + }, { - "interface": "r5", - "metric": "internal", - "next-hop": "30", - "parent": "r4-eth1", - "type": "IP6", + "interface": "r4-eth1", + "metric": "30", + "next-hop": "r5", + "parent": "r3(4)", + "type": "IP6 internal", "vertex": "2001:db8:1:1::/64" } ] - }, + }, "level-2": { "ipv4": [ { "vertex": "r4" - }, + }, { - "metric": "internal", - "parent": "0", - "type": "IP", + "metric": "0", + "parent": "r4(4)", + "type": "IP internal", "vertex": "10.0.21.0/24" - }, + }, { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r4(4)", - "type": "TE-IS", + "interface": "r4-eth0", + "metric": "10", + "next-hop": "r2", + "parent": "r4(4)", + "type": "TE-IS", "vertex": "r2" - }, + }, { - "interface": "r2", - "metric": "TE", - "next-hop": "20", - "parent": "r4-eth0", - "type": "IP", + "interface": "r4-eth0", + "metric": "20", + "next-hop": "r2", + "parent": "r2(4)", + "type": "IP TE", "vertex": "10.0.21.0/24" } - ], + ], "ipv6": [ { "vertex": "r4" - }, + }, { - "metric": "internal", - "parent": "0", - "type": "IP6", + "metric": "0", + "parent": "r4(4)", + "type": "IP6 internal", "vertex": "2001:db8:1:2::/64" - }, + }, { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r4(4)", - "type": "TE-IS", + "interface": "r4-eth0", + "metric": "10", + "next-hop": "r2", + "parent": "r4(4)", + "type": "TE-IS", "vertex": "r2" } ] diff --git a/tests/topotests/isis-topo1-vrf/r5/r5_topology.json b/tests/topotests/isis-topo1-vrf/r5/r5_topology.json index b4ed6a069d..ace56536e9 100644 --- a/tests/topotests/isis-topo1-vrf/r5/r5_topology.json +++ b/tests/topotests/isis-topo1-vrf/r5/r5_topology.json @@ -4,121 +4,121 @@ "ipv4": [ { "vertex": "r5" - }, + }, { - "metric": "internal", - "parent": "0", - "type": "IP", + "metric": "0", + "parent": "r5(4)", + "type": "IP internal", "vertex": "10.0.10.0/24" - }, + }, { - "metric": "internal", - "parent": "0", - "type": "IP", + "metric": "0", + "parent": "r5(4)", + "type": "IP internal", "vertex": "10.0.11.0/24" - }, + }, { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r5(4)", - "type": "TE-IS", + "interface": "r5-eth0", + "metric": "10", + "next-hop": "r3", + "parent": "r5(4)", + "type": "TE-IS", "vertex": "r3" - }, + }, { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r5(4)", - "type": "TE-IS", + "interface": "r5-eth1", + "metric": "10", + "next-hop": "r4", + "parent": "r5(4)", + "type": "TE-IS", "vertex": "r4" - }, + }, { - "interface": "r3", - "metric": "TE", - "next-hop": "20", - "parent": "r5-eth0", - "type": "IP", + "interface": "r5-eth0", + "metric": "20", + "next-hop": "r3", + "parent": "r3(4)", + "type": "IP TE", "vertex": "10.0.20.0/24" - }, + }, { - "interface": "r3", - "metric": "TE", - "next-hop": "20", - "parent": "r5-eth0", - "type": "IP", + "interface": "r5-eth0", + "metric": "20", + "next-hop": "r3", + "parent": "r3(4)", + "type": "IP TE", "vertex": "10.0.10.0/24" - }, + }, { - "interface": "r4", - "metric": "TE", - "next-hop": "20", - "parent": "r5-eth1", - "type": "IP", + "interface": "r5-eth1", + "metric": "20", + "next-hop": "r4", + "parent": "r4(4)", + "type": "IP TE", "vertex": "10.0.21.0/24" - }, + }, { - "interface": "r4", - "metric": "TE", - "next-hop": "20", - "parent": "r5-eth1", - "type": "IP", + "interface": "r5-eth1", + "metric": "20", + "next-hop": "r4", + "parent": "r4(4)", + "type": "IP TE", "vertex": "10.0.11.0/24" } - ], + ], "ipv6": [ { "vertex": "r5" - }, + }, { - "metric": "internal", - "parent": "0", - "type": "IP6", + "metric": "0", + "parent": "r5(4)", + "type": "IP6 internal", "vertex": "2001:db8:2:1::/64" - }, + }, { - "metric": "internal", - "parent": "0", - "type": "IP6", + "metric": "0", + "parent": "r5(4)", + "type": "IP6 internal", "vertex": "2001:db8:2:2::/64" - }, + }, { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r5(4)", - "type": "TE-IS", + "interface": "r5-eth0", + "metric": "10", + "next-hop": "r3", + "parent": "r5(4)", + "type": "TE-IS", "vertex": "r3" - }, + }, { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r5(4)", - "type": "TE-IS", + "interface": "r5-eth1", + "metric": "10", + "next-hop": "r4", + "parent": "r5(4)", + "type": "TE-IS", "vertex": "r4" - }, + }, { - "interface": "r3", - "metric": "internal", - "next-hop": "20", - "parent": "r5-eth0", - "type": "IP6", + "interface": "r5-eth0", + "metric": "20", + "next-hop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", "vertex": "2001:db8:1:1::/64" - }, + }, { - "interface": "r4", - "metric": "internal", - "next-hop": "20", - "parent": "r5-eth1", - "type": "IP6", + "interface": "r5-eth1", + "metric": "20", + "next-hop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", "vertex": "2001:db8:1:2::/64" } ] - }, + }, "level-2": { - "ipv4": [], + "ipv4": [], "ipv6": [] } } -}
\ No newline at end of file +} diff --git a/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py index 6ab78c385e..b7fe0c2ddb 100644 --- a/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py +++ b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py @@ -40,11 +40,30 @@ sys.path.append(os.path.join(CWD, "../")) from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger +from lib.topotest import iproute2_is_vrf_capable +from lib.common_config import ( + required_linux_kernel_version, + adjust_router_l3mdev, +) from mininet.topo import Topo pytestmark = [pytest.mark.isisd] +VERTEX_TYPE_LIST = [ + "pseudo_IS", + "pseudo_TE-IS", + "IS", + "TE-IS", + "ES", + "IP internal", + "IP external", + "IP TE", + "IP6 internal", + "IP6 external", + "UNKNOWN", +] + class ISISTopo1(Topo): "Simple two layer ISIS vrf topology" @@ -91,22 +110,6 @@ def setup_module(mod): tgen.start_topology() logger.info("Testing with VRF Lite support") - krel = platform.release() - - # May need to adjust handling of vrf traffic depending on kernel version - l3mdev_accept = 0 - if ( - topotest.version_cmp(krel, "4.15") >= 0 - and topotest.version_cmp(krel, "4.18") <= 0 - ): - l3mdev_accept = 1 - - if topotest.version_cmp(krel, "5.0") >= 0: - l3mdev_accept = 1 - - logger.info( - "krel '{0}' setting net.ipv4.tcp_l3mdev_accept={1}".format(krel, l3mdev_accept) - ) cmds = [ "ip link add {0}-cust1 type vrf table 1001", @@ -120,15 +123,9 @@ def setup_module(mod): # create VRF rx-cust1 and link rx-eth0 to rx-cust1 for cmd in cmds: output = tgen.net[rname].cmd(cmd.format(rname)) - output = tgen.net[rname].cmd("sysctl -n net.ipv4.tcp_l3mdev_accept") - logger.info( - "router {0}: existing tcp_l3mdev_accept was {1}".format(rname, output) - ) - if l3mdev_accept: - output = tgen.net[rname].cmd( - "sysctl -w net.ipv4.tcp_l3mdev_accept={}".format(l3mdev_accept) - ) + # adjust handling of vrf traffic + adjust_router_l3mdev(tgen, rname) for rname, router in tgen.routers().items(): router.load_config( @@ -193,18 +190,21 @@ def test_isis_route_installation(): def test_isis_linux_route_installation(): - - dist = platform.dist() - - if dist[1] == "16.04": - pytest.skip("Kernel not supported for vrf") - "Check whether all expected routes are present and installed in the OS" tgen = get_topogen() # Don't run this test if we have any failure. if tgen.routers_have_failure(): pytest.skip(tgen.errors) + # Required linux kernel version for this suite to run. + result = required_linux_kernel_version("4.15") + if result is not True: + pytest.skip("Kernel requirements are not met") + + # iproute2 needs to support VRFs for this suite to run. + if not iproute2_is_vrf_capable(): + pytest.skip("Installed iproute2 version does not support VRFs") + logger.info("Checking routers for installed ISIS vrf routes in OS") # Check for routes in `ip route show vrf {}-cust1` for rname, router in tgen.routers().items(): @@ -236,18 +236,21 @@ def test_isis_route6_installation(): def test_isis_linux_route6_installation(): - - dist = platform.dist() - - if dist[1] == "16.04": - pytest.skip("Kernel not supported for vrf") - "Check whether all expected routes are present and installed in the OS" tgen = get_topogen() # Don't run this test if we have any failure. if tgen.routers_have_failure(): pytest.skip(tgen.errors) + # Required linux kernel version for this suite to run. + result = required_linux_kernel_version("4.15") + if result is not True: + pytest.skip("Kernel requirements are not met") + + # iproute2 needs to support VRFs for this suite to run. + if not iproute2_is_vrf_capable(): + pytest.skip("Installed iproute2 version does not support VRFs") + logger.info("Checking routers for installed ISIS vrf IPv6 routes in OS") # Check for routes in `ip -6 route show vrf {}-cust1` for rname, router in tgen.routers().items(): @@ -308,6 +311,7 @@ def parse_topology(lines, level): areas = {} area = None ipv = None + vertex_type_regex = "|".join(VERTEX_TYPE_LIST) for line in lines: area_match = re.match(r"Area (.+):", line) @@ -327,44 +331,57 @@ def parse_topology(lines, level): ipv = "ipv4" continue - item_match = re.match(r"([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+)", line) - if item_match is not None: + item_match = re.match( + r"([^\s]+) ([^\s]+) ([^\s]+) ([^\s]+) ([^\s]+) ([^\s]+)", line + ) + if ( + item_match is not None + and item_match.group(1) == "Vertex" + and item_match.group(2) == "Type" + and item_match.group(3) == "Metric" + and item_match.group(4) == "Next-Hop" + and item_match.group(5) == "Interface" + and item_match.group(6) == "Parent" + ): # Skip header - if ( - item_match.group(1) == "Vertex" - and item_match.group(2) == "Type" - and item_match.group(3) == "Metric" - and item_match.group(4) == "Next-Hop" - and item_match.group(5) == "Interface" - and item_match.group(6) == "Parent" - ): - continue + continue + item_match = re.match( + r"([^\s]+) ({}) ([0]|([1-9][0-9]*)) ([^\s]+) ([^\s]+) ([^\s]+)".format( + vertex_type_regex + ), + line, + ) + if item_match is not None: areas[area][level][ipv].append( { "vertex": item_match.group(1), "type": item_match.group(2), "metric": item_match.group(3), - "next-hop": item_match.group(4), - "interface": item_match.group(5), - "parent": item_match.group(6), + "next-hop": item_match.group(5), + "interface": item_match.group(6), + "parent": item_match.group(7), } ) continue - item_match = re.match(r"([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+)", line) + item_match = re.match( + r"([^\s]+) ({}) ([0]|([1-9][0-9]*)) ([^\s]+)".format(vertex_type_regex), + line, + ) + if item_match is not None: areas[area][level][ipv].append( { "vertex": item_match.group(1), "type": item_match.group(2), "metric": item_match.group(3), - "parent": item_match.group(4), + "parent": item_match.group(5), } ) continue - item_match = re.match(r"([^ ]+)", line) + item_match = re.match(r"([^\s]+)", line) if item_match is not None: areas[area][level][ipv].append({"vertex": item_match.group(1)}) continue diff --git a/tests/topotests/ldp-snmp/test_ldp_snmp_topo1.py b/tests/topotests/ldp-snmp/test_ldp_snmp_topo1.py index 4144f9b261..f47d906157 100644 --- a/tests/topotests/ldp-snmp/test_ldp_snmp_topo1.py +++ b/tests/topotests/ldp-snmp/test_ldp_snmp_topo1.py @@ -141,15 +141,16 @@ def setup_module(mod): TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname)) ) router.load_config( - TopoRouter.RD_LDP, os.path.join(CWD, "{}/ldpd.conf".format(rname)), - "-M snmp" + TopoRouter.RD_LDP, + os.path.join(CWD, "{}/ldpd.conf".format(rname)), + "-M snmp", ) router.load_config( - TopoRouter.RD_SNMP, os.path.join(CWD, "{}/snmpd.conf".format(rname)), - "-Le -Ivacm_conf,usmConf,iquery -V -DAgentX,trap" + TopoRouter.RD_SNMP, + os.path.join(CWD, "{}/snmpd.conf".format(rname)), + "-Le -Ivacm_conf,usmConf,iquery -V -DAgentX,trap", ) - tgen.start_router() @@ -199,7 +200,7 @@ def test_rib(): # Skip if previous fatal error condition is raised # TODO: disabling this check to avoid 'snmpd not running' errors - #if tgen.routers_have_failure(): + # if tgen.routers_have_failure(): # pytest.skip(tgen.errors) for rname in ["r1", "r2", "r3"]: @@ -212,7 +213,7 @@ def test_ldp_adjacencies(): # Skip if previous fatal error condition is raised # TODO: disabling this check to avoid 'snmpd not running' errors - #if tgen.routers_have_failure(): + # if tgen.routers_have_failure(): # pytest.skip(tgen.errors) for rname in ["r1", "r2", "r3"]: @@ -226,7 +227,7 @@ def test_ldp_neighbors(): tgen = get_topogen() # Skip if previous fatal error condition is raised - #if tgen.routers_have_failure(): + # if tgen.routers_have_failure(): # pytest.skip(tgen.errors) for rname in ["r1", "r2", "r3"]: @@ -242,8 +243,8 @@ def test_r1_ldp_lsr_objects(): r1 = tgen.net.get("r1") r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") - assert r1_snmp.test_oid('mplsLdpLsrId', "01 01 01 01") - assert r1_snmp.test_oid('mplsLdpLsrLoopDetectionCapable', 'none(1)') + assert r1_snmp.test_oid("mplsLdpLsrId", "01 01 01 01") + assert r1_snmp.test_oid("mplsLdpLsrLoopDetectionCapable", "none(1)") def test_r1_ldp_entity_table(): @@ -253,52 +254,31 @@ def test_r1_ldp_entity_table(): r1 = tgen.net.get("r1") r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityLdpId', ['1.1.1.1:0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityIndex', ['1']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityProtocolVersion', ['1']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityAdminStatus', ['enable(1)']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityOperStatus', ['enabled(2)']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityTcpPort', ['646']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityUdpDscPort', ['646']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityMaxPduLength', ['4096 octets']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityKeepAliveHoldTimer', ['180 seconds']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityHelloHoldTimer', ['0 seconds']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityInitSessionThreshold', ['0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityLabelDistMethod', ['downstreamUnsolicited(2)']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityLabelRetentionMode', ['liberal(2)']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityPathVectorLimit', ['0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityHopCountLimit', ['0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityTransportAddrKind', ['loopback(2)']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityTargetPeer', ['true(1)']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityTargetPeerAddrType', ['ipv4(1)']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityTargetPeerAddr', ['01 01 01 01']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityLabelType', ['generic(1)']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityDiscontinuityTime', ['(0) 0:00:00.00']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityStorageType', ['nonVolatile(3)']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityRowStatus', ['createAndGo(4)']) + assert r1_snmp.test_oid_walk("mplsLdpEntityLdpId", ["1.1.1.1:0"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityIndex", ["1"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityProtocolVersion", ["1"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityAdminStatus", ["enable(1)"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityOperStatus", ["enabled(2)"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityTcpPort", ["646"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityUdpDscPort", ["646"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityMaxPduLength", ["4096 octets"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityKeepAliveHoldTimer", ["180 seconds"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityHelloHoldTimer", ["0 seconds"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityInitSessionThreshold", ["0"]) + assert r1_snmp.test_oid_walk( + "mplsLdpEntityLabelDistMethod", ["downstreamUnsolicited(2)"] + ) + assert r1_snmp.test_oid_walk("mplsLdpEntityLabelRetentionMode", ["liberal(2)"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityPathVectorLimit", ["0"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityHopCountLimit", ["0"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityTransportAddrKind", ["loopback(2)"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityTargetPeer", ["true(1)"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityTargetPeerAddrType", ["ipv4(1)"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityTargetPeerAddr", ["01 01 01 01"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityLabelType", ["generic(1)"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityDiscontinuityTime", ["(0) 0:00:00.00"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityStorageType", ["nonVolatile(3)"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityRowStatus", ["createAndGo(4)"]) def test_r1_ldp_entity_stats_table(): @@ -308,32 +288,23 @@ def test_r1_ldp_entity_stats_table(): r1 = tgen.net.get("r1") r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") + assert r1_snmp.test_oid_walk("mplsLdpEntityStatsSessionAttempts", ["0"]) assert r1_snmp.test_oid_walk( - 'mplsLdpEntityStatsSessionAttempts', ['0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityStatsSessionRejectedNoHelloErrors', ['0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityStatsSessionRejectedAdErrors', ['0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityStatsSessionRejectedMaxPduErrors', ['0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityStatsSessionRejectedLRErrors', ['0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityStatsBadLdpIdentifierErrors', ['0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityStatsBadPduLengthErrors', ['0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityStatsBadMessageLengthErrors', ['0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityStatsBadTlvLengthErrors', ['0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityStatsMalformedTlvValueErrors', ['0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityStatsKeepAliveTimerExpErrors', ['0']) + "mplsLdpEntityStatsSessionRejectedNoHelloErrors", ["0"] + ) + assert r1_snmp.test_oid_walk("mplsLdpEntityStatsSessionRejectedAdErrors", ["0"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityStatsSessionRejectedMaxPduErrors", ["0"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityStatsSessionRejectedLRErrors", ["0"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityStatsBadLdpIdentifierErrors", ["0"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityStatsBadPduLengthErrors", ["0"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityStatsBadMessageLengthErrors", ["0"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityStatsBadTlvLengthErrors", ["0"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityStatsMalformedTlvValueErrors", ["0"]) + assert r1_snmp.test_oid_walk("mplsLdpEntityStatsKeepAliveTimerExpErrors", ["0"]) assert r1_snmp.test_oid_walk( - 'mplsLdpEntityStatsShutdownReceivedNotifications', ['0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpEntityStatsShutdownSentNotifications', ['0']) + "mplsLdpEntityStatsShutdownReceivedNotifications", ["0"] + ) + assert r1_snmp.test_oid_walk("mplsLdpEntityStatsShutdownSentNotifications", ["0"]) def test_r1_ldp_peer_table(): @@ -343,17 +314,16 @@ def test_r1_ldp_peer_table(): r1 = tgen.net.get("r1") r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") + assert r1_snmp.test_oid_walk("mplsLdpPeerLdpId", ["2.2.2.2:0", "3.3.3.3:0"]) assert r1_snmp.test_oid_walk( - 'mplsLdpPeerLdpId', ['2.2.2.2:0', '3.3.3.3:0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpPeerLabelDistMethod', - ['downstreamUnsolicited(2)', 'downstreamUnsolicited(2)']) - assert r1_snmp.test_oid_walk( - 'mplsLdpPeerPathVectorLimit', ['0', '0']) + "mplsLdpPeerLabelDistMethod", + ["downstreamUnsolicited(2)", "downstreamUnsolicited(2)"], + ) + assert r1_snmp.test_oid_walk("mplsLdpPeerPathVectorLimit", ["0", "0"]) + assert r1_snmp.test_oid_walk("mplsLdpPeerTransportAddrType", ["ipv4(1)", "ipv4(1)"]) assert r1_snmp.test_oid_walk( - 'mplsLdpPeerTransportAddrType', ['ipv4(1)', 'ipv4(1)']) - assert r1_snmp.test_oid_walk( - 'mplsLdpPeerTransportAddr', ['02 02 02 02', '03 03 03 03']) + "mplsLdpPeerTransportAddr", ["02 02 02 02", "03 03 03 03"] + ) def test_r1_ldp_session_table(): @@ -363,18 +333,20 @@ def test_r1_ldp_session_table(): r1 = tgen.net.get("r1") r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") - assert r1_snmp.test_oid_walk('mplsLdpSessionState', - ['operational(5)', 'operational(5)']) - assert r1_snmp.test_oid_walk('mplsLdpSessionRole', - ['passive(3)', 'passive(3)']) - assert r1_snmp.test_oid_walk('mplsLdpSessionProtocolVersion', - ['1', '1']) - assert r1_snmp.test_oid_walk('mplsLdpSessionKeepAliveTime', - ['180 seconds', '180 seconds']) - assert r1_snmp.test_oid_walk('mplsLdpSessionMaxPduLength', - ['4096 octets', '4096 octets']) - assert r1_snmp.test_oid_walk('mplsLdpSessionDiscontinuityTime', - ['(0) 0:00:00.00', '(0) 0:00:00.00']) + assert r1_snmp.test_oid_walk( + "mplsLdpSessionState", ["operational(5)", "operational(5)"] + ) + assert r1_snmp.test_oid_walk("mplsLdpSessionRole", ["passive(3)", "passive(3)"]) + assert r1_snmp.test_oid_walk("mplsLdpSessionProtocolVersion", ["1", "1"]) + assert r1_snmp.test_oid_walk( + "mplsLdpSessionKeepAliveTime", ["180 seconds", "180 seconds"] + ) + assert r1_snmp.test_oid_walk( + "mplsLdpSessionMaxPduLength", ["4096 octets", "4096 octets"] + ) + assert r1_snmp.test_oid_walk( + "mplsLdpSessionDiscontinuityTime", ["(0) 0:00:00.00", "(0) 0:00:00.00"] + ) def test_r1_ldp_session_stats_table(): @@ -384,10 +356,8 @@ def test_r1_ldp_session_stats_table(): r1 = tgen.net.get("r1") r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") - assert r1_snmp.test_oid_walk( - 'mplsLdpSessionStatsUnknownMesTypeErrors', ['0', '0']) - assert r1_snmp.test_oid_walk( - 'mplsLdpSessionStatsUnknownTlvErrors', ['0', '0']) + assert r1_snmp.test_oid_walk("mplsLdpSessionStatsUnknownMesTypeErrors", ["0", "0"]) + assert r1_snmp.test_oid_walk("mplsLdpSessionStatsUnknownTlvErrors", ["0", "0"]) def test_r1_ldp_hello_adjacency_table(): @@ -397,12 +367,11 @@ def test_r1_ldp_hello_adjacency_table(): r1 = tgen.net.get("r1") r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") - assert r1_snmp.test_oid_walk('mplsLdpHelloAdjacencyIndex', - ['1', '2', '1']) - assert r1_snmp.test_oid_walk('mplsLdpHelloAdjacencyHoldTime', - ['15', '45', '15']) - assert r1_snmp.test_oid_walk('mplsLdpHelloAdjacencyType', - ['link(1)', 'targeted(2)', 'link(1)']) + assert r1_snmp.test_oid_walk("mplsLdpHelloAdjacencyIndex", ["1", "2", "1"]) + assert r1_snmp.test_oid_walk("mplsLdpHelloAdjacencyHoldTime", ["15", "45", "15"]) + assert r1_snmp.test_oid_walk( + "mplsLdpHelloAdjacencyType", ["link(1)", "targeted(2)", "link(1)"] + ) # Memory leak test template diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index 867831e114..d2212d1807 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -43,7 +43,7 @@ from lib.common_config import ( run_frr_cmd, FRRCFG_FILE, retry, - get_ipv6_linklocal_address + get_ipv6_linklocal_address, ) LOGDIR = "/tmp/topotests/" @@ -1582,7 +1582,7 @@ def verify_bgp_convergence_from_running_config(tgen, dut=None): return True -def clear_bgp(tgen, addr_type, router, vrf=None): +def clear_bgp(tgen, addr_type, router, vrf=None, neighbor=None): """ This API is to clear bgp neighborship by running clear ip bgp */clear bgp ipv6 * command, @@ -1593,6 +1593,7 @@ def clear_bgp(tgen, addr_type, router, vrf=None): * `addr_type`: ip type ipv4/ipv6 * `router`: device under test * `vrf`: vrf name + * `neighbor`: Neighbor for which bgp needs to be cleared Usage ----- @@ -1616,12 +1617,16 @@ def clear_bgp(tgen, addr_type, router, vrf=None): if vrf: for _vrf in vrf: run_frr_cmd(rnode, "clear ip bgp vrf {} *".format(_vrf)) + elif neighbor: + run_frr_cmd(rnode, "clear bgp ipv4 {}".format(neighbor)) else: run_frr_cmd(rnode, "clear ip bgp *") elif addr_type == "ipv6": if vrf: for _vrf in vrf: run_frr_cmd(rnode, "clear bgp vrf {} ipv6 *".format(_vrf)) + elif neighbor: + run_frr_cmd(rnode, "clear bgp ipv6 {}".format(neighbor)) else: run_frr_cmd(rnode, "clear bgp ipv6 *") else: diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index a4c98924b6..ead593d2ca 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -72,6 +72,59 @@ config.read(PYTESTINI_PATH) config_section = "topogen" +# Debug logs for daemons +DEBUG_LOGS = { + "pimd": [ + "debug msdp events", + "debug msdp packets", + "debug igmp events", + "debug igmp trace", + "debug mroute", + "debug mroute detail", + "debug pim events", + "debug pim packets", + "debug pim trace", + "debug pim zebra", + "debug pim bsm", + "debug pim packets joins", + "debug pim packets register", + "debug pim nht", + ], + "bgpd": [ + "debug bgp neighbor-events", + "debug bgp updates", + "debug bgp zebra", + "debug bgp nht", + "debug bgp neighbor-events", + "debug bgp graceful-restart", + "debug bgp update-groups", + "debug bgp vpn leak-from-vrf", + "debug bgp vpn leak-to-vrf", + "debug bgp zebr", + "debug bgp updates", + "debug bgp nht", + "debug bgp neighbor-events", + "debug vrf", + ], + "zebra": [ + "debug zebra events", + "debug zebra rib", + "debug zebra vxlan", + "debug zebra nht", + ], + "ospf": [ + "debug ospf event", + "debug ospf ism", + "debug ospf lsa", + "debug ospf nsm", + "debug ospf nssa", + "debug ospf packet all", + "debug ospf sr", + "debug ospf te", + "debug ospf zebra", + ], +} + if config.has_option("topogen", "verbosity"): loglevel = config.get("topogen", "verbosity") loglevel = loglevel.upper() @@ -249,6 +302,7 @@ def create_common_configuration( config_map = OrderedDict( { "general_config": "! FRR General Config\n", + "debug_log_config": "! Debug log Config\n", "interface_config": "! Interfaces Config\n", "static_route": "! Static Route Config\n", "prefix_list": "! Prefix List Config\n", @@ -1052,6 +1106,89 @@ def tcpdump_capture_stop(tgen, router): return True +def create_debug_log_config(tgen, input_dict, build=False): + """ + Enable/disable debug logs for any protocol with defined debug + options and logs would be saved to created log file + + Parameters + ---------- + * `tgen` : Topogen object + * `input_dict` : details to enable debug logs for protocols + * `build` : Only for initial setup phase this is set as True. + + + Usage: + ------ + input_dict = { + "r2": { + "debug":{ + "log_file" : "debug.log", + "enable": ["pimd", "zebra"], + "disable": { + "bgpd":[ + 'debug bgp neighbor-events', + 'debug bgp updates', + 'debug bgp zebra', + ] + } + } + } + } + + result = create_debug_log_config(tgen, input_dict) + + Returns + ------- + True or False + """ + + result = False + try: + for router in input_dict.keys(): + debug_config = [] + if "debug" in input_dict[router]: + debug_dict = input_dict[router]["debug"] + + disable_logs = debug_dict.setdefault("disable", None) + enable_logs = debug_dict.setdefault("enable", None) + log_file = debug_dict.setdefault("log_file", None) + + if log_file: + _log_file = os.path.join(LOGDIR, tgen.modname, log_file) + debug_config.append("log file {} \n".format(_log_file)) + + if type(enable_logs) is list: + for daemon in enable_logs: + for debug_log in DEBUG_LOGS[daemon]: + debug_config.append("{}".format(debug_log)) + elif type(enable_logs) is dict: + for daemon, debug_logs in enable_logs.items(): + for debug_log in debug_logs: + debug_config.append("{}".format(debug_log)) + + if type(disable_logs) is list: + for daemon in disable_logs: + for debug_log in DEBUG_LOGS[daemon]: + debug_config.append("no {}".format(debug_log)) + elif type(disable_logs) is dict: + for daemon, debug_logs in disable_logs.items(): + for debug_log in debug_logs: + debug_config.append("no {}".format(debug_log)) + + result = create_common_configuration( + tgen, router, debug_config, "debug_log_config", build=build + ) + except InvalidCLIError: + # Traceback + errormsg = traceback.format_exc() + logger.error(errormsg) + return errormsg + + logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name)) + return result + + ############################################# # Common APIs, will be used by all protocols ############################################# @@ -3728,7 +3865,7 @@ def get_ipv6_linklocal_address(topo, node, intf): """ tgen = get_topogen() ext_nh = tgen.net[node].get_ipv6_linklocal() - req_nh = topo[node]['links'][intf]['interface'] + req_nh = topo[node]["links"][intf]["interface"] llip = None for llips in ext_nh: if llips[0] == req_nh: @@ -3736,8 +3873,9 @@ def get_ipv6_linklocal_address(topo, node, intf): logger.info("Link local ip found = %s", llip) return llip - errormsg = "Failed: Link local ip not found on router {}, "\ - "interface {}".format(node, intf) + errormsg = "Failed: Link local ip not found on router {}, " "interface {}".format( + node, intf + ) return errormsg @@ -4372,3 +4510,51 @@ def verify_ip_nht(tgen, input_dict): logger.debug("Exiting lib API: verify_ip_nht()") return False + + +def kernel_requires_l3mdev_adjustment(): + """ + Checks if the L3 master device needs to be adjusted to handle VRF traffic + based on kernel version. + + Returns + ------- + 1 or 0 + """ + + if version_cmp(platform.release(), "4.15") >= 0: + return 1 + return 0 + + +def adjust_router_l3mdev(tgen, router): + """ + Adjusts a routers L3 master device to handle VRF traffic depending on kernel + version. + + Parameters + ---------- + * `tgen` : tgen object + * `router` : router id to be configured. + + Returns + ------- + True + """ + + l3mdev_accept = kernel_requires_l3mdev_adjustment() + + logger.info( + "router {0}: setting net.ipv4.tcp_l3mdev_accept={1}".format( + router, l3mdev_accept + ) + ) + + output = tgen.net[router].cmd("sysctl -n net.ipv4.tcp_l3mdev_accept") + logger.info("router {0}: existing tcp_l3mdev_accept was {1}".format(router, output)) + + tgen.net[router].cmd( + "sysctl -w net.ipv4.tcp_l3mdev_accept={}".format(l3mdev_accept) + ) + + return True diff --git a/tests/topotests/lib/ospf.py b/tests/topotests/lib/ospf.py index 9f642411b5..04a12d0eec 100644 --- a/tests/topotests/lib/ospf.py +++ b/tests/topotests/lib/ospf.py @@ -344,9 +344,7 @@ def config_ospf_interface(tgen, topo, input_dict=None, build=False, load_config= for lnk in input_dict[router]["links"].keys(): if "ospf" not in input_dict[router]["links"][lnk]: logger.debug( - "Router %s: ospf config is not present in" - "input_dict", - router + "Router %s: ospf config is not present in" "input_dict", router ) continue ospf_data = input_dict[router]["links"][lnk]["ospf"] diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index 5cc1a6981d..2a46115850 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -50,6 +50,9 @@ from mininet.node import Node, OVSSwitch, Host from mininet.log import setLogLevel, info from mininet.cli import CLI from mininet.link import Intf +from mininet.term import makeTerm + +g_extra_config = {} def gdb_core(obj, daemon, corefiles): @@ -516,6 +519,43 @@ def normalize_text(text): return text +def is_linux(): + """ + Parses unix name output to check if running on GNU/Linux. + + Returns True if running on Linux, returns False otherwise. + """ + + if os.uname()[0] == "Linux": + return True + return False + + +def iproute2_is_vrf_capable(): + """ + Checks if the iproute2 version installed on the system is capable of + handling VRFs by interpreting the output of the 'ip' utility found in PATH. + + Returns True if capability can be detected, returns False otherwise. + """ + + if is_linux(): + try: + subp = subprocess.Popen( + ["ip", "route", "show", "vrf"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + stdin=subprocess.PIPE, + ) + iproute2_err = subp.communicate()[1].splitlines()[0].split()[0] + + if iproute2_err != "Error:": + return True + except Exception: + pass + return False + + def module_present_linux(module, load): """ Returns whether `module` is present. @@ -1303,6 +1343,28 @@ class Router(Node): logger.info("No daemon {} known".format(daemon)) # print "Daemons after:", self.daemons + # Run a command in a new window (gnome-terminal, screen, tmux, xterm) + def runInWindow(self, cmd, title=None): + topo_terminal = os.getenv("FRR_TOPO_TERMINAL") + if topo_terminal or ("TMUX" not in os.environ and "STY" not in os.environ): + term = topo_terminal if topo_terminal else "xterm" + makeTerm(self, title=title if title else cmd, term=term, cmd=cmd) + else: + nscmd = "sudo nsenter -m -n -t {} {}".format(self.pid, cmd) + if "TMUX" in os.environ: + self.cmd("tmux select-layout main-horizontal") + wcmd = "tmux split-window -h" + cmd = "{} {}".format(wcmd, nscmd) + elif "STY" in os.environ: + if os.path.exists( + "/run/screen/S-{}/{}".format(os.environ["USER"], os.environ["STY"]) + ): + wcmd = "screen" + else: + wcmd = "sudo -u {} screen".format(os.environ["SUDO_USER"]) + cmd = "{} {}".format(wcmd, nscmd) + self.cmd(cmd) + def startRouter(self, tgen=None): # Disable integrated-vtysh-config self.cmd( @@ -1355,6 +1417,14 @@ class Router(Node): return "LDP/MPLS Tests need mpls kernel modules" self.cmd("echo 100000 > /proc/sys/net/mpls/platform_labels") + shell_routers = g_extra_config["shell"] + if "all" in shell_routers or self.name in shell_routers: + self.runInWindow(os.getenv("SHELL", "bash")) + + vtysh_routers = g_extra_config["vtysh"] + if "all" in vtysh_routers or self.name in vtysh_routers: + self.runInWindow("vtysh") + if self.daemons["eigrpd"] == 1: eigrpd_path = os.path.join(self.daemondir, "eigrpd") if not os.path.isfile(eigrpd_path): @@ -1381,6 +1451,10 @@ class Router(Node): def startRouterDaemons(self, daemons=None): "Starts all FRR daemons for this router." + gdb_breakpoints = g_extra_config["gdb_breakpoints"] + gdb_daemons = g_extra_config["gdb_daemons"] + gdb_routers = g_extra_config["gdb_routers"] + bundle_data = "" if os.path.exists("/etc/frr/support_bundle_commands.conf"): @@ -1410,7 +1484,7 @@ class Router(Node): # If `daemons` was specified then some upper API called us with # specific daemons, otherwise just use our own configuration. daemons_list = [] - if daemons != None: + if daemons is not None: daemons_list = daemons else: # Append all daemons configured. @@ -1418,47 +1492,64 @@ class Router(Node): if self.daemons[daemon] == 1: daemons_list.append(daemon) - # Start Zebra first - if "zebra" in daemons_list: - zebra_path = os.path.join(self.daemondir, "zebra") - zebra_option = self.daemons_options["zebra"] - self.cmd( - "ASAN_OPTIONS=log_path=zebra.asan {0} {1} --log file:zebra.log --log-level debug -s 90000000 -d > zebra.out 2> zebra.err".format( - zebra_path, zebra_option + def start_daemon(daemon, extra_opts=None): + daemon_opts = self.daemons_options.get(daemon, "") + rediropt = " > {0}.out 2> {0}.err".format(daemon) + if daemon == "snmpd": + binary = "/usr/sbin/snmpd" + cmdenv = "" + cmdopt = "{} -C -c /etc/frr/snmpd.conf -p ".format( + daemon_opts + ) + "/var/run/{}/snmpd.pid -x /etc/frr/agentx".format(self.routertype) + else: + binary = os.path.join(self.daemondir, daemon) + cmdenv = "ASAN_OPTIONS=log_path={0}.asan".format(daemon) + cmdopt = "{} --log file:{}.log --log-level debug".format( + daemon_opts, daemon ) - ) - logger.debug("{}: {} zebra started".format(self, self.routertype)) + if extra_opts: + cmdopt += " " + extra_opts - # Remove `zebra` so we don't attempt to start it again. + if ( + (gdb_routers or gdb_daemons) + and ( + not gdb_routers or self.name in gdb_routers or "all" in gdb_routers + ) + and (not gdb_daemons or daemon in gdb_daemons or "all" in gdb_daemons) + ): + if daemon == "snmpd": + cmdopt += " -f " + + cmdopt += rediropt + gdbcmd = "sudo -E gdb " + binary + if gdb_breakpoints: + gdbcmd += " -ex 'set breakpoint pending on'" + for bp in gdb_breakpoints: + gdbcmd += " -ex 'b {}'".format(bp) + gdbcmd += " -ex 'run {}'".format(cmdopt) + + self.runInWindow(gdbcmd, daemon) + else: + if daemon != "snmpd": + cmdopt += " -d " + cmdopt += rediropt + self.cmd(" ".join([cmdenv, binary, cmdopt])) + logger.info("{}: {} {} started".format(self, self.routertype, daemon)) + + # Start Zebra first + if "zebra" in daemons_list: + start_daemon("zebra", "-s 90000000") while "zebra" in daemons_list: daemons_list.remove("zebra") # Start staticd next if required if "staticd" in daemons_list: - staticd_path = os.path.join(self.daemondir, "staticd") - staticd_option = self.daemons_options["staticd"] - self.cmd( - "ASAN_OPTIONS=log_path=staticd.asan {0} {1} --log file:staticd.log --log-level debug -d > staticd.out 2> staticd.err".format( - staticd_path, staticd_option - ) - ) - logger.debug("{}: {} staticd started".format(self, self.routertype)) - - # Remove `staticd` so we don't attempt to start it again. + start_daemon("staticd") while "staticd" in daemons_list: daemons_list.remove("staticd") if "snmpd" in daemons_list: - snmpd_path = "/usr/sbin/snmpd" - snmpd_option = self.daemons_options["snmpd"] - self.cmd( - "{0} {1} -C -c /etc/frr/snmpd.conf -p /var/run/{2}/snmpd.pid -x /etc/frr/agentx > snmpd.out 2> snmpd.err".format( - snmpd_path, snmpd_option, self.routertype - ) - ) - logger.info("{}: {} snmpd started".format(self, self.routertype)) - - # Remove `snmpd` so we don't attempt to start it again. + start_daemon("snmpd") while "snmpd" in daemons_list: daemons_list.remove("snmpd") @@ -1470,17 +1561,9 @@ class Router(Node): # Now start all the other daemons for daemon in daemons_list: - # Skip disabled daemons and zebra if self.daemons[daemon] == 0: continue - - daemon_path = os.path.join(self.daemondir, daemon) - self.cmd( - "ASAN_OPTIONS=log_path={2}.asan {0} {1} --log file:{2}.log --log-level debug -d > {2}.out 2> {2}.err".format( - daemon_path, self.daemons_options.get(daemon, ""), daemon - ) - ) - logger.debug("{}: {} {} started".format(self, self.routertype, daemon)) + start_daemon(daemon) # Check if daemons are running. rundaemons = self.cmd("ls -1 /var/run/%s/*.pid" % self.routertype) diff --git a/tests/topotests/multicast-pim-bsm-topo1/test_mcast_pim_bsmp_01.py b/tests/topotests/multicast-pim-bsm-topo1/test_mcast_pim_bsmp_01.py index 6b7180978e..cd398a5111 100644 --- a/tests/topotests/multicast-pim-bsm-topo1/test_mcast_pim_bsmp_01.py +++ b/tests/topotests/multicast-pim-bsm-topo1/test_mcast_pim_bsmp_01.py @@ -648,7 +648,11 @@ def test_BSR_CRP_with_blackhole_address_p1(request): input_dict = { "i1": {"static_routes": [{"network": BSR1_ADDR, "next_hop": next_hop_rp}]}, "l1": {"static_routes": [{"network": BSR1_ADDR, "next_hop": next_hop_lhr}]}, - "f1": {"static_routes": [{"network": CRP, "next_hop": next_hop_fhr, "delete": True}]}, + "f1": { + "static_routes": [ + {"network": CRP, "next_hop": next_hop_fhr, "delete": True} + ] + }, } result = create_static_routes(tgen, input_dict) @@ -692,10 +696,11 @@ def test_BSR_CRP_with_blackhole_address_p1(request): step("Verify if b1 chosen as BSR in l1") result = verify_pim_bsr(tgen, topo, "l1", BSR_IP_1, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "b1 is not chosen as BSR in l1 \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "b1 is not chosen as BSR in l1 \n Error: {}".format( tc_name, result - )) + ) state_after = verify_pim_interface_traffic(tgen, state_dict) assert isinstance( @@ -841,10 +846,12 @@ def test_new_router_fwd_p0(request): # Verify bsr state in l1 step("Verify no BSR in l1 as i1 would not forward the no-forward bsm") result = verify_pim_bsr(tgen, topo, "l1", bsr_ip, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "BSR data is present after no-forward bsm also \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) # unconfigure unicast bsm on f1-i1-eth2 step("unconfigure unicast bsm on f1-i1-eth2, will forward with only mcast") @@ -966,10 +973,11 @@ def test_int_bsm_config_p1(request): result = verify_ip_mroutes( tgen, "i1", src_addr, GROUP_ADDRESS, iif, oil, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "Mroutes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "Mroutes are still present \n Error: {}".format( tc_name, result - )) + ) # unconfigure bsm processing on f1 on f1-i1-eth2 step("unconfigure bsm processing on f1 in f1-i1-eth2, will drop bsm") @@ -989,20 +997,21 @@ def test_int_bsm_config_p1(request): # Verify bsr state in i1 step("Verify if b1 is not chosen as BSR in i1") result = verify_pim_bsr(tgen, topo, "i1", bsr_ip, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "b1 is chosen as BSR in i1 \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "b1 is chosen as BSR in i1 \n Error: {}".format( tc_name, result - )) + ) # check if mroute still not installed because of rp not available step("check if mroute still not installed because of rp not available") result = verify_ip_mroutes( tgen, "i1", src_addr, GROUP_ADDRESS, iif, oil, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "mroute installed but rp not available \n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "mroute installed but rp not available \n Error: {}".format(tc_name, result) + ) # configure bsm processing on i1 on f1-i1-eth2 step("configure bsm processing on f1 in f1-i1-eth2, will accept bsm") @@ -1464,10 +1473,11 @@ def test_BSM_timeout_p0(request): tgen, topo, "f1", group, rp_source="BSR", expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "bsr has not aged out in f1 \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "bsr has not aged out in f1 \n Error: {}".format( tc_name, result - )) + ) # Verify RP mapping removed after hold timer expires group = "225.1.1.1/32" @@ -1491,20 +1501,23 @@ def test_BSM_timeout_p0(request): result = verify_join_state_and_timer( tgen, dut, iif, src_addr, GROUP_ADDRESS, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "join state is up and join timer is running in l1 \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) # Verify ip mroute is not installed step("Verify mroute not installed in l1") result = verify_ip_mroutes( tgen, dut, src_addr, GROUP_ADDRESS, iif, oil, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "mroute installed in l1 \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "mroute installed in l1 \n Error: {}".format( tc_name, result - )) + ) step("clear BSM database before moving to next case") clear_bsrp_data(tgen, topo) @@ -1657,10 +1670,11 @@ def test_iif_join_state_p0(request): result = verify_ip_mroutes( tgen, dut, src_addr, GROUP_ADDRESS, iif, oil, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "mroute installed in l1 \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "mroute installed in l1 \n Error: {}".format( tc_name, result - )) + ) # Add back route for RP to make it reachable step("Add back route for RP to make it reachable") diff --git a/tests/topotests/multicast-pim-bsm-topo2/test_mcast_pim_bsmp_02.py b/tests/topotests/multicast-pim-bsm-topo2/test_mcast_pim_bsmp_02.py index 5fc5e52518..199746d5f6 100644 --- a/tests/topotests/multicast-pim-bsm-topo2/test_mcast_pim_bsmp_02.py +++ b/tests/topotests/multicast-pim-bsm-topo2/test_mcast_pim_bsmp_02.py @@ -104,6 +104,10 @@ from lib.pim import ( from lib.topolog import logger from lib.topojson import build_topo_from_json, build_config_from_json + +pytestmark = [pytest.mark.pimd] + + # Reading the data from JSON File for topology creation jsonFile = "{}/mcast_pim_bsmp_02.json".format(CWD) try: @@ -454,10 +458,11 @@ def test_starg_mroute_p0(request): result = verify_ip_mroutes( tgen, dut, src_addr, GROUP_ADDRESS, iif, oil, wait=20, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "mroute installed in l1 \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "mroute installed in l1 \n Error: {}".format( tc_name, result - )) + ) # Send BSM again to configure rp step("Add back RP by sending BSM from b1") @@ -807,10 +812,11 @@ def test_BSR_election_p0(request): # Verify bsr state in FHR step("Verify if b2 is not chosen as bsr in f1") result = verify_pim_bsr(tgen, topo, "f1", bsr_ip2, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "b2 is chosen as bsr in f1 \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "b2 is chosen as bsr in f1 \n Error: {}".format( tc_name, result - )) + ) # Verify if b1 is still chosen as bsr step("Verify if b1 is still chosen as bsr in f1") diff --git a/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo3.py b/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo3.py index 1c22654541..33f476de44 100755 --- a/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo3.py +++ b/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo3.py @@ -3487,11 +3487,11 @@ def test_prune_sent_to_LHR_and_FHR_when_PIMnbr_down_p2(request): IGMP_JOIN_RANGE_1, expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "upstream is still present after shut the link from " - "FHR to RP from RP node \n Error: {}".format( - tc_name, result - )) + "FHR to RP from RP node \n Error: {}".format(tc_name, result) + ) step(" No shut the link from FHR to RP from RP node") @@ -3638,11 +3638,11 @@ def test_prune_sent_to_LHR_and_FHR_when_PIMnbr_down_p2(request): IGMP_JOIN_RANGE_1, expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "upstream is still present after shut the link from " - "FHR to RP from FHR node \n Error: {}".format( - tc_name, result - )) + "FHR to RP from FHR node \n Error: {}".format(tc_name, result) + ) step(" No shut the link from FHR to RP from FHR node") diff --git a/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo4.py b/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo4.py index 68b7849c2b..1081b764ac 100755 --- a/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo4.py +++ b/tests/topotests/multicast-pim-sm-topo3/test_multicast_pim_sm_topo4.py @@ -490,10 +490,12 @@ def test_mroute_when_RP_reachable_default_route_p2(request): data["oil"], expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "mroutes(S,G) are present after delete of static routes on c1 \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) result = verify_upstream_iif( tgen, @@ -503,10 +505,12 @@ def test_mroute_when_RP_reachable_default_route_p2(request): IGMP_JOIN_RANGE_1, expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "upstream is present after delete of static routes on c1 \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) for data in input_dict_starg: result = verify_ip_mroutes( @@ -518,10 +522,12 @@ def test_mroute_when_RP_reachable_default_route_p2(request): data["oil"], expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "mroutes(*,G) are present after delete of static routes on c1 \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) result = verify_upstream_iif( tgen, @@ -531,10 +537,12 @@ def test_mroute_when_RP_reachable_default_route_p2(request): IGMP_JOIN_RANGE_1, expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "upstream is present after delete of static routes on c1 \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("Configure default routes on c2") @@ -557,10 +565,12 @@ def test_mroute_when_RP_reachable_default_route_p2(request): result = verify_pim_rp_info( tgen, topo, dut, GROUP_RANGE_1, "Unknown", rp_address, SOURCE, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "RP info is unknown after removing static route from c2 \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("Verify (s,g) populated after adding default route ") @@ -787,10 +797,11 @@ def test_mroute_with_RP_default_route_all_nodes_p2(request): data["oil"], expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " - "mroutes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "mroutes are still present \n Error: {}".format( tc_name, result - )) + ) result = verify_upstream_iif( tgen, @@ -800,10 +811,11 @@ def test_mroute_with_RP_default_route_all_nodes_p2(request): IGMP_JOIN_RANGE_1, expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " - "upstream is still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "upstream is still present \n Error: {}".format( tc_name, result - )) + ) step("Configure default routes on all the nodes") @@ -840,10 +852,12 @@ def test_mroute_with_RP_default_route_all_nodes_p2(request): result = verify_pim_rp_info( tgen, topo, dut, GROUP_RANGE_1, "Unknown", rp_address, SOURCE, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "RP info is unknown after removing static route from c2 \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("Verify (s,g) populated after adding default route ") diff --git a/tests/topotests/multicast-pim-static-rp-topo1/test_multicast_pim_static_rp.py b/tests/topotests/multicast-pim-static-rp-topo1/test_multicast_pim_static_rp.py index 1317ec67b4..e90230eb3b 100755 --- a/tests/topotests/multicast-pim-static-rp-topo1/test_multicast_pim_static_rp.py +++ b/tests/topotests/multicast-pim-static-rp-topo1/test_multicast_pim_static_rp.py @@ -423,10 +423,12 @@ def test_add_delete_static_RP_p0(request): dut = "r1" interface = "r1-r0-eth0" result = verify_igmp_groups(tgen, dut, interface, GROUP_ADDRESS, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: igmp group present without any IGMP join \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r1: Verify show ip pim interface traffic without any IGMP join") state_dict = {"r1": {"r1-r2-eth1": ["pruneTx"]}} @@ -492,26 +494,29 @@ def test_add_delete_static_RP_p0(request): result = verify_pim_rp_info( tgen, topo, dut, GROUP_RANGE_ALL, iif, rp_address, SOURCE, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: RP info present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: RP info present \n Error: {}".format( tc_name, result - )) + ) step("r1: Verify upstream IIF interface") result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: upstream IIF interface present \n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: upstream IIF interface present \n Error: {}".format(tc_name, result) + ) step("r1: Verify upstream join state and join timer") result = verify_join_state_and_timer( tgen, dut, iif, STAR, GROUP_ADDRESS, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: upstream join state is up and join timer is running \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r1: Verify PIM state") result = verify_pim_state(tgen, dut, iif, oif, GROUP_ADDRESS, expected=False) @@ -521,10 +526,11 @@ def test_add_delete_static_RP_p0(request): step("r1: Verify ip mroutes") result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: mroutes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: mroutes are still present \n Error: {}".format( tc_name, result - )) + ) step("r1: Verify show ip pim interface traffic without any IGMP join") state_after = verify_pim_interface_traffic(tgen, state_dict) @@ -681,10 +687,12 @@ def test_SPT_RPT_path_same_p1(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: (S, G) upstream join state is up and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r3: Verify (S, G) ip mroutes") oif = "r3-r2-eth1" @@ -811,17 +819,19 @@ def test_not_reachable_static_RP_p0(request): "using show ip pim state" ) result = verify_pim_state(tgen, dut, iif, oif, GROUP_ADDRESS, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "OIL is not same and IIF is not cleared on R1 \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r1: upstream IIF should be unknown , verify using show ip pim" "upstream") result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: upstream IIF is not unknown \n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: upstream IIF is not unknown \n Error: {}".format(tc_name, result) + ) step( "r1: join state should not be joined and join timer should stop," @@ -830,10 +840,12 @@ def test_not_reachable_static_RP_p0(request): result = verify_join_state_and_timer( tgen, dut, iif, STAR, GROUP_ADDRESS, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: join state is joined and timer is not stopped \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step( "r1: (*,G) prune is sent towards the RP interface, verify using" @@ -850,10 +862,12 @@ def test_not_reachable_static_RP_p0(request): step("r1: (*, G) cleared from mroute table using show ip mroute") result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: (*, G) are not cleared from mroute table \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) logger.info("Expected behavior: {}".format(result)) # Uncomment next line for debugging @@ -920,10 +934,11 @@ def test_add_RP_after_join_received_p1(request): result = verify_pim_rp_info( tgen, topo, dut, GROUP_RANGE_ALL, iif, rp_address, SOURCE, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: rp-info is present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: rp-info is present \n Error: {}".format( tc_name, result - )) + ) step("joinTx value before join sent") state_dict = {"r1": {"r1-r2-eth1": ["joinTx"]}} @@ -944,34 +959,38 @@ def test_add_RP_after_join_received_p1(request): step("r1: Verify upstream IIF interface") result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: upstream IFF interface is present \n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: upstream IFF interface is present \n Error: {}".format(tc_name, result) + ) step("r1: Verify upstream join state and join timer") result = verify_join_state_and_timer( tgen, dut, iif, STAR, GROUP_ADDRESS, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: upstream join state is joined and timer is running \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r1: Verify PIM state") result = verify_pim_state(tgen, dut, iif, oif, GROUP_ADDRESS, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: PIM state is up\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: PIM state is up\n Error: {}".format( tc_name, result - )) + ) step("r1: Verify ip mroutes") result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: mroutes are still present\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: mroutes are still present\n Error: {}".format( tc_name, result - )) + ) step("r1: Configure static RP") input_dict = { @@ -1095,33 +1114,37 @@ def test_reachable_static_RP_after_join_p0(request): step("r1 : Verify upstream IIF interface") iif = "r1-r2-eth1" result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: upstream IIF interface is present\n Error: {}".format( - tc_name, result - )) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: upstream IIF interface is present\n Error: {}".format(tc_name, result) + ) step("r1 : Verify upstream join state and join timer") result = verify_join_state_and_timer( tgen, dut, iif, STAR, GROUP_ADDRESS, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: upstream join state is joined and timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r1 : Verify PIM state") result = verify_pim_state(tgen, dut, iif, oif, GROUP_ADDRESS, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: PIM state is up\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: PIM state is up\n Error: {}".format( tc_name, result - )) + ) step("r1 : Verify ip mroutes") result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: mroutes are still present\n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: mroutes are still present\n Error: {}".format( tc_name, result - )) + ) step("r1: Make RP reachable") intf = "r1-r2-eth1" @@ -1362,10 +1385,12 @@ def test_send_join_on_higher_preffered_rp_p1(request): result = verify_pim_rp_info( tgen, topo, dut, GROUP_RANGE, oif, rp_address_2, SOURCE, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: rp-info is present for group 225.1.1.1 \n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step( "r1 : Verify RPF interface updated in mroute when higher preferred" @@ -1619,11 +1644,11 @@ def test_RP_configured_as_LHR_1_p1(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: (S, G) upstream join state is joined and join" - " timer is running \n Error: {}".format( - tc_name, result - )) + " timer is running \n Error: {}".format(tc_name, result) + ) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -1828,10 +1853,12 @@ def test_RP_configured_as_LHR_2_p1(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -2036,10 +2063,12 @@ def test_RP_configured_as_FHR_1_p1(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -2245,10 +2274,12 @@ def test_RP_configured_as_FHR_2_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -2372,10 +2403,12 @@ def test_SPT_RPT_path_different_p1(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -2394,10 +2427,12 @@ def test_SPT_RPT_path_different_p1(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r2: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r2: Verify (S, G) ip mroutes") oif = "none" @@ -2623,10 +2658,12 @@ def test_restart_pimd_process_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -2791,10 +2828,12 @@ def test_multiple_groups_same_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -2813,10 +2852,12 @@ def test_multiple_groups_same_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r2: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r2: Verify (S, G) ip mroutes") oif = "none" @@ -2932,10 +2973,12 @@ def test_multiple_groups_same_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r2: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r2: Verify (S, G) ip mroutes") oif = "none" @@ -2952,10 +2995,12 @@ def test_multiple_groups_same_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -3132,10 +3177,12 @@ def test_multiple_groups_different_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r2: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r2: Verify (S, G) ip mroutes") oif = "none" @@ -3154,10 +3201,12 @@ def test_multiple_groups_different_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -3224,10 +3273,12 @@ def test_multiple_groups_different_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r4: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r4: Verify (S, G) ip mroutes") oif = "none" @@ -3399,10 +3450,12 @@ def test_multiple_groups_different_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r2: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r2: Verify (S, G) ip mroutes") oif = "none" @@ -3421,10 +3474,12 @@ def test_multiple_groups_different_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -3491,10 +3546,12 @@ def test_multiple_groups_different_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r4: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r4: Verify (S, G) ip mroutes") oif = "none" @@ -3513,10 +3570,12 @@ def test_multiple_groups_different_RP_address_p2(request): result = verify_join_state_and_timer( tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r3: Verify (S, G) ip mroutes") oif = "r3-r1-eth0" @@ -3643,30 +3702,36 @@ def test_shutdown_primary_path_p1(request): iif = "r1-r3-eth2" oif = "r1-r0-eth0" result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: (*,G) mroutes are not cleared after shut of R1 to R3 link\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r2: Verify (*, G) ip mroutes") dut = "r2" iif = "lo" oif = "r2-r3-eth1" result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r2: (*,G) mroutes are not cleared after shut of R1 to R3 link\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r3: Verify (*, G) ip mroutes") dut = "r3" iif = "r3-r2-eth1" oif = "r3-r1-eth0" result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r3: (*,G) mroutes are not cleared after shut of R1 to R3 link\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r3: No shutdown the link from R1 to R3 from R3 node") dut = "r3" @@ -3826,20 +3891,24 @@ def test_delete_RP_shut_noshut_upstream_interface_p1(request): iif = "r1-r2-eth1" oif = "r1-r0-eth0" result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: (*,G) mroutes are not cleared after shut of R1 to R0 link\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r2: Verify (*, G) ip mroutes cleared") dut = "r2" iif = "lo" oif = "r2-r1-eth0" result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r2: (*,G) mroutes are not cleared after shut of R1 to R0 link\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) write_test_footer(tc_name) @@ -3949,20 +4018,24 @@ def test_delete_RP_shut_noshut_RP_interface_p1(request): iif = "r1-r2-eth1" oif = "r1-r0-eth0" result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: (*,G) mroutes are not cleared after shut of R1 to R2 and R3 link\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) step("r2: Verify (*, G) ip mroutes cleared") dut = "r2" iif = "lo" oif = "r2-r1-eth0" result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r2: (*,G) mroutes are not cleared after shut of R1 to R2 and R3 link\n Error: {}".format( - tc_name, result - )) + tc_name, result + ) + ) write_test_footer(tc_name) diff --git a/tests/topotests/nhrp-topo/r1/nhrp4_cache.json b/tests/topotests/nhrp-topo/r1/nhrp4_cache.json new file mode 100644 index 0000000000..6426a939be --- /dev/null +++ b/tests/topotests/nhrp-topo/r1/nhrp4_cache.json @@ -0,0 +1,29 @@ +{ + "attr":{ + "entriesCount":2 + }, + "table":[ + { + "interface":"r1-gre0", + "type":"nhs", + "protocol":"10.255.255.2", + "nbma":"10.2.1.2", + "claimed_nbma":"10.2.1.2", + "used":false, + "timeout":true, + "auth":false, + "identity":"" + }, + { + "interface":"r1-gre0", + "type":"local", + "protocol":"10.255.255.1", + "nbma":"10.1.1.1", + "claimed_nbma":"10.1.1.1", + "used":false, + "timeout":false, + "auth":false, + "identity":"-" + } + ] +} diff --git a/tests/topotests/nhrp-topo/r1/nhrp_route4.json b/tests/topotests/nhrp-topo/r1/nhrp_route4.json new file mode 100644 index 0000000000..68b5a6ece2 --- /dev/null +++ b/tests/topotests/nhrp-topo/r1/nhrp_route4.json @@ -0,0 +1,25 @@ +{ + "10.255.255.2\/32":[ + { + "prefix":"10.255.255.2\/32", + "protocol":"nhrp", + "vrfId":0, + "vrfName":"default", + "selected":true, + "destSelected":true, + "distance":10, + "metric":0, + "installed":true, + "internalNextHopNum":1, + "internalNextHopActiveNum":1, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"r1-gre0", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/nhrp-topo/r1/nhrpd.conf b/tests/topotests/nhrp-topo/r1/nhrpd.conf new file mode 100644 index 0000000000..04114bdbe6 --- /dev/null +++ b/tests/topotests/nhrp-topo/r1/nhrpd.conf @@ -0,0 +1,10 @@ +log stdout debugging +debug nhrp all +interface r1-gre0 + ip nhrp holdtime 500 + ip nhrp shortcut + ip nhrp network-id 42 + ip nhrp nhs dynamic nbma 10.2.1.2 + ip nhrp registration no-unique + tunnel source r1-eth0 +exit diff --git a/tests/topotests/nhrp-topo/r1/zebra.conf b/tests/topotests/nhrp-topo/r1/zebra.conf new file mode 100644 index 0000000000..b45670fcb2 --- /dev/null +++ b/tests/topotests/nhrp-topo/r1/zebra.conf @@ -0,0 +1,12 @@ +interface r1-eth0 + ip address 10.1.1.1/24 +! +ip route 10.2.1.0/24 10.1.1.3 +interface r1-gre0 + ip address 10.255.255.1/32 + no link-detect + ipv6 nd suppress-ra +exit +interface r1-eth1 + ip address 192.168.1.1/24 +! diff --git a/tests/topotests/nhrp-topo/r2/nhrp4_cache.json b/tests/topotests/nhrp-topo/r2/nhrp4_cache.json new file mode 100644 index 0000000000..34558e0c28 --- /dev/null +++ b/tests/topotests/nhrp-topo/r2/nhrp4_cache.json @@ -0,0 +1,29 @@ +{ + "attr":{ + "entriesCount":2 + }, + "table":[ + { + "interface":"r2-gre0", + "type":"local", + "protocol":"10.255.255.2", + "nbma":"10.2.1.2", + "claimed_nbma":"10.2.1.2", + "used":false, + "timeout":false, + "auth":false, + "identity":"-" + }, + { + "interface":"r2-gre0", + "type":"dynamic", + "protocol":"10.255.255.1", + "nbma":"10.1.1.1", + "claimed_nbma":"10.1.1.1", + "used":false, + "timeout":true, + "auth":false, + "identity":"" + } + ] +} diff --git a/tests/topotests/nhrp-topo/r2/nhrp_route4.json b/tests/topotests/nhrp-topo/r2/nhrp_route4.json new file mode 100644 index 0000000000..7393cba893 --- /dev/null +++ b/tests/topotests/nhrp-topo/r2/nhrp_route4.json @@ -0,0 +1,25 @@ +{ + "10.255.255.1\/32":[ + { + "prefix":"10.255.255.1\/32", + "protocol":"nhrp", + "vrfId":0, + "vrfName":"default", + "selected":true, + "destSelected":true, + "distance":10, + "metric":0, + "installed":true, + "internalNextHopNum":1, + "internalNextHopActiveNum":1, + "nexthops":[ + { + "fib":true, + "directlyConnected":true, + "interfaceName":"r2-gre0", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/nhrp-topo/r2/nhrpd.conf b/tests/topotests/nhrp-topo/r2/nhrpd.conf new file mode 100644 index 0000000000..e4f6fb7445 --- /dev/null +++ b/tests/topotests/nhrp-topo/r2/nhrpd.conf @@ -0,0 +1,10 @@ +debug nhrp all +log stdout debugging +nhrp nflog-group 1 +interface r2-gre0 + ip nhrp holdtime 500 + ip nhrp redirect + ip nhrp network-id 42 + ip nhrp registration no-unique + tunnel source r2-eth0 +exit diff --git a/tests/topotests/nhrp-topo/r2/zebra.conf b/tests/topotests/nhrp-topo/r2/zebra.conf new file mode 100644 index 0000000000..9f40d4d72e --- /dev/null +++ b/tests/topotests/nhrp-topo/r2/zebra.conf @@ -0,0 +1,12 @@ +interface r2-eth0 + ip address 10.2.1.2/24 +! +ip route 10.1.1.0/24 10.2.1.3 +interface r2-gre0 + ip address 10.255.255.2/32 + no link-detect + ipv6 nd suppress-ra +! +interface r2-eth1 + ip address 192.168.2.2/24 +! diff --git a/tests/topotests/nhrp-topo/r3/zebra.conf b/tests/topotests/nhrp-topo/r3/zebra.conf new file mode 100644 index 0000000000..6d3d267978 --- /dev/null +++ b/tests/topotests/nhrp-topo/r3/zebra.conf @@ -0,0 +1,11 @@ +debug zebra kernel +debug zebra rib +debug zebra events +debug zebra packet +ip forwarding +interface r3-eth0 + ip address 10.1.1.3/24 +! +interface r3-eth1 + ip address 10.2.1.3/24 +exit diff --git a/tests/topotests/nhrp-topo/test_nhrp_topo.dot b/tests/topotests/nhrp-topo/test_nhrp_topo.dot new file mode 100644 index 0000000000..6b68fb398f --- /dev/null +++ b/tests/topotests/nhrp-topo/test_nhrp_topo.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-topo2"; + + # 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\n2001:db8:1::/64", + fillcolor="#d0e0d0", + style=filled, + ]; + sw2 [ + shape=oval, + label="sw2\n10.0.3.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + sw3 [ + shape=oval, + label="sw3\n2001:db8:4::/64", + fillcolor="#d0e0d0", + style=filled, + ]; + + # Connections + r1 -- sw1 [label="eth0"]; + r2 -- sw1 [label="eth0"]; + + r2 -- sw2 [label="eth1"]; + r3 -- sw2 [label="eth0"]; + + r2 -- sw3 [label="eth2"]; + r4 -- sw3 [label="eth0"]; +} diff --git a/tests/topotests/nhrp-topo/test_nhrp_topo.py b/tests/topotests/nhrp-topo/test_nhrp_topo.py new file mode 100644 index 0000000000..1687961f34 --- /dev/null +++ b/tests/topotests/nhrp-topo/test_nhrp_topo.py @@ -0,0 +1,221 @@ +#!/usr/bin/env python + +# +# test_nhrp_topo.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2019 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_nhrp_topo.py: Test the FRR/Quagga NHRP 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 NHRPTopo(Topo): + "Test topology builder" + def build(self, *_args, **_opts): + "Build function" + tgen = get_topogen(self) + + # Create 3 routers. + for routern in range(1, 4): + tgen.add_router('r{}'.format(routern)) + + switch = tgen.add_switch('s1') + switch.add_link(tgen.gears['r1']) + switch.add_link(tgen.gears['r3']) + 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 = tgen.add_switch('s4') + switch.add_link(tgen.gears['r1']) + + +def _populate_iface(): + tgen = get_topogen() + cmds_tot_hub = ['ip tunnel add {0}-gre0 mode gre ttl 64 key 42 dev {0}-eth0 local 10.2.1.{1} remote 0.0.0.0', + 'ip link set dev {0}-gre0 up', + 'echo 0 > /proc/sys/net/ipv4/ip_forward_use_pmtu', + 'echo 1 > /proc/sys/net/ipv6/conf/{0}-eth0/disable_ipv6', + 'echo 1 > /proc/sys/net/ipv6/conf/{0}-gre0/disable_ipv6'] + + cmds_tot = ['ip tunnel add {0}-gre0 mode gre ttl 64 key 42 dev {0}-eth0 local 10.1.1.{1} remote 0.0.0.0', + 'ip link set dev {0}-gre0 up', + 'echo 0 > /proc/sys/net/ipv4/ip_forward_use_pmtu', + 'echo 1 > /proc/sys/net/ipv6/conf/{0}-eth0/disable_ipv6', + 'echo 1 > /proc/sys/net/ipv6/conf/{0}-gre0/disable_ipv6'] + + for cmd in cmds_tot_hub: + input = cmd.format('r2', '2') + logger.info('input: '+cmd) + output = tgen.net['r2'].cmd(cmd.format('r2', '2')) + logger.info('output: '+output); + + for cmd in cmds_tot: + input = cmd.format('r1', '1') + logger.info('input: '+cmd) + output = tgen.net['r1'].cmd(cmd.format('r1', '1')) + logger.info('output: '+output); + + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(NHRPTopo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + _populate_iface() + + for rname, router in router_list.iteritems(): + router.load_config( + TopoRouter.RD_ZEBRA, + os.path.join(CWD, '{}/zebra.conf'.format(rname)), + ) + if rname in ('r1', 'r2'): + router.load_config( + TopoRouter.RD_NHRP, + os.path.join(CWD, '{}/nhrpd.conf'.format(rname)) + ) + + # Initialize all routers. + logger.info('Launching BGP, NHRP') + for name in router_list: + router = tgen.gears[name] + router.start() + + +def teardown_module(_mod): + "Teardown the pytest environment" + tgen = get_topogen() + tgen.stop_topology() + + +def test_protocols_convergence(): + """ + Assert that all protocols have converged before checking for the NHRP + statuses as they depend on it. + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Check IPv4 routing tables. + logger.info("Checking NHRP cache and IPv4 routes for convergence") + router_list = tgen.routers() + + for rname, router in router_list.iteritems(): + if rname == 'r3': + continue + + json_file = '{}/{}/nhrp4_cache.json'.format(CWD, router.name) + if not os.path.isfile(json_file): + logger.info('skipping file {}'.format(json_file)) + continue + + expected = json.loads(open(json_file).read()) + test_func = partial(topotest.router_json_cmp, + router, 'show ip nhrp cache json', expected) + _, result = topotest.run_and_expect(test_func, None, count=40, + wait=0.5) + + output = router.vtysh_cmd('show ip nhrp cache') + logger.info(output) + + assertmsg = '"{}" JSON output mismatches'.format(router.name) + assert result is None, assertmsg + + for rname, router in router_list.iteritems(): + if rname == 'r3': + continue + + json_file = '{}/{}/nhrp_route4.json'.format(CWD, router.name) + if not os.path.isfile(json_file): + logger.info('skipping file {}'.format(json_file)) + continue + + expected = json.loads(open(json_file).read()) + test_func = partial(topotest.router_json_cmp, + router, 'show ip route nhrp json', expected) + _, result = topotest.run_and_expect(test_func, None, count=40, + wait=0.5) + + output = router.vtysh_cmd('show ip route nhrp') + logger.info(output) + + assertmsg = '"{}" JSON output mismatches'.format(router.name) + assert result is None, assertmsg + + for rname, router in router_list.iteritems(): + if rname == 'r3': + continue + logger.info('Dump neighbor information on {}-gre0'.format(rname)) + output = router.run('ip neigh show') + logger.info(output) + + +def test_nhrp_connection(): + "Assert that the NHRP peers can find themselves." + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + pingrouter = tgen.gears['r1'] + logger.info('Check Ping IPv4 from R1 to R2 = 10.255.255.2)') + output = pingrouter.run('ping 10.255.255.2 -f -c 1000') + logger.info(output) + if '1000 packets transmitted, 1000 received' not in output: + assertmsg = 'expected ping IPv4 from R1 to R2 should be ok' + assert 0, assertmsg + else: + logger.info('Check Ping IPv4 from R1 to R2 OK') + + +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/ospf-sr-topo1/test_ospf_sr_topo1.py b/tests/topotests/ospf-sr-topo1/test_ospf_sr_topo1.py index 57b93c3fd5..b6e5e14830 100644 --- a/tests/topotests/ospf-sr-topo1/test_ospf_sr_topo1.py +++ b/tests/topotests/ospf-sr-topo1/test_ospf_sr_topo1.py @@ -86,6 +86,7 @@ from mininet.topo import Topo pytestmark = [pytest.mark.ospfd] + class TemplateTopo(Topo): "Test topology builder" @@ -385,9 +386,7 @@ def test_rib_ipv4_step5(): pytest.skip(tgen.errors) logger.info("Disabling SR on rt6") - tgen.net["rt6"].cmd( - 'vtysh -c "conf t" -c "router ospf" -c "no segment-routing on"' - ) + tgen.net["rt6"].cmd('vtysh -c "conf t" -c "router ospf" -c "no segment-routing on"') for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( @@ -652,7 +651,7 @@ def test_mpls_lib_step10(): # Expected changes: # -All commands should be rejected # -#def test_ospf_invalid_config_step11(): +# def test_ospf_invalid_config_step11(): # logger.info("Test (step 11): check if invalid configuration is rejected") # tgen = get_topogen() # diff --git a/tests/topotests/ospf-te-topo1/__init__.py b/tests/topotests/ospf-te-topo1/__init__.py new file mode 100755 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/ospf-te-topo1/__init__.py diff --git a/tests/topotests/ospf-te-topo1/r1/ospfd.conf b/tests/topotests/ospf-te-topo1/r1/ospfd.conf new file mode 100644 index 0000000000..312dd2697e --- /dev/null +++ b/tests/topotests/ospf-te-topo1/r1/ospfd.conf @@ -0,0 +1,23 @@ +! +interface lo + ip ospf area 0.0.0.0 +! +interface r1-eth0 + ip ospf network point-to-point + ip ospf hello-interval 2 + ip ospf dead-interval 10 + ip ospf area 0.0.0.0 +! +interface r1-eth1 + ip ospf network point-to-point + ip ospf hello-interval 2 + ip ospf dead-interval 10 + ip ospf area 0.0.0.0 +! +router ospf + ospf router-id 10.0.255.1 + capability opaque + mpls-te on + mpls-te router-address 10.0.255.1 +! + diff --git a/tests/topotests/ospf-te-topo1/r1/zebra.conf b/tests/topotests/ospf-te-topo1/r1/zebra.conf new file mode 100644 index 0000000000..7c5dc3ffe0 --- /dev/null +++ b/tests/topotests/ospf-te-topo1/r1/zebra.conf @@ -0,0 +1,21 @@ +! +interface lo + ip address 10.0.255.1/32 +! +interface r1-eth0 + ip address 10.0.0.1/24 + link-params + metric 20 + delay 10000 + ava-bw 1.25e+08 + enable + exit-link-params +! +interface r1-eth1 + ip address 10.0.1.1/24 + link-params + enable + exit-link-params +! +ip forwarding +! diff --git a/tests/topotests/ospf-te-topo1/r2/ospfd.conf b/tests/topotests/ospf-te-topo1/r2/ospfd.conf new file mode 100644 index 0000000000..e9c3f65bc2 --- /dev/null +++ b/tests/topotests/ospf-te-topo1/r2/ospfd.conf @@ -0,0 +1,34 @@ +! +interface lo + ip ospf area 0.0.0.0 +! +interface r2-eth0 + ip ospf network point-to-point + ip ospf hello-interval 2 + ip ospf dead-interval 10 + ip ospf area 0.0.0.0 +! +interface r2-eth1 + ip ospf network point-to-point + ip ospf hello-interval 2 + ip ospf dead-interval 10 + ip ospf area 0.0.0.0 +! +interface r2-eth2 + ip ospf network point-to-point + ip ospf area 0.0.0.0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +interface r2-eth3 + ip ospf network point-to-point + ip ospf hello-interval 2 + ip ospf dead-interval 10 + ip ospf area 0.0.0.0 +! +router ospf + ospf router-id 10.0.255.2 + capability opaque + mpls-te on + mpls-te router-address 10.0.255.2 +! diff --git a/tests/topotests/ospf-te-topo1/r2/zebra.conf b/tests/topotests/ospf-te-topo1/r2/zebra.conf new file mode 100644 index 0000000000..69e10191f3 --- /dev/null +++ b/tests/topotests/ospf-te-topo1/r2/zebra.conf @@ -0,0 +1,33 @@ +! +interface lo + ip address 10.0.255.2/32 +! +interface r2-eth0 + ip address 10.0.0.2/24 + link-params + enable + exit-link-params +! +interface r2-eth1 + ip address 10.0.1.2/24 + link-params + enable + exit-link-params +! +interface r2-eth2 + ip address 10.0.3.2/24 + link-params + enable + exit-link-params +! +interface r2-eth3 + ip address 10.0.4.2/24 + link-params + metric 30 + delay 25000 + use-bw 1.25e+8 + enable + exit-link-params +! +ip forwarding +! diff --git a/tests/topotests/ospf-te-topo1/r3/ospfd.conf b/tests/topotests/ospf-te-topo1/r3/ospfd.conf new file mode 100644 index 0000000000..caa5f1e1eb --- /dev/null +++ b/tests/topotests/ospf-te-topo1/r3/ospfd.conf @@ -0,0 +1,24 @@ +! +interface lo + ip ospf area 0.0.0.0 +! +interface r3-eth0 + ip ospf network point-to-point + ip ospf area 0.0.0.0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +interface r3-eth1 + ip ospf network point-to-point + ip ospf area 0.0.0.0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +! +router ospf + ospf router-id 10.0.255.3 + capability opaque + mpls-te on + mpls-te router-address 10.0.255.3 + mpls-te inter-as as +! diff --git a/tests/topotests/ospf-te-topo1/r3/zebra.conf b/tests/topotests/ospf-te-topo1/r3/zebra.conf new file mode 100644 index 0000000000..4cf9077085 --- /dev/null +++ b/tests/topotests/ospf-te-topo1/r3/zebra.conf @@ -0,0 +1,22 @@ +! +interface lo + ip address 10.0.255.3/32 +! +interface r3-eth0 + ip address 10.0.3.1/24 + link-params + enable + admin-grp 0x20 + exit-link-params +! +interface r3-eth1 + ip address 10.0.5.1/24 + link-params + enable + metric 10 + delay 50000 + neighbor 10.0.255.5 as 65535 + exit-link-params +! +ip forwarding +! diff --git a/tests/topotests/ospf-te-topo1/r4/ospfd.conf b/tests/topotests/ospf-te-topo1/r4/ospfd.conf new file mode 100644 index 0000000000..e454673153 --- /dev/null +++ b/tests/topotests/ospf-te-topo1/r4/ospfd.conf @@ -0,0 +1,22 @@ +! +interface lo + ip ospf area 0.0.0.0 +! +interface r4-eth0 + ip ospf network point-to-point + ip ospf hello-interval 2 + ip ospf dead-interval 10 + ip ospf area 0.0.0.0 +! +! +router ospf + ospf router-id 10.0.255.4 + capability opaque + mpls-te on + mpls-te router-address 10.0.255.4 + segment-routing on + segment-routing local-block 5000 5999 + segment-routing global-block 10000 19999 + segment-routing node-msd 12 + segment-routing prefix 10.0.255.4/32 index 400 no-php-flag +! diff --git a/tests/topotests/ospf-te-topo1/r4/zebra.conf b/tests/topotests/ospf-te-topo1/r4/zebra.conf new file mode 100644 index 0000000000..18c003b230 --- /dev/null +++ b/tests/topotests/ospf-te-topo1/r4/zebra.conf @@ -0,0 +1,12 @@ +! +interface lo + ip address 10.0.255.4/32 +! +interface r4-eth0 + ip address 10.0.4.1/24 + link-params + enable + exit-link-params +! +ip forwarding +! diff --git a/tests/topotests/ospf-te-topo1/reference/ted_step1.json b/tests/topotests/ospf-te-topo1/reference/ted_step1.json new file mode 100644 index 0000000000..9624292ccd --- /dev/null +++ b/tests/topotests/ospf-te-topo1/reference/ted_step1.json @@ -0,0 +1,577 @@ +{ + "ted":{ + "name":"OSPF", + "key":1, + "verticesCount":5, + "edgesCount":9, + "subnetsCount":14, + "vertices":[ + { + "vertex-id":167837441, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.1", + "vertex-type":"Standard" + }, + { + "vertex-id":167837442, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.2", + "vertex-type":"Standard" + }, + { + "vertex-id":167837443, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.3", + "vertex-type":"ASBR" + }, + { + "vertex-id":167837444, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.4", + "vertex-type":"Standard", + "segment-routing":{ + "srgb-size":10000, + "srgb-lower":10000, + "algorithms":[ + { + "0":"SPF" + } + ], + "srlb-size":1000, + "srlb-lower":5000, + "msd":12 + } + }, + { + "vertex-id":167837445, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.5", + "vertex-type":"Remote ASBR", + "asn":65535 + } + ], + "edges":[ + { + "edge-id":167772161, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "local-vertex-id":167837441, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":20, + "local-address":"10.0.0.1", + "remote-address":"10.0.0.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":10000, + "available-bandwidth":125000000.0 + } + }, + { + "edge-id":167772162, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837441, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.0.2", + "remote-address":"10.0.0.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + } + }, + { + "edge-id":167772417, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "local-vertex-id":167837441, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.1.1", + "remote-address":"10.0.1.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + } + }, + { + "edge-id":167772418, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837441, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.1.2", + "remote-address":"10.0.1.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + } + }, + { + "edge-id":167772929, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "local-vertex-id":167837443, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "admin-group":32, + "local-address":"10.0.3.1", + "remote-address":"10.0.3.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + } + }, + { + "edge-id":167772930, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837443, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.3.2", + "remote-address":"10.0.3.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + } + }, + { + "edge-id":167773185, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "local-vertex-id":167837444, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.4.1", + "remote-address":"10.0.4.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5001, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5000, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167773186, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837444, + "metric":10, + "edge-attributes":{ + "te-metric":30, + "local-address":"10.0.4.2", + "remote-address":"10.0.4.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":25000, + "utilized-bandwidth":125000000.0 + } + }, + { + "edge-id":167773441, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "local-vertex-id":167837443, + "remote-vertex-id":167837445, + "metric":0, + "edge-attributes":{ + "te-metric":10, + "local-address":"10.0.5.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "remote-asn":65535, + "remote-as-address":"10.0.255.5", + "delay":50000 + } + } + ], + "subnets":[ + { + "subnet-id":"10.0.0.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":10 + }, + { + "subnet-id":"10.0.0.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.1.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":10 + }, + { + "subnet-id":"10.0.1.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.3.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "vertex-id":167837443, + "metric":10 + }, + { + "subnet-id":"10.0.3.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.4.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "vertex-id":167837444, + "metric":10 + }, + { + "subnet-id":"10.0.4.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.5.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "vertex-id":167837443, + "metric":10 + }, + { + "subnet-id":"10.0.255.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":0 + }, + { + "subnet-id":"10.0.255.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":0 + }, + { + "subnet-id":"10.0.255.3\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "vertex-id":167837443, + "metric":0 + }, + { + "subnet-id":"10.0.255.4\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "vertex-id":167837444, + "metric":0, + "segment-routing":{ + "pref-sid":400, + "algo":0, + "flags":"0x40" + } + }, + { + "subnet-id":"10.0.255.5\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.5", + "vertex-id":167837445, + "metric":10 + } + ] + } +} diff --git a/tests/topotests/ospf-te-topo1/reference/ted_step2.json b/tests/topotests/ospf-te-topo1/reference/ted_step2.json new file mode 100644 index 0000000000..623d1dc7e0 --- /dev/null +++ b/tests/topotests/ospf-te-topo1/reference/ted_step2.json @@ -0,0 +1,477 @@ +{ + "ted":{ + "name":"OSPF", + "key":1, + "verticesCount":5, + "edgesCount":7, + "subnetsCount":12, + "vertices":[ + { + "vertex-id":167837441, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.1", + "vertex-type":"Standard" + }, + { + "vertex-id":167837442, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.2", + "vertex-type":"Standard" + }, + { + "vertex-id":167837443, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.3", + "vertex-type":"ASBR" + }, + { + "vertex-id":167837444, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.4", + "vertex-type":"Standard", + "segment-routing":{ + "srgb-size":10000, + "srgb-lower":10000, + "algorithms":[ + { + "0":"SPF" + } + ], + "srlb-size":1000, + "srlb-lower":5000, + "msd":12 + } + }, + { + "vertex-id":167837445, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.5", + "vertex-type":"Remote ASBR", + "asn":65535 + } + ], + "edges":[ + { + "edge-id":167772161, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "local-vertex-id":167837441, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":20, + "local-address":"10.0.0.1", + "remote-address":"10.0.0.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":10000, + "available-bandwidth":125000000.0 + } + }, + { + "edge-id":167772162, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837441, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.0.2", + "remote-address":"10.0.0.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + } + }, + { + "edge-id":167772929, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "local-vertex-id":167837443, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "admin-group":32, + "local-address":"10.0.3.1", + "remote-address":"10.0.3.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + } + }, + { + "edge-id":167772930, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837443, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.3.2", + "remote-address":"10.0.3.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + } + }, + { + "edge-id":167773185, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "local-vertex-id":167837444, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.4.1", + "remote-address":"10.0.4.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5001, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5000, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167773186, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837444, + "metric":10, + "edge-attributes":{ + "te-metric":30, + "local-address":"10.0.4.2", + "remote-address":"10.0.4.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":25000, + "utilized-bandwidth":125000000.0 + } + }, + { + "edge-id":167773441, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "local-vertex-id":167837443, + "remote-vertex-id":167837445, + "metric":0, + "edge-attributes":{ + "te-metric":10, + "local-address":"10.0.5.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "remote-asn":65535, + "remote-as-address":"10.0.255.5", + "delay":50000 + } + } + ], + "subnets":[ + { + "subnet-id":"10.0.0.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":10 + }, + { + "subnet-id":"10.0.0.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.3.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "vertex-id":167837443, + "metric":10 + }, + { + "subnet-id":"10.0.3.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.4.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "vertex-id":167837444, + "metric":10 + }, + { + "subnet-id":"10.0.4.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.5.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "vertex-id":167837443, + "metric":10 + }, + { + "subnet-id":"10.0.255.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":0 + }, + { + "subnet-id":"10.0.255.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":0 + }, + { + "subnet-id":"10.0.255.3\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "vertex-id":167837443, + "metric":0 + }, + { + "subnet-id":"10.0.255.4\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "vertex-id":167837444, + "metric":0, + "segment-routing":{ + "pref-sid":400, + "algo":0, + "flags":"0x40" + } + }, + { + "subnet-id":"10.0.255.5\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.5", + "vertex-id":167837445, + "metric":10 + } + ] + } +} diff --git a/tests/topotests/ospf-te-topo1/reference/ted_step3.json b/tests/topotests/ospf-te-topo1/reference/ted_step3.json new file mode 100644 index 0000000000..117011a43a --- /dev/null +++ b/tests/topotests/ospf-te-topo1/reference/ted_step3.json @@ -0,0 +1,409 @@ +{ + "ted":{ + "name":"OSPF", + "key":1, + "verticesCount":4, + "edgesCount":6, + "subnetsCount":10, + "vertices":[ + { + "vertex-id":167837441, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.1", + "vertex-type":"Standard" + }, + { + "vertex-id":167837442, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.2", + "vertex-type":"Standard" + }, + { + "vertex-id":167837443, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.3", + "vertex-type":"ASBR" + }, + { + "vertex-id":167837444, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.4", + "vertex-type":"Standard", + "segment-routing":{ + "srgb-size":10000, + "srgb-lower":10000, + "algorithms":[ + { + "0":"SPF" + } + ], + "srlb-size":1000, + "srlb-lower":5000, + "msd":12 + } + } + ], + "edges":[ + { + "edge-id":167772161, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "local-vertex-id":167837441, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":20, + "local-address":"10.0.0.1", + "remote-address":"10.0.0.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":10000, + "available-bandwidth":125000000.0 + } + }, + { + "edge-id":167772162, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837441, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.0.2", + "remote-address":"10.0.0.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + } + }, + { + "edge-id":167772929, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "local-vertex-id":167837443, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "admin-group":32, + "local-address":"10.0.3.1", + "remote-address":"10.0.3.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + } + }, + { + "edge-id":167772930, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837443, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.3.2", + "remote-address":"10.0.3.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + } + }, + { + "edge-id":167773185, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "local-vertex-id":167837444, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.4.1", + "remote-address":"10.0.4.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5001, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5000, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167773186, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837444, + "metric":10, + "edge-attributes":{ + "te-metric":30, + "local-address":"10.0.4.2", + "remote-address":"10.0.4.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":25000, + "utilized-bandwidth":125000000.0 + } + } + ], + "subnets":[ + { + "subnet-id":"10.0.0.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":10 + }, + { + "subnet-id":"10.0.0.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.3.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "vertex-id":167837443, + "metric":10 + }, + { + "subnet-id":"10.0.3.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.4.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "vertex-id":167837444, + "metric":10 + }, + { + "subnet-id":"10.0.4.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.255.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":0 + }, + { + "subnet-id":"10.0.255.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":0 + }, + { + "subnet-id":"10.0.255.3\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "vertex-id":167837443, + "metric":0 + }, + { + "subnet-id":"10.0.255.4\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "vertex-id":167837444, + "metric":0, + "segment-routing":{ + "pref-sid":400, + "algo":0, + "flags":"0x40" + } + } + ] + } +} diff --git a/tests/topotests/ospf-te-topo1/reference/ted_step4.json b/tests/topotests/ospf-te-topo1/reference/ted_step4.json new file mode 100644 index 0000000000..5c2dee1e4b --- /dev/null +++ b/tests/topotests/ospf-te-topo1/reference/ted_step4.json @@ -0,0 +1,490 @@ +{ + "ted":{ + "name":"OSPF", + "key":1, + "verticesCount":4, + "edgesCount":6, + "subnetsCount":10, + "vertices":[ + { + "vertex-id":167837441, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.1", + "vertex-type":"Standard", + "segment-routing":{ + "srgb-size":4000, + "srgb-lower":20000, + "algorithms":[ + { + "0":"SPF" + } + ], + "srlb-size":1000, + "srlb-lower":15000 + } + }, + { + "vertex-id":167837442, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.2", + "vertex-type":"Standard", + "segment-routing":{ + "srgb-size":8000, + "srgb-lower":16000, + "algorithms":[ + { + "0":"SPF" + } + ], + "srlb-size":2000, + "srlb-lower":5000, + "msd":16 + } + }, + { + "vertex-id":167837443, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.3", + "vertex-type":"ASBR" + }, + { + "vertex-id":167837444, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.4", + "vertex-type":"Standard", + "segment-routing":{ + "srgb-size":10000, + "srgb-lower":10000, + "algorithms":[ + { + "0":"SPF" + } + ], + "srlb-size":1000, + "srlb-lower":5000, + "msd":12 + } + } + ], + "edges":[ + { + "edge-id":167772161, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "local-vertex-id":167837441, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":20, + "local-address":"10.0.0.1", + "remote-address":"10.0.0.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":10000, + "available-bandwidth":125000000.0 + }, + "segment-routing":[ + { + "adj-sid":15001, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":15000, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167772162, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837441, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.0.2", + "remote-address":"10.0.0.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5001, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5000, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167772929, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "local-vertex-id":167837443, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "admin-group":32, + "local-address":"10.0.3.1", + "remote-address":"10.0.3.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + } + }, + { + "edge-id":167772930, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837443, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.3.2", + "remote-address":"10.0.3.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5003, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5002, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167773185, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "local-vertex-id":167837444, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.4.1", + "remote-address":"10.0.4.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5001, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5000, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167773186, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837444, + "metric":10, + "edge-attributes":{ + "te-metric":30, + "local-address":"10.0.4.2", + "remote-address":"10.0.4.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":25000, + "utilized-bandwidth":125000000.0 + }, + "segment-routing":[ + { + "adj-sid":5005, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5004, + "flags":"0xe0", + "weight":0 + } + ] + } + ], + "subnets":[ + { + "subnet-id":"10.0.0.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":10 + }, + { + "subnet-id":"10.0.0.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.3.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "vertex-id":167837443, + "metric":10 + }, + { + "subnet-id":"10.0.3.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.4.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "vertex-id":167837444, + "metric":10 + }, + { + "subnet-id":"10.0.4.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.255.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":0, + "segment-routing":{ + "pref-sid":10, + "algo":0, + "flags":"0x0" + } + }, + { + "subnet-id":"10.0.255.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":0, + "segment-routing":{ + "pref-sid":20, + "algo":0, + "flags":"0x50" + } + }, + { + "subnet-id":"10.0.255.3\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "vertex-id":167837443, + "metric":0 + }, + { + "subnet-id":"10.0.255.4\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "vertex-id":167837444, + "metric":0, + "segment-routing":{ + "pref-sid":400, + "algo":0, + "flags":"0x40" + } + } + ] + } +} diff --git a/tests/topotests/ospf-te-topo1/reference/ted_step5.json b/tests/topotests/ospf-te-topo1/reference/ted_step5.json new file mode 100644 index 0000000000..47e747f3ca --- /dev/null +++ b/tests/topotests/ospf-te-topo1/reference/ted_step5.json @@ -0,0 +1,614 @@ +{ + "ted":{ + "name":"OSPF", + "key":1, + "verticesCount":4, + "edgesCount":8, + "subnetsCount":12, + "vertices":[ + { + "vertex-id":167837441, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.1", + "vertex-type":"Standard", + "segment-routing":{ + "srgb-size":4000, + "srgb-lower":20000, + "algorithms":[ + { + "0":"SPF" + } + ], + "srlb-size":1000, + "srlb-lower":15000 + } + }, + { + "vertex-id":167837442, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.2", + "vertex-type":"Standard", + "segment-routing":{ + "srgb-size":8000, + "srgb-lower":16000, + "algorithms":[ + { + "0":"SPF" + } + ], + "srlb-size":2000, + "srlb-lower":5000, + "msd":16 + } + }, + { + "vertex-id":167837443, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.3", + "vertex-type":"ASBR" + }, + { + "vertex-id":167837444, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.4", + "vertex-type":"Standard", + "segment-routing":{ + "srgb-size":10000, + "srgb-lower":10000, + "algorithms":[ + { + "0":"SPF" + } + ], + "srlb-size":1000, + "srlb-lower":5000, + "msd":12 + } + } + ], + "edges":[ + { + "edge-id":167772161, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "local-vertex-id":167837441, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":20, + "local-address":"10.0.0.1", + "remote-address":"10.0.0.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":10000, + "available-bandwidth":125000000.0 + }, + "segment-routing":[ + { + "adj-sid":15001, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":15000, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167772162, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837441, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.0.2", + "remote-address":"10.0.0.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5001, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5000, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167772417, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "local-vertex-id":167837441, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.1.1", + "remote-address":"10.0.1.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":15003, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":15002, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167772418, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837441, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.1.2", + "remote-address":"10.0.1.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5007, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5006, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167772929, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "local-vertex-id":167837443, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "admin-group":32, + "local-address":"10.0.3.1", + "remote-address":"10.0.3.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + } + }, + { + "edge-id":167772930, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837443, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.3.2", + "remote-address":"10.0.3.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5003, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5002, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167773185, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "local-vertex-id":167837444, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.4.1", + "remote-address":"10.0.4.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5001, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5000, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167773186, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837444, + "metric":10, + "edge-attributes":{ + "te-metric":30, + "local-address":"10.0.4.2", + "remote-address":"10.0.4.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":25000, + "utilized-bandwidth":125000000.0 + }, + "segment-routing":[ + { + "adj-sid":5005, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5004, + "flags":"0xe0", + "weight":0 + } + ] + } + ], + "subnets":[ + { + "subnet-id":"10.0.0.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":10 + }, + { + "subnet-id":"10.0.0.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.1.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":10 + }, + { + "subnet-id":"10.0.1.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.3.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "vertex-id":167837443, + "metric":10 + }, + { + "subnet-id":"10.0.3.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.4.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "vertex-id":167837444, + "metric":10 + }, + { + "subnet-id":"10.0.4.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.255.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":0, + "segment-routing":{ + "pref-sid":10, + "algo":0, + "flags":"0x0" + } + }, + { + "subnet-id":"10.0.255.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":0, + "segment-routing":{ + "pref-sid":20, + "algo":0, + "flags":"0x50" + } + }, + { + "subnet-id":"10.0.255.3\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "vertex-id":167837443, + "metric":0 + }, + { + "subnet-id":"10.0.255.4\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "vertex-id":167837444, + "metric":0, + "segment-routing":{ + "pref-sid":400, + "algo":0, + "flags":"0x40" + } + } + ] + } +} diff --git a/tests/topotests/ospf-te-topo1/reference/ted_step6.json b/tests/topotests/ospf-te-topo1/reference/ted_step6.json new file mode 100644 index 0000000000..74bd83fbdb --- /dev/null +++ b/tests/topotests/ospf-te-topo1/reference/ted_step6.json @@ -0,0 +1,615 @@ +{ + "ted":{ + "name":"OSPF", + "key":1, + "verticesCount":4, + "edgesCount":8, + "subnetsCount":12, + "vertices":[ + { + "vertex-id":167837441, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.1", + "vertex-type":"Standard", + "segment-routing":{ + "srgb-size":4000, + "srgb-lower":20000, + "algorithms":[ + { + "0":"SPF" + } + ], + "srlb-size":1000, + "srlb-lower":15000 + } + }, + { + "vertex-id":167837442, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.2", + "vertex-type":"Standard", + "segment-routing":{ + "srgb-size":8000, + "srgb-lower":16000, + "algorithms":[ + { + "0":"SPF" + } + ], + "srlb-size":2000, + "srlb-lower":5000, + "msd":16 + } + }, + { + "vertex-id":167837443, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.3", + "vertex-type":"ASBR" + }, + { + "vertex-id":167837444, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.4", + "vertex-type":"Standard", + "segment-routing":{ + "srgb-size":10000, + "srgb-lower":10000, + "algorithms":[ + { + "0":"SPF" + } + ], + "srlb-size":1000, + "srlb-lower":5000, + "msd":12 + } + } + ], + "edges":[ + { + "edge-id":167772161, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "local-vertex-id":167837441, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":20, + "local-address":"10.0.0.1", + "remote-address":"10.0.0.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":10000, + "available-bandwidth":125000000.0 + }, + "segment-routing":[ + { + "adj-sid":15001, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":15000, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167772162, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837441, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.0.2", + "remote-address":"10.0.0.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5001, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5000, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167772417, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "local-vertex-id":167837441, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.1.1", + "remote-address":"10.0.1.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":15003, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":15002, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167772418, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837441, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.1.2", + "remote-address":"10.0.1.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5007, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5006, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167772929, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "local-vertex-id":167837443, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "admin-group":32, + "local-address":"10.0.3.1", + "remote-address":"10.0.3.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + } + }, + { + "edge-id":167772930, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837443, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.3.2", + "remote-address":"10.0.3.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5003, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5002, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167773185, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "local-vertex-id":167837444, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.4.1", + "remote-address":"10.0.4.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":20000, + "jitter":10000 + }, + "segment-routing":[ + { + "adj-sid":5001, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5000, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167773186, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837444, + "metric":10, + "edge-attributes":{ + "te-metric":30, + "local-address":"10.0.4.2", + "remote-address":"10.0.4.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":25000 + }, + "segment-routing":[ + { + "adj-sid":5005, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5004, + "flags":"0xe0", + "weight":0 + } + ] + } + ], + "subnets":[ + { + "subnet-id":"10.0.0.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":10 + }, + { + "subnet-id":"10.0.0.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.1.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":10 + }, + { + "subnet-id":"10.0.1.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.3.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "vertex-id":167837443, + "metric":10 + }, + { + "subnet-id":"10.0.3.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.4.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "vertex-id":167837444, + "metric":10 + }, + { + "subnet-id":"10.0.4.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.255.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":0, + "segment-routing":{ + "pref-sid":10, + "algo":0, + "flags":"0x0" + } + }, + { + "subnet-id":"10.0.255.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":0, + "segment-routing":{ + "pref-sid":20, + "algo":0, + "flags":"0x50" + } + }, + { + "subnet-id":"10.0.255.3\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "vertex-id":167837443, + "metric":0 + }, + { + "subnet-id":"10.0.255.4\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "vertex-id":167837444, + "metric":0, + "segment-routing":{ + "pref-sid":400, + "algo":0, + "flags":"0x40" + } + } + ] + } +} diff --git a/tests/topotests/ospf-te-topo1/reference/ted_step7.json b/tests/topotests/ospf-te-topo1/reference/ted_step7.json new file mode 100644 index 0000000000..1cea9f0455 --- /dev/null +++ b/tests/topotests/ospf-te-topo1/reference/ted_step7.json @@ -0,0 +1,456 @@ +{ + "ted":{ + "name":"OSPF", + "key":1, + "verticesCount":3, + "edgesCount":6, + "subnetsCount":9, + "vertices":[ + { + "vertex-id":167837441, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.1", + "vertex-type":"Standard", + "segment-routing":{ + "srgb-size":4000, + "srgb-lower":20000, + "algorithms":[ + { + "0":"SPF" + } + ], + "srlb-size":1000, + "srlb-lower":15000 + } + }, + { + "vertex-id":167837442, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.2", + "vertex-type":"Standard", + "segment-routing":{ + "srgb-size":8000, + "srgb-lower":16000, + "algorithms":[ + { + "0":"SPF" + } + ], + "srlb-size":2000, + "srlb-lower":5000, + "msd":16 + } + }, + { + "vertex-id":167837443, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.3", + "vertex-type":"ASBR" + } + ], + "edges":[ + { + "edge-id":167772161, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "local-vertex-id":167837441, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":20, + "local-address":"10.0.0.1", + "remote-address":"10.0.0.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":10000, + "available-bandwidth":125000000.0 + }, + "segment-routing":[ + { + "adj-sid":15001, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":15000, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167772162, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837441, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.0.2", + "remote-address":"10.0.0.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5001, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5000, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167772417, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "local-vertex-id":167837441, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.1.1", + "remote-address":"10.0.1.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":15003, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":15002, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167772418, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837441, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.1.2", + "remote-address":"10.0.1.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5007, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5006, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167772929, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "local-vertex-id":167837443, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "admin-group":32, + "local-address":"10.0.3.1", + "remote-address":"10.0.3.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + } + }, + { + "edge-id":167772930, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837443, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.3.2", + "remote-address":"10.0.3.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5003, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5002, + "flags":"0xe0", + "weight":0 + } + ] + } + ], + "subnets":[ + { + "subnet-id":"10.0.0.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":10 + }, + { + "subnet-id":"10.0.0.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.1.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":10 + }, + { + "subnet-id":"10.0.1.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.3.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "vertex-id":167837443, + "metric":10 + }, + { + "subnet-id":"10.0.3.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.255.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":0, + "segment-routing":{ + "pref-sid":10, + "algo":0, + "flags":"0x0" + } + }, + { + "subnet-id":"10.0.255.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":0, + "segment-routing":{ + "pref-sid":20, + "algo":0, + "flags":"0x50" + } + }, + { + "subnet-id":"10.0.255.3\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "vertex-id":167837443, + "metric":0 + } + ] + } +} diff --git a/tests/topotests/ospf-te-topo1/test_ospf_te_topo1.py b/tests/topotests/ospf-te-topo1/test_ospf_te_topo1.py new file mode 100644 index 0000000000..32f9b3453e --- /dev/null +++ b/tests/topotests/ospf-te-topo1/test_ospf_te_topo1.py @@ -0,0 +1,300 @@ +#!/usr/bin/env python + +# +# test_ospf_te_topo1.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2021 by Orange +# Author: Olivier Dugeon <olivier.dugeon@orange.com> +# +# 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_ospf_te_topo1.py: Test the FRR OSPF with Traffic Engineering. + + +------------+ + | | + | R1 | + | 10.0.225.1 | + | | + +------------+ + r1-eth0| |r1-eth1 + | | + 10.0.0.0/24| |10.0.1.0/24 + | | + r2-eth0| |r2-eth1 + +------------+ +------------+ + | | | | + | R2 |r2-eth2 r3-eth0| R3 | + | 10.0.255.2 +------------------+ 10.0.255.3 | + | | 10.0.3.0/24 | | + +------------+ +------+-----+ + r2-eth3| r3-eth1| + | | + 10.0.4.0/24| 10.0.5.0/24| + | | + r4-eth0| V + +------------+ ASBR 10.0.255.5 + | | + | R4 | + | 10.0.255.4 | + | | + +------------+ + +""" + +import os +import sys +import json +from functools import partial + +# 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 +# Required to instantiate the topology builder class. +from mininet.topo import Topo + +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +# and Finally pytest +import pytest + +pytestmark = [pytest.mark.ospfd] + + +class OspfTeTopo(Topo): + "Test topology builder" + + def build(self): + "Build function" + tgen = get_topogen(self) + + # Create 4 routers + for routern in range(1, 5): + tgen.add_router("r{}".format(routern)) + + # Interconect router 1 and 2 with 2 links + 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["r1"]) + switch.add_link(tgen.gears["r2"]) + + # Interconect router 3 and 2 + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["r2"]) + + # Interconect router 4 and 2 + switch = tgen.add_switch("s4") + switch.add_link(tgen.gears["r4"]) + switch.add_link(tgen.gears["r2"]) + + # Interconnect router 3 with next AS + switch = tgen.add_switch("s5") + switch.add_link(tgen.gears["r3"]) + + +def setup_module(mod): + "Sets up the pytest environment" + + logger.info("\n\n---- Starting OSPF TE tests ----\n") + + tgen = Topogen(OspfTeTopo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for rname, router in router_list.items(): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname)) + ) + + # Initialize all routers. + tgen.start_router() + + +def teardown_module(): + "Teardown the pytest environment" + + tgen = get_topogen() + tgen.stop_topology() + + logger.info("\n\n---- OSPF TE tests End ----\n") + + +def compare_ted_json_output(tgen, rname, fileref): + "Compare TED JSON output" + + logger.info('Comparing router "%s" TED output', rname) + + filename = "{}/reference/{}".format(CWD, fileref) + expected = json.loads(open(filename).read()) + command = "show ip ospf mpls-te database json" + + # Run test function until we get an result. Wait at most 60 seconds. + test_func = partial(topotest.router_json_cmp, tgen.gears[rname], command, expected) + _, diff = topotest.run_and_expect(test_func, None, count=60, wait=2) + assertmsg = '"{}" TED JSON output mismatches the expected result'.format(rname) + assert diff is None, assertmsg + + +def setup_testcase(msg): + "Setup test case" + + logger.info(msg) + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + return tgen + + +# Note that all routers must discover the same Network Topology, so the same TED. + + +def test_step1(): + "Step1: Check initial topology" + + tgen = setup_testcase("Step1: test initial OSPF TE Data Base") + + for rname in ["r1", "r2", "r3", "r4"]: + compare_ted_json_output(tgen, rname, "ted_step1.json") + + +def test_step2(): + "Step2: Shutdown interface between r1 and r2 and verify that \ + corresponding Edges are removed from the TED on all routers " + + tgen = setup_testcase("Step2: Shutdown interface between r1 & r2") + + tgen.net["r1"].cmd('vtysh -c "conf t" -c "interface r1-eth1" -c "shutdown"') + tgen.net["r2"].cmd('vtysh -c "conf t" -c "interface r2-eth1" -c "shutdown"') + + for rname in ["r1", "r2", "r3", "r4"]: + compare_ted_json_output(tgen, rname, "ted_step2.json") + + +def test_step3(): + "Step3: Disable Inter-AS on r3 and verify that corresponding Edge and \ + remote ASBR are removed from the TED on all routers" + + tgen = setup_testcase("Step3: Disable Inter-AS on r3") + + tgen.net["r3"].cmd('vtysh -c "conf t" -c "router ospf" -c "no mpls-te inter-as"') + for rname in ["r1", "r2", "r3", "r4"]: + compare_ted_json_output(tgen, rname, "ted_step3.json") + + +def test_step4(): + "Step4: Enable Segment Routing on r1 and r2 and verify that corresponding \ + Edges are updated with Adjacency SID and Subnets with Prefix SID in the \ + TED on all routers" + + tgen = setup_testcase("Step4: Enable Segment Routing on r1 & r2") + + tgen.net["r1"].cmd('vtysh -c "conf t" -c "router ospf" -c "segment-routing on"') + tgen.net["r1"].cmd( + 'vtysh -c "conf t" -c "router ospf" -c "segment-routing global-block 20000 23999"' + ) + tgen.net["r1"].cmd( + 'vtysh -c "conf t" -c "router ospf" -c "segment-routing prefix 10.0.255.1/32 index 10"' + ) + tgen.net["r2"].cmd('vtysh -c "conf t" -c "router ospf" -c "segment-routing on"') + tgen.net["r2"].cmd( + 'vtysh -c "conf t" -c "router ospf" -c "segment-routing node-msd 16"' + ) + tgen.net["r2"].cmd( + 'vtysh -c "conf t" -c "router ospf" -c "segment-routing local-block 5000 6999"' + ) + tgen.net["r2"].cmd( + 'vtysh -c "conf t" -c "router ospf" -c "segment-routing prefix 10.0.255.2/32 index 20 explicit-null"' + ) + + for rname in ["r1", "r2", "r3", "r4"]: + compare_ted_json_output(tgen, rname, "ted_step4.json") + + +def test_step5(): + "Step5: Re-enable interface between r1 & r2 and verify that corresponding \ + Edges are added in the TED on all routers" + + tgen = setup_testcase("Step5: Re-enable interface between r1 & r2") + + tgen.net["r1"].cmd('vtysh -c "conf t" -c "interface r1-eth1" -c "no shutdown"') + tgen.net["r2"].cmd('vtysh -c "conf t" -c "interface r2-eth1" -c "no shutdown"') + + for rname in ["r1", "r2", "r3", "r4"]: + compare_ted_json_output(tgen, rname, "ted_step5.json") + + +def test_step6(): + "Step6: Set delay and jitter for interface r4-eth0 on r4, remove use-bw \ + for interface r2-eth3 on r2 and verify that corresponding Edges are \ + updated in the TED on all routers" + + tgen = setup_testcase("Step6: Modify link parameters on r2 & r4") + + tgen.net["r2"].cmd( + 'vtysh -c "conf t" -c "interface r2-eth3" -c "link-params" -c "no use-bw"' + ) + tgen.net["r4"].cmd( + 'vtysh -c "conf t" -c "interface r4-eth0" -c "link-params" -c "delay 20000"' + ) + tgen.net["r4"].cmd( + 'vtysh -c "conf t" -c "interface r4-eth0" -c "link-params" -c "delay-variation 10000"' + ) + + for rname in ["r1", "r2", "r3", "r4"]: + compare_ted_json_output(tgen, rname, "ted_step6.json") + + +def test_step7(): + "Step7: Disable OSPF on r4 and verify that corresponding Vertex, Edges and \ + Subnets are removed from the TED on all remaining routers" + + tgen = setup_testcase("Step7: Disable OSPF on r4") + + tgen.net["r4"].cmd('vtysh -c "conf t" -c "no router ospf"') + + for rname in ["r1", "r2", "r3"]: + compare_ted_json_output(tgen, rname, "ted_step7.json") + + +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/ospf-topo1/r1/ospf6d.conf-pre-v4 b/tests/topotests/ospf-topo1/r1/ospf6d.conf-pre-v4 deleted file mode 100644 index 6a40f859db..0000000000 --- a/tests/topotests/ospf-topo1/r1/ospf6d.conf-pre-v4 +++ /dev/null @@ -1,9 +0,0 @@ -! -router ospf6 - router-id 10.0.255.1 - redistribute kernel - redistribute connected - redistribute static - interface r1-eth0 area 0.0.0.0 - interface r1-eth1 area 0.0.0.0 -! diff --git a/tests/topotests/ospf-topo1/r2/ospf6d.conf-pre-v4 b/tests/topotests/ospf-topo1/r2/ospf6d.conf-pre-v4 deleted file mode 100644 index 7448b25327..0000000000 --- a/tests/topotests/ospf-topo1/r2/ospf6d.conf-pre-v4 +++ /dev/null @@ -1,9 +0,0 @@ -! -router ospf6 - router-id 10.0.255.2 - redistribute kernel - redistribute connected - redistribute static - interface r2-eth0 area 0.0.0.0 - interface r2-eth1 area 0.0.0.0 -! diff --git a/tests/topotests/ospf-topo1/r3/ospf6d.conf-pre-v4 b/tests/topotests/ospf-topo1/r3/ospf6d.conf-pre-v4 deleted file mode 100644 index e853e0e2b2..0000000000 --- a/tests/topotests/ospf-topo1/r3/ospf6d.conf-pre-v4 +++ /dev/null @@ -1,10 +0,0 @@ -! -router ospf6 - router-id 10.0.255.3 - redistribute kernel - redistribute connected - redistribute static - interface r3-eth0 area 0.0.0.0 - interface r3-eth1 area 0.0.0.0 - interface r3-eth2 area 0.0.0.1 -! diff --git a/tests/topotests/ospf-topo1/r4/ospf6d.conf-pre-v4 b/tests/topotests/ospf-topo1/r4/ospf6d.conf-pre-v4 deleted file mode 100644 index dcc07a4fdc..0000000000 --- a/tests/topotests/ospf-topo1/r4/ospf6d.conf-pre-v4 +++ /dev/null @@ -1,9 +0,0 @@ -! -router ospf6 - router-id 10.0.255.4 - redistribute kernel - redistribute connected - redistribute static - interface r4-eth0 area 0.0.0.1 - interface r4-eth1 area 0.0.0.1 -! diff --git a/tests/topotests/ospf-topo1/test_ospf_topo1.py b/tests/topotests/ospf-topo1/test_ospf_topo1.py index 5bb6c2c818..42634ce906 100644 --- a/tests/topotests/ospf-topo1/test_ospf_topo1.py +++ b/tests/topotests/ospf-topo1/test_ospf_topo1.py @@ -93,8 +93,6 @@ def setup_module(mod): tgen.start_topology() ospf6_config = "ospf6d.conf" - if tgen.gears["r1"].has_version("<", "4.0"): - ospf6_config = "ospf6d.conf-pre-v4" router_list = tgen.routers() for rname, router in router_list.items(): @@ -118,6 +116,88 @@ def teardown_module(mod): tgen.stop_topology() +def test_wait_protocol_convergence(): + "Wait for OSPFv2/OSPFv3 to converge" + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("waiting for protocols to converge") + + def expect_ospfv2_neighbor_full(router, neighbor): + "Wait until OSPFv2 convergence." + logger.info("waiting OSPFv2 router '{}'".format(router)) + + def run_command_and_expect(): + """ + Function that runs command and expect the following outcomes: + * Full/DR + * Full/DROther + * Full/Backup + """ + result = tgen.gears[router].vtysh_cmd( + "show ip ospf neighbor json", isjson=True + ) + if ( + topotest.json_cmp( + result, {"neighbors": {neighbor: [{"state": "Full/DR"}]}} + ) + is None + ): + return None + + if ( + topotest.json_cmp( + result, {"neighbors": {neighbor: [{"state": "Full/DROther"}]}} + ) + is None + ): + return None + + return topotest.json_cmp( + result, {"neighbors": {neighbor: [{"state": "Full/Backup"}]}} + ) + + _, result = topotest.run_and_expect( + run_command_and_expect, None, count=130, wait=1 + ) + assertmsg = '"{}" convergence failure'.format(router) + assert result is None, assertmsg + + def expect_ospfv3_neighbor_full(router, neighbor): + "Wait until OSPFv3 convergence." + logger.info("waiting OSPFv3 router '{}'".format(router)) + test_func = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show ipv6 ospf6 neighbor json", + {"neighbors": [{"neighborId": neighbor, "state": "Full"}]}, + ) + _, result = topotest.run_and_expect(test_func, None, count=130, wait=1) + assertmsg = '"{}" convergence failure'.format(router) + assert result is None, assertmsg + + # Wait for OSPFv2 convergence + expect_ospfv2_neighbor_full("r1", "10.0.255.2") + expect_ospfv2_neighbor_full("r1", "10.0.255.3") + expect_ospfv2_neighbor_full("r2", "10.0.255.1") + expect_ospfv2_neighbor_full("r2", "10.0.255.3") + expect_ospfv2_neighbor_full("r3", "10.0.255.1") + expect_ospfv2_neighbor_full("r3", "10.0.255.2") + expect_ospfv2_neighbor_full("r3", "10.0.255.4") + expect_ospfv2_neighbor_full("r4", "10.0.255.3") + + # Wait for OSPFv3 convergence + expect_ospfv3_neighbor_full("r1", "10.0.255.2") + expect_ospfv3_neighbor_full("r1", "10.0.255.3") + expect_ospfv3_neighbor_full("r2", "10.0.255.1") + expect_ospfv3_neighbor_full("r2", "10.0.255.3") + expect_ospfv3_neighbor_full("r3", "10.0.255.1") + expect_ospfv3_neighbor_full("r3", "10.0.255.2") + expect_ospfv3_neighbor_full("r3", "10.0.255.4") + expect_ospfv3_neighbor_full("r4", "10.0.255.3") + + def compare_show_ipv6_ospf6(rname, expected): """ Calls 'show ipv6 ospf6 route' for router `rname` and compare the obtained diff --git a/tests/topotests/ospf6-topo1/r1/ospf6d.conf b/tests/topotests/ospf6-topo1/r1/ospf6d.conf index ab2c0c647e..9f7e058931 100644 --- a/tests/topotests/ospf6-topo1/r1/ospf6d.conf +++ b/tests/topotests/ospf6-topo1/r1/ospf6d.conf @@ -11,9 +11,13 @@ debug ospf6 flooding ! interface r1-stubnet ipv6 ospf6 network broadcast + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 ! interface r1-sw5 ipv6 ospf6 network broadcast + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 ! router ospf6 ospf6 router-id 10.0.0.1 diff --git a/tests/topotests/ospf6-topo1/r2/ospf6d.conf b/tests/topotests/ospf6-topo1/r2/ospf6d.conf index 075e815ed8..26ebc2c0ea 100644 --- a/tests/topotests/ospf6-topo1/r2/ospf6d.conf +++ b/tests/topotests/ospf6-topo1/r2/ospf6d.conf @@ -11,9 +11,13 @@ debug ospf6 flooding ! interface r2-stubnet ipv6 ospf6 network broadcast + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 ! interface r2-sw5 ipv6 ospf6 network broadcast + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 ! router ospf6 ospf6 router-id 10.0.0.2 diff --git a/tests/topotests/ospf6-topo1/r3/ospf6d.conf b/tests/topotests/ospf6-topo1/r3/ospf6d.conf index e9a07a7e28..e902496530 100644 --- a/tests/topotests/ospf6-topo1/r3/ospf6d.conf +++ b/tests/topotests/ospf6-topo1/r3/ospf6d.conf @@ -11,12 +11,18 @@ debug ospf6 flooding ! interface r3-stubnet ipv6 ospf6 network broadcast + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 ! interface r3-sw5 ipv6 ospf6 network broadcast + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 ! interface r3-sw6 ipv6 ospf6 network broadcast + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 ! router ospf6 ospf6 router-id 10.0.0.3 diff --git a/tests/topotests/ospf6-topo1/r4/ospf6d.conf b/tests/topotests/ospf6-topo1/r4/ospf6d.conf index fa66645f5a..5607a789de 100644 --- a/tests/topotests/ospf6-topo1/r4/ospf6d.conf +++ b/tests/topotests/ospf6-topo1/r4/ospf6d.conf @@ -11,9 +11,13 @@ debug ospf6 flooding ! interface r4-stubnet ipv6 ospf6 network broadcast + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 ! interface r4-sw6 ipv6 ospf6 network broadcast + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 ! router ospf6 ospf6 router-id 10.0.0.4 diff --git a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py index 6ae886b76e..f8c3476e18 100644 --- a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py +++ b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py @@ -185,70 +185,38 @@ def teardown_module(mod): tgen.stop_topology() -def test_ospf6_converged(): - +def test_wait_protocol_convergence(): + "Wait for OSPFv3 to converge" tgen = get_topogen() - - # Don't run this test if we have any failure. if tgen.routers_have_failure(): pytest.skip(tgen.errors) - # For debugging, uncomment the next line - # tgen.mininet_cli() - - # Wait for OSPF6 to converge (All Neighbors in either Full or TwoWay State) - logger.info("Waiting for OSPF6 convergence") - - # Set up for regex - pat1 = re.compile("^[0-9]") - pat2 = re.compile("Full") - - timeout = 60 - while timeout > 0: - logger.info("Timeout in %s: " % timeout), - sys.stdout.flush() - - # Look for any node not yet converged - for router, rnode in tgen.routers().items(): - resStr = rnode.vtysh_cmd("show ipv6 ospf neigh") - - isConverged = False + logger.info("waiting for protocols to converge") - for line in resStr.splitlines(): - res1 = pat1.match(line) - if res1: - isConverged = True - res2 = pat2.search(line) - - if res2 == None: - isConverged = False - break - - if isConverged == False: - logger.info("Waiting for {}".format(router)) - sys.stdout.flush() - break - - if isConverged: - logger.info("Done") - break - else: - sleep(5) - timeout -= 5 + def expect_neighbor_full(router, neighbor): + "Wait until OSPFv3 convergence." + logger.info("waiting OSPFv3 router '{}'".format(router)) + test_func = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show ipv6 ospf6 neighbor json", + {"neighbors": [{"neighborId": neighbor, "state": "Full"}]}, + ) + _, result = topotest.run_and_expect(test_func, None, count=130, wait=1) + assertmsg = '"{}" convergence failure'.format(router) + assert result is None, assertmsg - if timeout == 0: - # Bail out with error if a router fails to converge - ospfStatus = rnode.vtysh_cmd("show ipv6 ospf neigh") - assert False, "OSPFv6 did not converge:\n{}".format(ospfStatus) + expect_neighbor_full("r1", "10.0.0.2") + expect_neighbor_full("r1", "10.0.0.3") - logger.info("OSPFv3 converged.") + expect_neighbor_full("r2", "10.0.0.1") + expect_neighbor_full("r2", "10.0.0.3") - # For debugging, uncomment the next line - # tgen.mininet_cli() + expect_neighbor_full("r3", "10.0.0.1") + expect_neighbor_full("r3", "10.0.0.2") + expect_neighbor_full("r3", "10.0.0.4") - # Make sure that all daemons are still running - if tgen.routers_have_failure(): - assert tgen.errors == "", tgen.errors + expect_neighbor_full("r4", "10.0.0.3") def compare_show_ipv6(rname, expected): diff --git a/tests/topotests/ospf6-topo2/r1/ospf6d.conf b/tests/topotests/ospf6-topo2/r1/ospf6d.conf new file mode 100644 index 0000000000..c403fcd8dc --- /dev/null +++ b/tests/topotests/ospf6-topo2/r1/ospf6d.conf @@ -0,0 +1,9 @@ +interface r1-eth0 + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 +! +router ospf6 + ospf6 router-id 10.254.254.1 + area 0.0.0.1 stub + interface r1-eth0 area 0.0.0.1 +! diff --git a/tests/topotests/ospf6-topo2/r1/zebra.conf b/tests/topotests/ospf6-topo2/r1/zebra.conf new file mode 100644 index 0000000000..7fee2da8ba --- /dev/null +++ b/tests/topotests/ospf6-topo2/r1/zebra.conf @@ -0,0 +1,5 @@ +ipv6 forwarding +! +interface r1-eth0 + ipv6 address 2001:db8:1::2/64 +! diff --git a/tests/topotests/ospf6-topo2/r2/ospf6d.conf b/tests/topotests/ospf6-topo2/r2/ospf6d.conf new file mode 100644 index 0000000000..d4bb0e2a41 --- /dev/null +++ b/tests/topotests/ospf6-topo2/r2/ospf6d.conf @@ -0,0 +1,17 @@ +interface r2-eth0 + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 +! +interface r2-eth1 + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 +! +router ospf6 + ospf6 router-id 10.254.254.2 + redistribute connected + redistribute static + default-information originate always metric 123 + area 0.0.0.1 stub + interface r2-eth0 area 0.0.0.1 + interface r2-eth1 area 0.0.0.0 +! diff --git a/tests/topotests/ospf6-topo2/r2/zebra.conf b/tests/topotests/ospf6-topo2/r2/zebra.conf new file mode 100644 index 0000000000..891945a4e7 --- /dev/null +++ b/tests/topotests/ospf6-topo2/r2/zebra.conf @@ -0,0 +1,8 @@ +ipv6 forwarding +! +interface r2-eth0 + ipv6 address 2001:db8:1::1/64 +! +interface r2-eth1 + ipv6 address 2001:db8:2::2/64 +! diff --git a/tests/topotests/ospf6-topo2/r3/ospf6d.conf b/tests/topotests/ospf6-topo2/r3/ospf6d.conf new file mode 100644 index 0000000000..aaef00d5bb --- /dev/null +++ b/tests/topotests/ospf6-topo2/r3/ospf6d.conf @@ -0,0 +1,10 @@ +interface r3-eth0 + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 +! +router ospf6 + ospf6 router-id 10.254.254.3 + redistribute connected + redistribute static + interface r3-eth0 area 0.0.0.0 +! diff --git a/tests/topotests/ospf6-topo2/r3/zebra.conf b/tests/topotests/ospf6-topo2/r3/zebra.conf new file mode 100644 index 0000000000..dea2fe4778 --- /dev/null +++ b/tests/topotests/ospf6-topo2/r3/zebra.conf @@ -0,0 +1,8 @@ +ipv6 forwarding +! +interface r3-eth0 + ipv6 address 2001:db8:2::1/64 +! +ipv6 route fc00:1::/64 fc00:100::1234 +ipv6 route fc00:2::/64 fc00:100::1234 +ipv6 route fc00:3::/64 fc00:100::1234 diff --git a/tests/topotests/ospf6-topo2/test_ospf6_topo2.dot b/tests/topotests/ospf6-topo2/test_ospf6_topo2.dot new file mode 100644 index 0000000000..ba7a36f2b5 --- /dev/null +++ b/tests/topotests/ospf6-topo2/test_ospf6_topo2.dot @@ -0,0 +1,71 @@ +## 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="ospf6-topo2"; + + # 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, + ]; + + # Switches + sw1 [ + shape=oval, + label="sw1\n2001:db8:1::/64", + fillcolor="#d0e0d0", + style=filled, + ]; + sw2 [ + shape=oval, + label="sw2\n2001:db8:2::/64", + fillcolor="#d0e0d0", + style=filled, + ]; + sw3 [ + shape=oval, + label="sw3\n2001:db8:3::/64", + fillcolor="#d0e0d0", + style=filled, + ]; + + # Connections + subgraph cluster0 { + label="area 0.0.0.1"; + r1 -- sw1 [label="eth0\n.2"]; + } + + subgraph cluster1 { + label="area 0.0.0.0"; + r2 -- sw1 [label="eth0\n.1"]; + r2 -- sw2 [label="eth1\n.2"]; + r3 -- sw2 [label="eth0\n.1"]; + r3 -- sw3 [label="eth1\n.2"]; + } +} diff --git a/tests/topotests/ospf6-topo2/test_ospf6_topo2.png b/tests/topotests/ospf6-topo2/test_ospf6_topo2.png Binary files differnew file mode 100644 index 0000000000..ee1de60736 --- /dev/null +++ b/tests/topotests/ospf6-topo2/test_ospf6_topo2.png diff --git a/tests/topotests/ospf6-topo2/test_ospf6_topo2.py b/tests/topotests/ospf6-topo2/test_ospf6_topo2.py new file mode 100644 index 0000000000..efc8565bb3 --- /dev/null +++ b/tests/topotests/ospf6-topo2/test_ospf6_topo2.py @@ -0,0 +1,184 @@ +#!/usr/bin/env python + +# +# test_ospf6_topo2.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2021 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_ospf6_topo2.py: Test the FRR OSPFv3 daemon. +""" + +import os +import sys +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 + +pytestmark = [pytest.mark.ospf6d] + + +class OSPFv3Topo2(Topo): + "Test topology builder" + + def build(self, *_args, **_opts): + "Build function" + tgen = get_topogen(self) + + # Create 3 routers + for routern in range(1, 4): + 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"]) + + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(OSPFv3Topo2, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + for rname, router in router_list.items(): + daemon_file = "{}/{}/zebra.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_ZEBRA, daemon_file) + + daemon_file = "{}/{}/ospf6d.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_OSPF6, daemon_file) + + # Initialize all routers. + tgen.start_router() + + +def test_wait_protocol_convergence(): + "Wait for OSPFv3 to converge" + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("waiting for protocols to converge") + + def expect_neighbor_full(router, neighbor): + "Wait until OSPFv3 convergence." + logger.info("waiting OSPFv3 router '{}'".format(router)) + test_func = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show ipv6 ospf6 neighbor json", + {"neighbors": [{"neighborId": neighbor, "state": "Full"}]}, + ) + _, result = topotest.run_and_expect(test_func, None, count=130, wait=1) + assertmsg = '"{}" convergence failure'.format(router) + assert result is None, assertmsg + + expect_neighbor_full("r1", "10.254.254.2") + expect_neighbor_full("r2", "10.254.254.1") + expect_neighbor_full("r2", "10.254.254.3") + expect_neighbor_full("r3", "10.254.254.2") + + +def test_ospf6_default_route(): + "Wait for OSPFv3 default route in stub area." + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("waiting for default route") + + def expect_route(router, route, metric): + "Test OSPF6 route existence." + logger.info("waiting OSPFv3 router '{}' routes".format(router)) + test_func = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show ipv6 route json", + {route: [{"metric": metric}]}, + ) + _, result = topotest.run_and_expect(test_func, None, count=4, wait=1) + assertmsg = '"{}" convergence failure'.format(router) + assert result is None, assertmsg + + def expect_lsa(router, area, prefix, metric): + "Test OSPF6 LSA existence." + logger.info("waiting OSPFv3 router '{}' LSA".format(router)) + test_func = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show ipv6 ospf6 database inter-prefix detail json", + { + "areaScopedLinkStateDb": [ + { + "areaId": area, + "lsa": [ + { + "prefix": prefix, + "metric": metric, + } + ], + } + ] + }, + ) + _, result = topotest.run_and_expect(test_func, None, count=4, wait=1) + assertmsg = '"{}" convergence failure'.format(router) + assert result is None, assertmsg + + metric = 123 + expect_lsa("r1", "0.0.0.1", "::/0", metric) + expect_route("r1", "::/0", metric + 10) + + +def teardown_module(_mod): + "Teardown the pytest environment" + tgen = get_topogen() + tgen.stop_topology() + + +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/ospf_basic_functionality/test_ospf_chaos.py b/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py index cebe55b39c..c117fc6a72 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py @@ -249,17 +249,20 @@ def test_ospf_chaos_tc31_p1(request): dut = "r1" protocol = "ospf" result = verify_ospf_rib(tgen, dut, input_dict, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: OSPF routes are present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: OSPF routes are present \n Error: {}".format( tc_name, result - )) + ) - result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, - expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present \n Error: {}".format( + result = verify_rib( + tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False + ) + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: routes are still present \n Error: {}".format( tc_name, result - )) + ) step("Bring up OSPFd daemon on R0.") start_router_daemons(tgen, "r0", ["ospfd"]) @@ -482,17 +485,20 @@ def test_ospf_chaos_tc34_p1(request): dut = "r1" protocol = "ospf" result = verify_ospf_rib(tgen, dut, input_dict, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: OSPF routes are present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: OSPF routes are present \n Error: {}".format( tc_name, result - )) + ) - result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, - expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present \n Error: {}".format( + result = verify_rib( + tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False + ) + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: routes are still present \n Error: {}".format( tc_name, result - )) + ) step("Bring up staticd daemon on R0.") start_router_daemons(tgen, "r0", ["staticd"]) diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py index adf82a5e85..1aabc06db0 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py @@ -259,19 +259,21 @@ def test_ospf_ecmp_tc16_p0(request): shutdown_bringup_interface(tgen, dut, intf, False) result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: OSPF routes are present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: OSPF routes are present \n Error: {}".format( tc_name, result - )) + ) protocol = "ospf" result = verify_rib( tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: routes are still present \n Error: {}".format( tc_name, result - )) + ) for intfr in range(1, 7): intf = topo["routers"]["r1"]["links"]["r0-link{}".format(intfr)]["interface"] @@ -326,10 +328,11 @@ def test_ospf_ecmp_tc16_p0(request): result = verify_ospf_rib( tgen, dut, input_dict, next_hop=nh, attempts=5, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: OSPF routes are present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: OSPF routes are present \n Error: {}".format( tc_name, result - )) + ) protocol = "ospf" result = verify_rib( @@ -342,10 +345,11 @@ def test_ospf_ecmp_tc16_p0(request): attempts=5, expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: routes are still present \n Error: {}".format( tc_name, result - )) + ) step("Re configure the static route in R0.") dut = "r0" @@ -432,10 +436,11 @@ def test_ospf_ecmp_tc17_p0(request): result = verify_ospf_rib( tgen, dut, input_dict, next_hop=nh, attempts=5, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: OSPF routes are present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: OSPF routes are present \n Error: {}".format( tc_name, result - )) + ) protocol = "ospf" result = verify_rib( @@ -448,10 +453,11 @@ def test_ospf_ecmp_tc17_p0(request): attempts=5, expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: routes are still present \n Error: {}".format( tc_name, result - )) + ) step("Reconfigure the static route in R0.Change ECMP value to 2.") dut = "r0" diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py index c5230d6614..e6dc18a434 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py @@ -307,10 +307,11 @@ def test_ospf_lan_ecmp_tc18_p0(request): result = verify_ospf_rib( tgen, dut, input_dict, next_hop=nh, attempts=5, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: OSPF routes are present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: OSPF routes are present \n Error: {}".format( tc_name, result - )) + ) protocol = "ospf" result = verify_rib( @@ -323,10 +324,11 @@ def test_ospf_lan_ecmp_tc18_p0(request): attempts=5, expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: routes are still present \n Error: {}".format( tc_name, result - )) + ) write_test_footer(tc_name) diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_lan.py b/tests/topotests/ospf_basic_functionality/test_ospf_lan.py index 2fbb27f4fc..d9b90a132a 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_lan.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_lan.py @@ -397,10 +397,11 @@ def test_ospf_lan_tc1_p0(request): shutdown_bringup_interface(tgen, dut, intf, False) result = verify_ospf_neighbor(tgen, topo, dut, lan=True, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r0: OSPF neighbors-hip is up \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r0: OSPF neighbors-hip is up \n Error: {}".format( tc_name, result - )) + ) step("No Shut interface on R0") dut = "r0" diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py b/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py index b99ce6cfb8..7864d0307a 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py @@ -332,18 +332,20 @@ def test_ospf_routemaps_functionality_tc19_p0(request): } } result = verify_ospf_rib(tgen, dut, input_dict, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: OSPF routes are present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: OSPF routes are present \n Error: {}".format( tc_name, result - )) + ) result = verify_rib( tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are present in fib \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: routes are present in fib \n Error: {}".format( tc_name, result - )) + ) step("Delete and reconfigure prefix list.") # Create ip prefix list @@ -383,18 +385,20 @@ def test_ospf_routemaps_functionality_tc19_p0(request): } } result = verify_ospf_rib(tgen, dut, input_dict, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: OSPF routes are present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: OSPF routes are present \n Error: {}".format( tc_name, result - )) + ) result = verify_rib( tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: OSPF routes are present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: OSPF routes are present \n Error: {}".format( tc_name, result - )) + ) pfx_list = { "r0": { @@ -438,18 +442,20 @@ def test_ospf_routemaps_functionality_tc19_p0(request): } } result = verify_ospf_rib(tgen, dut, input_dict, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: OSPF routes are present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: OSPF routes are present \n Error: {}".format( tc_name, result - )) + ) result = verify_rib( tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: routes are still present \n Error: {}".format( tc_name, result - )) + ) write_test_footer(tc_name) @@ -496,18 +502,20 @@ def test_ospf_routemaps_functionality_tc20_p0(request): dut = "r1" protocol = "ospf" result = verify_ospf_rib(tgen, dut, input_dict, attempts=2, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: OSPF routes are present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: OSPF routes are present \n Error: {}".format( tc_name, result - )) + ) result = verify_rib( tgen, "ipv4", dut, input_dict, protocol=protocol, attempts=2, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: routes are still present \n Error: {}".format( tc_name, result - )) + ) step( "configure the route map with the same name that is used " @@ -523,18 +531,20 @@ def test_ospf_routemaps_functionality_tc20_p0(request): dut = "r1" protocol = "ospf" result = verify_ospf_rib(tgen, dut, input_dict, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: OSPF routes are present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: OSPF routes are present \n Error: {}".format( tc_name, result - )) + ) result = verify_rib( tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: routes are still present \n Error: {}".format( tc_name, result - )) + ) # Create route map routemaps = {"r0": {"route_maps": {"rmap_ipv4": [{"action": "deny"}]}}} @@ -545,18 +555,20 @@ def test_ospf_routemaps_functionality_tc20_p0(request): dut = "r1" protocol = "ospf" result = verify_ospf_rib(tgen, dut, input_dict, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: OSPF routes are present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: OSPF routes are present \n Error: {}".format( tc_name, result - )) + ) result = verify_rib( tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: routes are still present \n Error: {}".format( tc_name, result - )) + ) step("Delete the route map.") # Create route map @@ -573,18 +585,20 @@ def test_ospf_routemaps_functionality_tc20_p0(request): dut = "r1" protocol = "ospf" result = verify_ospf_rib(tgen, dut, input_dict, expected=False) - assert result is not True, ("Testcase {} : Failed \n " - "r1: OSPF routes are present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: OSPF routes are present \n Error: {}".format( tc_name, result - )) + ) result = verify_rib( tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False ) - assert result is not True, ("Testcase {} : Failed \n " - "r1: routes are still present \n Error: {}".format( + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: routes are still present \n Error: {}".format( tc_name, result - )) + ) write_test_footer(tc_name) diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py index fb6b28ce5b..1432a82b12 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py @@ -247,11 +247,11 @@ def test_ospf_redistribution_tc5_p0(request): if result is not True: break - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: OSPF routes are present after deleting ip address of newly " - "configured interface of R0 \n Error: {}".format( - tc_name, result - )) + "configured interface of R0 \n Error: {}".format(tc_name, result) + ) protocol = "ospf" result = verify_rib( @@ -264,11 +264,11 @@ def test_ospf_redistribution_tc5_p0(request): attempts=5, expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: OSPF routes are present in fib after deleting ip address of newly " - "configured interface of R0 \n Error: {}".format( - tc_name, result - )) + "configured interface of R0 \n Error: {}".format(tc_name, result) + ) step("Add back the deleted ip address on newly configured interface of R0") topo1 = { @@ -370,11 +370,11 @@ def test_ospf_redistribution_tc6_p0(request): result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh, expected=False) if result is not True: break - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: OSPF routes are present after deleting ip address of newly " - "configured loopback of R0 \n Error: {}".format( - tc_name, result - )) + "configured loopback of R0 \n Error: {}".format(tc_name, result) + ) protocol = "ospf" result = verify_rib( @@ -386,11 +386,11 @@ def test_ospf_redistribution_tc6_p0(request): next_hop=nh, expected=False, ) - assert result is not True, ("Testcase {} : Failed \n " + assert result is not True, ( + "Testcase {} : Failed \n " "r1: OSPF routes are present in fib after deleting ip address of newly " - "configured loopback of R0 \n Error: {}".format( - tc_name, result - )) + "configured loopback of R0 \n Error: {}".format(tc_name, result) + ) step("Add back the deleted ip address on newly configured interface of R0") topo1 = { diff --git a/tests/topotests/ospf_suppress_fa/__init__.py b/tests/topotests/ospf_suppress_fa/__init__.py new file mode 100755 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/ospf_suppress_fa/__init__.py diff --git a/tests/topotests/ospf_suppress_fa/r1/ospfd.conf b/tests/topotests/ospf_suppress_fa/r1/ospfd.conf new file mode 100644 index 0000000000..c02be35b14 --- /dev/null +++ b/tests/topotests/ospf_suppress_fa/r1/ospfd.conf @@ -0,0 +1,9 @@ +! +interface r1-eth0 + ip ospf network point-to-point + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +router ospf + network 10.0.12.0/24 area 0 +! diff --git a/tests/topotests/ospf_suppress_fa/r1/zebra.conf b/tests/topotests/ospf_suppress_fa/r1/zebra.conf new file mode 100644 index 0000000000..c1e31fb474 --- /dev/null +++ b/tests/topotests/ospf_suppress_fa/r1/zebra.conf @@ -0,0 +1,4 @@ +! +interface r1-eth0 + ip address 10.0.12.1/24 +! diff --git a/tests/topotests/ospf_suppress_fa/r2/ospfd.conf b/tests/topotests/ospf_suppress_fa/r2/ospfd.conf new file mode 100644 index 0000000000..ebc7d252fd --- /dev/null +++ b/tests/topotests/ospf_suppress_fa/r2/ospfd.conf @@ -0,0 +1,16 @@ +! +interface r2-eth0 + ip ospf network point-to-point + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +interface r2-eth1 + ip ospf network point-to-point + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +router ospf + network 10.0.12.0/24 area 0 + network 10.0.23.0/24 area 1 + area 1 nssa +! diff --git a/tests/topotests/ospf_suppress_fa/r2/zebra.conf b/tests/topotests/ospf_suppress_fa/r2/zebra.conf new file mode 100644 index 0000000000..9f1a26349e --- /dev/null +++ b/tests/topotests/ospf_suppress_fa/r2/zebra.conf @@ -0,0 +1,7 @@ +! +interface r2-eth0 + ip address 10.0.12.2/24 +! +interface r2-eth1 + ip address 10.0.23.2/24 +! diff --git a/tests/topotests/ospf_suppress_fa/r3/ospfd.conf b/tests/topotests/ospf_suppress_fa/r3/ospfd.conf new file mode 100644 index 0000000000..08be11a7b7 --- /dev/null +++ b/tests/topotests/ospf_suppress_fa/r3/ospfd.conf @@ -0,0 +1,11 @@ +! +interface r3-eth0 + ip ospf network point-to-point + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +router ospf + redistribute static + network 10.0.23.0/24 area 1 + area 1 nssa +! diff --git a/tests/topotests/ospf_suppress_fa/r3/zebra.conf b/tests/topotests/ospf_suppress_fa/r3/zebra.conf new file mode 100644 index 0000000000..f76cbf74d2 --- /dev/null +++ b/tests/topotests/ospf_suppress_fa/r3/zebra.conf @@ -0,0 +1,8 @@ +! +ip route 3.3.1.1/32 Null0 +ip route 3.3.2.2/32 Null0 +ip route 3.3.3.3/32 Null0 +! +interface r3-eth0 + ip address 10.0.23.3/24 +! diff --git a/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.dot b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.dot new file mode 100644 index 0000000000..1036658f1a --- /dev/null +++ b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.dot @@ -0,0 +1,66 @@ +## 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_topo1 { + label="ospf suppress-fa"; + + # Routers + r1 [ + label="r1\nrtr-id 10.0.12.1", + shape=doubleoctagon, + fillcolor="#f08080", + style=filled, + ]; + r2 [ + label="r2 (ABR)\nrtr-id 10.0.23.2", + shape=doubleoctagon, + fillcolor="#f08080", + style=filled, + ]; + r3 [ + label="r3 (ASBR)\nrtr-id 10.0.23.3", + shape=doubleoctagon, + fillcolor="#f08080", + style=filled, + ]; + + # Switches + s1 [ + label="s1\n10.0.12.0/24", + shape=oval, + fillcolor="#d0e0d0", + style=filled, + ]; + s2 [ + label="s2\n10.0.23.0/24", + shape=oval, + fillcolor="#d0e0d0", + style=filled, + ]; + + # Connections + subgraph cluster0 { + label="area 0" + r1 -- s1 [label="eth1\n.1"]; + r2 -- s1 [label="eth1\n.2"]; + } + + subgraph cluster1 { + label="area 1\nNSSA" + r2 -- s2 [label="eth2\n.2"]; + r3 -- s2 [label="eth1\n.3"]; + } + + { rank=same; r1; r2; r3; } +} diff --git a/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.dot.jpg b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.dot.jpg Binary files differnew file mode 100644 index 0000000000..2907d799f5 --- /dev/null +++ b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.dot.jpg diff --git a/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py new file mode 100644 index 0000000000..76e50beb5c --- /dev/null +++ b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +# +# test_ospf_suppres_fa.py +# Carles Kishimoto +# +# 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_ospf_suppres_fa.py: Test OSPF suppress-fa feature +- Topology: r1 --- R2 (ABR) --- R3 (redistribute static) + +test_ospf_set_suppress_fa() + 1) R1: Get a dict[LSA_ID] = fwd_addr for all type 5 LSA + 2) R2: Configure: area 1 nssa suppress-fa + 3) R1: Get a dict[LSA_ID] and compare fwd_address with 0.0.0.0 + +test_ospf_unset_suppress_fa() + 4) R2: Configure: no area 1 nssa suppress-fa + 5) R1: Get a dict[LSA_ID] = fwd_addr and compare it with the dict obtained in 1) +""" + +import os +import sys +import re +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 + +# Required to instantiate the topology builder class. +from mininet.topo import Topo + + +class NetworkTopo(Topo): + "OSPF topology builder" + + def build(self, *_args, **_opts): + "Build function" + + tgen = get_topogen(self) + + # Create routers + for router in range(1, 4): + tgen.add_router("r{}".format(router)) + + # R1-R2 backbone area + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + # R2-R3 NSSA area + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["r3"]) + + +def setup_module(mod): + "Sets up the pytest environment" + + tgen = Topogen(NetworkTopo, mod.__name__) + tgen.start_topology() + + # This is a sample of configuration loading. + router_list = tgen.routers() + + # For all registred routers, load the zebra and ospf configuration file + for rname, router in router_list.items(): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname)) + ) + + tgen.start_router() + + +def teardown_module(_mod): + "Teardown the pytest environment" + + tgen = get_topogen() + 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(10, "Waiting for OSPF convergence") + + +def ospf_configure_suppress_fa(router_name, area): + "Configure OSPF suppress-fa in router_name" + + tgen = get_topogen() + router = tgen.gears[router_name] + router.vtysh_cmd( + "conf t\nrouter ospf\narea {} nssa suppress-fa\nexit\n".format(area) + ) + + +def ospf_unconfigure_suppress_fa(router_name, area): + "Remove OSPF suppress-fa in router_name" + + tgen = get_topogen() + router = tgen.gears[router_name] + router.vtysh_cmd( + "conf t\nrouter ospf\nno area {} nssa suppress-fa\nexit\n".format(area) + ) + + +def ospf_get_lsa_type5(router_name): + "Return a dict with link state id as key and forwarding addresses as value" + + result = dict() + tgen = get_topogen() + router = tgen.gears[router_name] + cmd = "show ip ospf database external\n" + output = topotest.normalize_text(router.vtysh_cmd(cmd)) + for line in output.splitlines(): + re0 = re.match(r"\s+Link State ID: (\S+) \(External Network Number\)", line) + if re0: + lsa = re0.group(1) + re1 = re.match(r"\s+Forward Address: (\S+)", line) + if re1: + result[lsa] = re1.group(1) + return result + + +@pytest.fixture(scope="module", name="original") +def test_ospf_set_suppress_fa(): + "Test OSPF area [x] nssa suppress-fa" + + # Get current forwarding address for each LSA type-5 in r1 + initial = ospf_get_lsa_type5("r1") + + # Configure suppres-fa in r2 area 1 + ospf_configure_suppress_fa("r2", "1") + topotest.sleep(10, "Waiting for OSPF convergence") + + # Check forwarding address on r1 for all statics is 0.0.0.0 + assertmsg = "Forwarding address is not 0.0.0.0 after enabling OSPF suppress-fa" + suppress = ospf_get_lsa_type5("r1") + for prefix in suppress: + assert suppress[prefix] == "0.0.0.0", assertmsg + + # Return the original forwarding addresses so we can compare them + # in the test_ospf_unset_supress_fa + return initial + + +def test_ospf_unset_supress_fa(original): + "Test OSPF no area [x] nssa suppress-fa" + + # Remove suppress-fa in r2 area 1 + ospf_unconfigure_suppress_fa("r2", "1") + topotest.sleep(10, "Waiting for OSPF convergence") + + # Check forwarding address is the original value on r1 for all statics + assertmsg = "Forwarding address is not correct after removing OSPF suppress-fa" + restore = ospf_get_lsa_type5("r1") + for prefix in restore: + assert restore[prefix] == original[prefix], assertmsg + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py index dc4e29ebde..5d4950a70e 100644 --- a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py +++ b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py @@ -949,10 +949,11 @@ def static_routes_rmap_pfxlist_p0_tc7_ebgp(request): result4 = verify_rib( tgen, addr_type, dut, input_dict, protocol=protocol, expected=False ) - assert result4 is not True, ("Testcase {} : Failed \n" - "routes are still present \n Error: {}".format( + assert ( + result4 is not True + ), "Testcase {} : Failed \n" "routes are still present \n Error: {}".format( tc_name, result4 - )) + ) step("vm4 should be present in FRR1") dut = "r1" diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py index 14db729195..09c437c3c4 100644 --- a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py +++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py @@ -947,10 +947,11 @@ def test_static_routes_rmap_pfxlist_p0_tc7_ibgp(request): result4 = verify_rib( tgen, addr_type, dut, input_dict, protocol=protocol, expected=False ) - assert result4 is not True, ("Testcase {} : Failed \n" - "routes are still present \n Error: {}".format( + assert ( + result4 is not True + ), "Testcase {} : Failed \n" "routes are still present \n Error: {}".format( tc_name, result4 - )) + ) step("vm4 should be present in FRR1") dut = "r1" |
