diff options
Diffstat (limited to 'tests/topotests/static_simple')
-rw-r--r-- | tests/topotests/static_simple/r1/mgmtd.conf | 1 | ||||
-rw-r--r-- | tests/topotests/static_simple/r1/staticd.conf | 1 | ||||
-rw-r--r-- | tests/topotests/static_simple/r1/zebra.conf | 11 | ||||
-rw-r--r-- | tests/topotests/static_simple/test_static_simple.py | 214 |
4 files changed, 227 insertions, 0 deletions
diff --git a/tests/topotests/static_simple/r1/mgmtd.conf b/tests/topotests/static_simple/r1/mgmtd.conf new file mode 100644 index 0000000..0f9f97c --- /dev/null +++ b/tests/topotests/static_simple/r1/mgmtd.conf @@ -0,0 +1 @@ +log timestamp precision 3 diff --git a/tests/topotests/static_simple/r1/staticd.conf b/tests/topotests/static_simple/r1/staticd.conf new file mode 100644 index 0000000..0f9f97c --- /dev/null +++ b/tests/topotests/static_simple/r1/staticd.conf @@ -0,0 +1 @@ +log timestamp precision 3 diff --git a/tests/topotests/static_simple/r1/zebra.conf b/tests/topotests/static_simple/r1/zebra.conf new file mode 100644 index 0000000..ec82761 --- /dev/null +++ b/tests/topotests/static_simple/r1/zebra.conf @@ -0,0 +1,11 @@ +log timestamp precision 3 + +interface r1-eth0 + ip address 101.0.0.1/24 + ipv6 address 2101::1/64 +exit + +interface r1-eth1 vrf red + ip address 102.0.0.1/24 + ipv6 address 2102::1/64 +exit diff --git a/tests/topotests/static_simple/test_static_simple.py b/tests/topotests/static_simple/test_static_simple.py new file mode 100644 index 0000000..fd87224 --- /dev/null +++ b/tests/topotests/static_simple/test_static_simple.py @@ -0,0 +1,214 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC +# +# Copyright (c) 2021, LabN Consulting, L.L.C. +# Copyright (c) 2019-2020 by +# Donatas Abraitis <donatas.abraitis@gmail.com> +# +""" +Test static route functionality +""" + +import datetime +import ipaddress +import math +import os +import sys +import re + +import pytest +from lib.topogen import TopoRouter, Topogen, get_topogen +from lib.topolog import logger +from lib.common_config import retry, step + +pytestmark = [pytest.mark.staticd] + + +@pytest.fixture(scope="module") +def tgen(request): + "Setup/Teardown the environment and provide tgen argument to tests" + + topodef = {"s1": ("r1",), "s2": ("r1",)} + + tgen = Topogen(topodef, request.module.__name__) + tgen.start_topology() + + router_list = tgen.routers() + for rname, router in router_list.items(): + # Setup VRF red + router.net.add_l3vrf("red", 10) + router.net.add_loop("lo-red") + router.net.attach_iface_to_l3vrf("lo-red", "red") + router.net.attach_iface_to_l3vrf(rname + "-eth1", "red") + # and select daemons to run + router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") + router.load_config(TopoRouter.RD_MGMTD) + router.load_config(TopoRouter.RD_STATIC) + + tgen.start_router() + yield tgen + tgen.stop_topology() + + +def get_ip_networks(super_prefix, count): + count_log2 = math.log(count, 2) + if count_log2 != int(count_log2): + count_log2 = int(count_log2) + 1 + else: + count_log2 = int(count_log2) + network = ipaddress.ip_network(super_prefix) + return tuple(network.subnets(count_log2))[0:count] + + +def enable_debug(router): + router.vtysh_cmd("debug northbound callbacks configuration") + + +def disable_debug(router): + router.vtysh_cmd("no debug northbound callbacks configuration") + + +@retry(retry_timeout=30, initial_wait=0.1) +def check_kernel(r1, super_prefix, count, add, is_blackhole, vrf, matchvia): + network = ipaddress.ip_network(super_prefix) + vrfstr = f" vrf {vrf}" if vrf else "" + if network.version == 6: + kernel = r1.run(f"ip -6 route show{vrfstr}") + else: + kernel = r1.run(f"ip -4 route show{vrfstr}") + + logger.debug("checking kernel routing table%s:\n%s", vrfstr, kernel) + for i, net in enumerate(get_ip_networks(super_prefix, count)): + if not add: + assert str(net) not in kernel + continue + + if is_blackhole: + route = f"blackhole {str(net)} proto (static|196) metric 20" + else: + route = ( + f"{str(net)}(?: nhid [0-9]+)? {matchvia} " + "proto (static|196) metric 20" + ) + assert re.search(route, kernel), f"Failed to find \n'{route}'\n in \n'{kernel}'" + + +def do_config( + r1, + count, + add=True, + do_ipv6=False, + via=None, + vrf=None, + use_cli=False, +): + optype = "adding" if add else "removing" + iptype = "IPv6" if do_ipv6 else "IPv4" + + # + # Set the route details + # + + if vrf: + super_prefix = "2002::/48" if do_ipv6 else "20.0.0.0/8" + else: + super_prefix = "2001::/48" if do_ipv6 else "10.0.0.0/8" + + matchtype = "" + matchvia = "" + if via == "blackhole": + pass + elif via: + matchvia = f"dev {via}" + else: + if vrf: + via = "2102::2" if do_ipv6 else "102.0.0.2" + matchvia = f"via {via} dev r1-eth1" + else: + via = "2101::2" if do_ipv6 else "101.0.0.2" + matchvia = f"via {via} dev r1-eth0" + + vrfdbg = " in vrf {}".format(vrf) if vrf else "" + logger.debug("{} {} static {} routes{}".format(optype, count, iptype, vrfdbg)) + + # + # Generate config file in a retrievable place + # + + config_file = os.path.join( + r1.logdir, r1.name, "{}-routes-{}.conf".format(iptype.lower(), optype) + ) + with open(config_file, "w") as f: + if use_cli: + f.write("configure terminal\n") + if vrf: + f.write("vrf {}\n".format(vrf)) + + for i, net in enumerate(get_ip_networks(super_prefix, count)): + if add: + f.write("ip route {} {}\n".format(net, via)) + else: + f.write("no ip route {} {}\n".format(net, via)) + + # + # Load config file. + # + + if use_cli: + load_command = 'vtysh < "{}"'.format(config_file) + else: + load_command = 'vtysh -f "{}"'.format(config_file) + tstamp = datetime.datetime.now() + output = r1.cmd_raises(load_command) + delta = (datetime.datetime.now() - tstamp).total_seconds() + + # + # Verify the results are in the kernel + # + check_kernel(r1, super_prefix, count, add, via == "blackhole", vrf, matchvia) + + optyped = "added" if add else "removed" + logger.debug( + "{} {} {} static routes under {}{} in {}s".format( + optyped, count, iptype.lower(), super_prefix, vrfdbg, delta + ) + ) + + +def guts(tgen, vrf, use_cli): + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.routers()["r1"] + + step("add via gateway", reset=True) + do_config(r1, 1, True, False, vrf=vrf, use_cli=use_cli) + step("remove via gateway") + do_config(r1, 1, False, False, vrf=vrf, use_cli=use_cli) + + via = f"lo-{vrf}" if vrf else "lo" + step("add via loopback") + do_config(r1, 1, True, False, via=via, vrf=vrf, use_cli=use_cli) + step("remove via loopback") + do_config(r1, 1, False, False, via=via, vrf=vrf, use_cli=use_cli) + + step("add via blackhole") + do_config(r1, 1, True, False, via="blackhole", vrf=vrf, use_cli=use_cli) + step("remove via blackhole") + do_config(r1, 1, False, False, via="blackhole", vrf=vrf, use_cli=use_cli) + + +def test_static_cli(tgen): + guts(tgen, "", True) + + +def test_static_file(tgen): + guts(tgen, "", False) + + +def test_static_vrf_cli(tgen): + guts(tgen, "red", True) + + +def test_static_vrf_file(tgen): + guts(tgen, "red", False) |