def test_bfd_loss_intermediate(): """ Assert that BFD notices the bfd link down failure. but BGP entries should still be present """ tgen = get_topogen() if tgen.routers_have_failure(): pytest.skip(tgen.errors) logger.info('removing IPv6 address from r2 to simulate loss of connectivity') # Disable r2-eth0 ipv6 address cmd = 'vtysh -c \"configure terminal\" -c \"interface r2-eth1\" -c "no ipv6 address 2001:db8:4::2/64\"' tgen.net['r2'].cmd(cmd) # Wait the minimum time we can before checking that BGP/BFD # converged. logger.info('waiting for BFD converge down') # Check that BGP converged quickly. for router in tgen.routers().values(): if router.name == 'r2': continue json_file = '{}/{}/peers_down.json'.format(CWD, router.name) expected = json.loads(open(json_file).read()) test_func = partial(topotest.router_json_cmp, router, 'show bfd peers json', expected) _, result = topotest.run_and_expect(test_func, None, count=8, wait=0.5) assertmsg = '"{}" JSON output mismatches'.format(router.name) assert result is None, assertmsg logger.info('waiting for BGP entries to become stale') for router in tgen.routers().values(): if router.name == 'r2': continue json_file = '{}/{}/bgp_ipv6_routes_down.json'.format(CWD, router.name) expected = json.loads(open(json_file).read()) test_func = partial(topotest.router_json_cmp, router, 'show bgp ipv6 json', expected) _, result = topotest.run_and_expect(test_func, None, count=50, wait=1) assertmsg = '"{}" JSON output mismatches'.format(router.name) assert result is None, assertmsg logger.info("Checking IPv6 routes on r1 should still be present") for router in tgen.routers().values(): if router.name == 'r2': continue if router.name == 'r3': continue json_file = '{}/r1/ipv6_routes.json'.format(CWD) expected = json.loads(open(json_file).read()) test_func = partial(topotest.router_json_cmp, router, 'show ipv6 route json', expected) _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assertmsg = '"{}" JSON output mismatches'.format(router.name) assert result is None, assertmsg
def test_ospf_link_down(): "Test OSPF convergence after a link goes down" tgen = get_topogen() if tgen.routers_have_failure(): pytest.skip('skipped because of router(s) failure') # Simulate a network down event on router3 switch3 interface. router3 = tgen.gears['r3'] topotest.interface_set_status(router3, 'r3-eth0', ifaceaction=False, vrf_name='r3-cust1') # Expect convergence on all routers for rname, router in tgen.routers().iteritems(): logger.info('Waiting for router "%s" convergence after link failure', rname) # Load expected results from the command reffile = os.path.join(CWD, '{}/ospfroute_down.txt'.format(rname)) expected = open(reffile).read() # Run test function until we get an result. Wait at most 60 seconds. test_func = partial(topotest.router_output_cmp, router, 'show ip ospf vrf {0}-cust1 route'.format(rname), expected) result, diff = topotest.run_and_expect(test_func, '', count=140, wait=0.5) assertmsg = 'OSPF did not converge on {}:\n{}'.format(rname, diff) assert result, assertmsg
def test_bgp_convergence(): "Test for BGP topology convergence" tgen = get_topogen() # uncomment if you want to troubleshoot # tgen.mininet_cli() # Skip if previous fatal error condition is raised if tgen.routers_have_failure(): pytest.skip(tgen.errors) logger.info('waiting for bgp convergence') # Expected result router = tgen.gears['r1'] if router.has_version('<', '3.0'): reffile = os.path.join(CWD, 'r1/summary20.txt') else: reffile = os.path.join(CWD, 'r1/summary.txt') expected = json.loads(open(reffile).read()) test_func = functools.partial(topotest.router_json_cmp, router, 'show bgp vrf r1-cust1 summary json', expected) _, res = topotest.run_and_expect(test_func, None, count=90, wait=0.5) assertmsg = 'BGP router network did not converge' assert res is None, assertmsg
def test_bgp_fast_reconvergence(): "Assert that BGP is converging after setting a link down." tgen = get_topogen() if tgen.routers_have_failure(): pytest.skip(tgen.errors) logger.info('waiting for BGP re convergence') # Check that BGP converged quickly. for router in tgen.routers().values(): ref_file = '{}/{}/bgp_prefixes.json'.format(CWD, router.name) expected = json.loads(open(ref_file).read()) # Load the same file as previous test, but set networks to None # to test absence. if router.name == 'r1': expected['routes']['10.254.254.2/32'] = None expected['routes']['10.254.254.3/32'] = None expected['routes']['10.254.254.4/32'] = None else: expected['routes']['10.254.254.1/32'] = None test_func = partial(topotest.router_json_cmp, router, 'show ip bgp vrf {}-cust1 json'.format(router.name), expected) _, res = topotest.run_and_expect( test_func, None, count=3, wait=1 ) assertmsg = '{}: bgp did not converge'.format(router.name) assert res is None, assertmsg
def test_protocols_convergence(): """ Assert that all protocols have converged before checking for the BFD statuses as they depend on it. """ tgen = get_topogen() if tgen.routers_have_failure(): pytest.skip(tgen.errors) # Check IPv6 routing tables. logger.info("Checking IPv6 routes for convergence") for router in tgen.routers().values(): if router.name == 'r2': continue json_file = '{}/{}/ipv6_routes.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 ipv6 route json', expected) _, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5) assertmsg = '"{}" JSON output mismatches'.format(router.name) assert result is None, assertmsg
def test_bgp_ecmp(): tgen = get_topogen() # Skip if previous fatal error condition is raised if tgen.routers_have_failure(): pytest.skip(tgen.errors) expect = { 'routerId': '10.0.255.1', 'routes': { }, } for net in range(1, 5): for subnet in range(0, 10): netkey = '10.20{}.{}.0/24'.format(net, subnet) expect['routes'][netkey] = [] for _ in range(0, 10): peer = {'multipath': True, 'valid': True} expect['routes'][netkey].append(peer) test_func = functools.partial(topotest.router_json_cmp, tgen.gears['r1'], 'show ip bgp json', expect) _, res = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assertmsg = 'expected multipath routes in "show ip bgp" output' assert res is None, assertmsg
def test_bfd_comes_back_again(): """ Assert that BFD notices the bfd link up and that ipv6 entries appear back """ tgen = get_topogen() logger.info('re-adding IPv6 address from r2 to simulate connectivity is back') # adds back r2-eth0 ipv6 address cmd = 'vtysh -c \"configure terminal\" -c \"interface r2-eth1\" -c "ipv6 address 2001:db8:4::2/64\"' tgen.net['r2'].cmd(cmd) # Wait the minimum time we can before checking that BGP/BFD # converged. logger.info('waiting for BFD to converge up') # Check that BGP converged quickly. for router in tgen.routers().values(): if router.name == 'r2': continue json_file = '{}/{}/peers.json'.format(CWD, router.name) expected = json.loads(open(json_file).read()) test_func = partial(topotest.router_json_cmp, router, 'show bfd peers json', expected) _, result = topotest.run_and_expect(test_func, None, count=8, wait=0.5) assertmsg = '"{}" JSON output mismatches'.format(router.name) assert result is None, assertmsg
def test_isis_convergence(): "Wait for the protocol to converge before starting to test" tgen = get_topogen() # Don't run this test if we have any failure. if tgen.routers_have_failure(): pytest.skip(tgen.errors) logger.info("waiting for ISIS protocol to converge") # Code to generate the json files. # for rname, router in tgen.routers().iteritems(): # open('/tmp/{}_topology.json'.format(rname), 'w').write( # json.dumps(show_isis_topology(router), indent=2, sort_keys=True) # ) for rname, router in tgen.routers().iteritems(): filename = '{0}/{1}/{1}_topology.json'.format(CWD, rname) expected = json.loads(open(filename).read()) def compare_isis_topology(router, expected): "Helper function to test ISIS topology convergence." actual = show_isis_topology(router) return topotest.json_cmp(actual, expected) test_func = functools.partial(compare_isis_topology, router, expected) (result, diff) = topotest.run_and_expect(test_func, None, wait=0.5, count=120) assert result, 'ISIS did not converge on {}:\n{}'.format(rname, diff)
def test_evpn_df(): """ 1. Check the DF role on all the PEs on rack-1. 2. Increase the DF preference on the non-DF and check if it becomes the DF winner. """ tgen = get_topogen() if tgen.routers_have_failure(): pytest.skip(tgen.errors) # We will run the tests on just one ES esi = host_es_map.get("hostd11") intf = "hostbond1" tors = [] tors.append(tgen.gears["torm11"]) tors.append(tgen.gears["torm12"]) df_node = "torm11" # check roles on rack-1 for tor in tors: role = "DF" if tor.name == df_node else "nonDF" test_fn = partial(check_df_role, tor, esi, role) _, result = topotest.run_and_expect(test_fn, None, count=20, wait=3) assertmsg = '"{}" DF role incorrect'.format(tor.name) assert result is None, assertmsg # change df preference on the nonDF to make it the df torm12 = tgen.gears["torm12"] torm12.vtysh_cmd("conf\ninterface %s\nevpn mh es-df-pref %d" % (intf, 60000)) df_node = "torm12" # re-check roles on rack-1; we should have a new winner for tor in tors: role = "DF" if tor.name == df_node else "nonDF" test_fn = partial(check_df_role, tor, esi, role) _, result = topotest.run_and_expect(test_fn, None, count=20, wait=3) assertmsg = '"{}" DF role incorrect'.format(tor.name) assert result is None, assertmsg
def check_mcast_entry(entry, mcastaddr, pimrp): "Helper function to check RP" tgen = get_topogen() logger.info( "Testing PIM RP selection for ACL {} entry using {}".format(entry, mcastaddr) ) with McastTesterHelper(tgen) as helper: helper.run("h2", ["--send=0.7", mcastaddr, "h2-eth0"]) helper.run("h1", [mcastaddr, "h1-eth0"]) logger.info("mcast join and source for {} started".format(mcastaddr)) # tgen.mininet_cli() router = tgen.gears["r1"] reffile = os.path.join(CWD, "r1/acl_{}_pim_join.json".format(entry)) expected = json.loads(open(reffile).read()) logger.info("verifying pim join on r1 for {}".format(mcastaddr)) test_func = functools.partial( topotest.router_json_cmp, router, "show ip pim join json", expected ) _, res = topotest.run_and_expect(test_func, None, count=60, wait=2) assertmsg = "PIM router r1 did not show join status" assert res is None, assertmsg logger.info("verifying pim join on PIM RP {} for {}".format(pimrp, mcastaddr)) router = tgen.gears[pimrp] reffile = os.path.join(CWD, "{}/acl_{}_pim_join.json".format(pimrp, entry)) expected = json.loads(open(reffile).read()) test_func = functools.partial( topotest.router_json_cmp, router, "show ip pim join json", expected ) _, res = topotest.run_and_expect(test_func, None, count=60, wait=2) assertmsg = "PIM router {} did not get selected as the PIM RP".format(pimrp) assert res is None, assertmsg return
def test_protocols_convergence(): """ Assert that all protocols have converged 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 IPv4 routes for convergence") for router in tgen.routers().values(): json_file = '{}/{}/ipv4_routes.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 vrf {}-cust1 json'.format(router.name), expected) _, result = topotest.run_and_expect(test_func, None, count=160, wait=0.5) assertmsg = '"{}" JSON output mismatches'.format(router.name) assert result is None, assertmsg # Check IPv6 routing tables. logger.info("Checking IPv6 routes for convergence") for router in tgen.routers().values(): json_file = '{}/{}/ipv6_routes.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 ipv6 route vrf {}-cust1 json'.format(router.name), expected) _, result = topotest.run_and_expect(test_func, None, count=160, wait=0.5) assertmsg = '"{}" JSON output mismatches'.format(router.name) assert result is None, assertmsg
def expect_loopback_route(router, iptype, route, proto): "Wait until route is present on RIB for protocol." logger.info('waiting route {} in {}'.format(route, router)) test_func = partial( topotest.router_json_cmp, tgen.gears[router], 'show {} route json'.format(iptype), { route: [{ 'protocol': proto }] } ) _, result = topotest.run_and_expect(test_func, None, count=130, wait=1) assertmsg = '"{}" OSPF convergence failure'.format(router) assert result is None, assertmsg
def expect_neighbor_down(router, interface, peer): "Wait until peer is present on interface." logger.info("waiting peer {} in {} to disappear".format( peer, interface)) test_func = partial(topotest.router_json_cmp, tgen.gears[router], "show ip pim neighbor json", {interface: { peer: None }}) _, result = topotest.run_and_expect(test_func, None, count=4, wait=1) assertmsg = '"{}" PIM convergence failure'.format(router) assert result is None, assertmsg
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 test_ospf_json(): "Test 'show ip ospf json' output for coherency." tgen = get_topogen() if tgen.routers_have_failure(): pytest.skip('skipped because of router(s) failure') for rname, router in tgen.routers().iteritems(): logger.info('Comparing router "%s" "show ip ospf vrf %s-cust1 json" output', router.name, router.name) expected = { '{}-cust1'.format(router.name) : { 'vrfName': '{}-cust1'.format(router.name), 'routerId': '10.0.255.{}'.format(rname[1:]), 'tosRoutesOnly': True, 'rfc2328Conform': True, 'spfScheduleDelayMsecs': 0, 'holdtimeMinMsecs': 50, 'holdtimeMaxMsecs': 5000, 'lsaMinIntervalMsecs': 5000, 'lsaMinArrivalMsecs': 1000, 'writeMultiplier': 20, 'refreshTimerMsecs': 10000, 'asbrRouter': 'injectingExternalRoutingInformation', 'attachedAreaCounter': 1, 'areas': {} } } # Area specific additional checks if router.name == 'r1' or router.name == 'r2' or router.name == 'r3': expected['{}-cust1'.format(router.name)]['areas']['0.0.0.0'] = { 'areaIfActiveCounter': 2, 'areaIfTotalCounter': 2, 'authentication': 'authenticationNone', 'backbone': True, 'lsaAsbrNumber': 0, 'lsaNetworkNumber': 1, 'lsaNssaNumber': 0, 'lsaNumber': 4, 'lsaOpaqueAreaNumber': 0, 'lsaOpaqueLinkNumber': 0, 'lsaRouterNumber': 3, 'lsaSummaryNumber': 0, 'nbrFullAdjacentCounter': 2, } test_func = partial(topotest.router_json_cmp, router, 'show ip ospf vrf {0}-cust1 json'.format(rname), expected) _, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assertmsg = '"{}" JSON output mismatches'.format(rname) assert diff is None, assertmsg
def expect_ospf6_route_types(router, expected_summary): "Expect the correct route types." logger.info("waiting OSPFv3 router '{}'".format(router)) test_func = partial( topotest.router_json_cmp, tgen.gears[router], "show ipv6 ospf6 route summary json", expected_summary, ) _, result = topotest.run_and_expect(test_func, None, count=10, wait=1) assertmsg = '"{}" convergence failure'.format(router) assert result is None, assertmsg
def test_ospf_json(): "Test 'show ip ospf json' output for coherency." tgen = get_topogen() if tgen.routers_have_failure(): pytest.skip('skipped because of router(s) failure') for rname, router in tgen.routers().iteritems(): logger.info( 'Comparing router "%s" "show ip ospf vrf %s-cust1 json" output', router.name, router.name) expected = { '{}-cust1'.format(router.name): { 'vrfName': '{}-cust1'.format(router.name), 'routerId': '10.0.255.{}'.format(rname[1:]), 'tosRoutesOnly': True, 'rfc2328Conform': True, 'spfScheduleDelayMsecs': 0, 'holdtimeMinMsecs': 50, 'holdtimeMaxMsecs': 5000, 'lsaMinIntervalMsecs': 5000, 'lsaMinArrivalMsecs': 1000, 'writeMultiplier': 20, 'refreshTimerMsecs': 10000, 'asbrRouter': 'injectingExternalRoutingInformation', 'attachedAreaCounter': 1, 'areas': {} } } # Area specific additional checks if router.name == 'r1' or router.name == 'r2' or router.name == 'r3': expected['{}-cust1'.format(router.name)]['areas']['0.0.0.0'] = { 'areaIfActiveCounter': 2, 'areaIfTotalCounter': 2, 'authentication': 'authenticationNone', 'backbone': True, 'lsaAsbrNumber': 0, 'lsaNetworkNumber': 1, 'lsaNssaNumber': 0, 'lsaNumber': 4, 'lsaOpaqueAreaNumber': 0, 'lsaOpaqueLinkNumber': 0, 'lsaRouterNumber': 3, 'lsaSummaryNumber': 0, 'nbrFullAdjacentCounter': 2, } test_func = partial(topotest.router_json_cmp, router, 'show ip ospf vrf {0}-cust1 json'.format(rname), expected) _, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assertmsg = '"{}" JSON output mismatches'.format(rname) assert diff is None, assertmsg
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 vrf {0}-cust1 neighbor json".format(router), {"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
def expect_route(router_name, routes_expected): "Helper function to avoid repeated code." tgen = get_topogen() test_func = functools.partial( topotest.router_json_cmp, tgen.gears[router_name], "show ip route json", routes_expected, ) _, result = topotest.run_and_expect(test_func, None, count=120, wait=1) assertmsg = '"{}" BGP convergence failure'.format(router_name) assert result is None, assertmsg
def run_one_setup(r1, s): "Run one ecmp config" # Extract params expected_installed = s["expect_in"] expected_removed = s["expect_rem"] retries = s["retries"] wait = s["wait"] for d in expected_installed["routes"]: if d["type"] == "sharp": count = d["rib"] break logger.info("Testing {} routes X {} ecmp".format(count, s["ecmp"])) r1.vtysh_cmd( "sharp install route 1.0.0.0 \ nexthop-group {} {}".format(s["nhg"], count), isjson=False, ) test_func = partial(topotest.router_json_cmp, r1, "show ip route summary json", expected_installed) success, result = topotest.run_and_expect(test_func, None, retries, wait) assert success, "Route scale test install failed:\n{}".format(result) output = r1.vtysh_cmd("sharp data route", isjson=False) logger.info("{} routes X {} ecmp installed".format(count, s["ecmp"])) logger.info(output) r1.vtysh_cmd("sharp remove route 1.0.0.0 {}".format(count), isjson=False) test_func = partial(topotest.router_json_cmp, r1, "show ip route summary json", expected_removed) success, result = topotest.run_and_expect(test_func, None, retries, wait) assert success, "Route scale test remove failed:\n{}".format(result) output = r1.vtysh_cmd("sharp data route", isjson=False) logger.info("{} routes x {} ecmp removed".format(count, s["ecmp"])) logger.info(output)
def test_bgp_delayopen_without(): "Optional test of BGP functionality and behaviour without DelayOpenTimer enabled to establish a reference for following tests" tgen = get_topogen() if tgen.routers_have_failure(): pytest.skip(tgen.errors) # part 1: no delay r1 <=> no delay r4 logger.info("Starting optional test of BGP functionality without DelayOpenTimer enabled to establish a reference for following tests") # 1.1 enable peering shutdown logger.info("Enable shutdown of peering between r1 and r4") tgen.net["r1"].cmd('vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.2 shutdown"') tgen.net["r4"].cmd('vtysh -c "conf t" -c "router bgp 65100" -c "neighbor 192.168.101.1 shutdown"') # 1.2 wait for peers to shut down (poll output) for router_num in [1, 4]: logger.info("Checking BGP summary after enabling shutdown of peering on r{}".format(router_num)) router = tgen.gears["r{}".format(router_num)] reffile = os.path.join(CWD, "r{}/bgp_delayopen_summary_shutdown.json".format(router_num)) expected = json.loads(open(reffile).read()) test_func = functools.partial(topotest.router_json_cmp, router, "show ip bgp summary json", expected) _, res = topotest.run_and_expect(test_func, None, count=3, wait=1) assertmsg = "BGP session on r{} did not shut down peer".format(router_num) assert res is None, assertmsg # 1.3 disable peering shutdown logger.info("Disable shutdown of peering between r1 and r4") tgen.net["r1"].cmd('vtysh -c "conf t" -c "router bgp 65000" -c "no neighbor 192.168.101.2 shutdown"') tgen.net["r4"].cmd('vtysh -c "conf t" -c "router bgp 65100" -c "no neighbor 192.168.101.1 shutdown"') # 1.4 wait for peers to establish connection (poll output) for router_num in [1, 4]: logger.info("Checking BGP summary after disabling shutdown of peering on r{}".format(router_num)) router = tgen.gears["r{}".format(router_num)] reffile = os.path.join(CWD, "r{}/bgp_delayopen_summary_established.json".format(router_num)) expected = json.loads(open(reffile).read()) test_func = functools.partial(topotest.router_json_cmp, router, "show ip bgp summary json", expected) _, res = topotest.run_and_expect(test_func, None, count=5, wait=1) assertmsg = "BGP session on r{} did not establish a connection with peer".format(router_num) assert res is None, assertmsg
def router_compare_json_output(rname, command, reference, tries): "Compare router JSON output" logger.info('Comparing router "%s" "%s" output', rname, command) tgen = get_topogen() filename = "{}/{}/{}".format(CWD, rname, reference) expected = json.loads(open(filename).read()) test_func = partial(topotest.router_json_cmp, tgen.gears[rname], command, expected) _, diff = topotest.run_and_expect(test_func, None, count=tries, wait=0.5) assertmsg = '"{}" JSON output mismatches the expected result'.format(rname) assert diff is None, assertmsg
def test_bgp_disable_norib_routes(): "Test Routes in Zebra and BGP with the 'bgp-norib' configuration" tgen = get_topogen() # Skip if previous fatal error condition is raised if tgen.routers_have_failure(): pytest.skip(tgen.errors) # Checking local BGP routes - they need to be gone from Zebra logger.info( "Checking Zebra routes after removing bgp shutdown on router r1") router = tgen.gears["r1"] reffile = os.path.join(CWD, "r1/ip_route.json") expected = json.loads(open(reffile).read()) test_func = functools.partial(topotest.router_json_cmp, router, "show ip route json", expected) _, res = topotest.run_and_expect(test_func, None, count=30, wait=2) assertmsg = "Zebra IPv4 Routes wrong after removing the 'bgp no-rib'" assert res is None, assertmsg # Check BGP Summary on local and remote routers for rtrNum in [1, 2, 4]: logger.info( "Checking BGP Summary after removing the 'bgp no-rib' on router r1 on router r{}" .format(rtrNum)) router = tgen.gears["r{}".format(rtrNum)] reffile = os.path.join(CWD, "r{}/bgp_summary.json".format(rtrNum)) expected = json.loads(open(reffile).read()) test_func = functools.partial(topotest.router_json_cmp, router, "show ip bgp summary json", expected) _, res = topotest.run_and_expect(test_func, None, count=30, wait=2) assertmsg = "BGP sessions on router R{} has incorrect routes after removing 'bgp no-rib on r1'".format( rtrNum) assert res is None, assertmsg
def test_pim_rp_sees_stream(): "Ensure that the RP sees the stream and has acted accordingly" tgen = get_topogen() rp = tgen.gears["rp"] json_file = "{}/{}/upstream.json".format(CWD, rp.name) expected = json.loads(open(json_file).read()) test_func = partial(topotest.router_json_cmp, rp, "show ip pim upstream json", expected) _, result = topotest.run_and_expect(test_func, None, count=20, wait=0.5) assertmsg = '"{}" JSON output mismatches'.format(rp.name) assert result is None, assertmsg
def check_ping(name, dest_addr, expect_connected): def _check(name, dest_addr, match): tgen = get_topogen() output = tgen.gears[name].run("ping {} -c 1 -w 1".format(dest_addr)) logger.info(output) assert match in output, "ping fail" match = "{} packet loss".format("0%" if expect_connected else "100%") logger.info("[+] check {} {} {}".format(name, dest_addr, match)) tgen = get_topogen() func = functools.partial(_check, name, dest_addr, match) success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed"
def test_bgp_as_wide_bgp_identifier(): tgen = get_topogen() if tgen.routers_have_failure(): pytest.skip(tgen.errors) def _bgp_converge(router): output = json.loads( router.vtysh_cmd("show ip bgp neighbor 192.168.255.1 json")) expected = {"192.168.255.1": {"bgpState": "Established"}} return topotest.json_cmp(output, expected) def _bgp_failed(router): output = json.loads( router.vtysh_cmd("show ip bgp neighbor 192.168.255.1 json")) expected = { "192.168.255.1": { "lastNotificationReason": "OPEN Message Error/Bad BGP Identifier" } } return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, tgen.gears["r1"]) success, result = topotest.run_and_expect(test_func, None, count=260, wait=0.5) assert result is None, 'Failed to converge: "{}"'.format(tgen.gears["r1"]) test_func = functools.partial(_bgp_failed, tgen.gears["r3"]) success, result = topotest.run_and_expect(test_func, None, count=260, wait=0.5) assert result is None, 'Bad BGP Identifier notification not sent: "{}"'.format( tgen.gears["r3"])
def expect_bfd_peer_settings(router, settings): "Expect the following BFD configuration" logger.info("Verifying BFD peer {} in {}".format( settings["peer"], router)) test_func = partial( topotest.router_json_cmp, tgen.gears[router], "show bfd peers json", [settings], ) _, result = topotest.run_and_expect(test_func, None, count=4, wait=1) assertmsg = '"{}" BFD convergence failure'.format(router) assert result is None, assertmsg
def router_compare_json_output(rname, command, reference): "Compare router JSON output" logger.info('Comparing router "%s" "%s" output', rname, command) tgen = get_topogen() expected = json.loads(reference) # 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=120, wait=0.5) assertmsg = '"{}" JSON output mismatches the expected result'.format(rname) assert diff is None, assertmsg
def expect_bfd_configuration(router): "Load JSON file and compare with 'show bfd peer json'" logger.info('waiting BFD configuration on router {}'.format(router)) bfd_config = json.loads(open('{}/{}/bfd-peers.json'.format(CWD, router)).read()) test_func = partial( topotest.router_json_cmp, tgen.gears[router], 'show bfd peers json', bfd_config ) _, result = topotest.run_and_expect(test_func, None, count=130, wait=1) assertmsg = '"{}" BFD configuration failure'.format(router) assert result is None, assertmsg
def test_bgp_aggregator_zero(): tgen = get_topogen() if tgen.routers_have_failure(): pytest.skip(tgen.errors) def _bgp_converge(): output = json.loads( tgen.gears["r1"].vtysh_cmd("show ip bgp neighbor 10.0.0.2 json")) expected = { "10.0.0.2": { "bgpState": "Established", "addressFamilyInfo": { "ipv4Unicast": { "acceptedPrefixCounter": 1 } }, } } return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge) success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "More than one prefix seen at r1, SHOULD be only one." def _bgp_has_correct_routes_without_asn_0(): output = json.loads(tgen.gears["r1"].vtysh_cmd("show ip bgp json")) expected = {"routes": {"192.168.100.101/32": [{"valid": True}]}} return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_has_correct_routes_without_asn_0) success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed listing 192.168.100.101/32, SHOULD be accepted."
def test_ospf_kernel_route(): "Test OSPF Segment Routing MPLS route installation" tgen = get_topogen() if tgen.routers_have_failure(): pytest.skip(tgen.errors) logger.info("--- test OSPF Segment Routing MPLS tables ---") def show_mpls_table_json_cmp(rt, expected): """ Reformat MPLS table output to use a list of labels instead of dict. Original: { "X": { inLabel: "X", # ... } } List format: [ { inLabel: "X", } ] """ out = rt.vtysh_cmd("show mpls table json", isjson=True) outlist = [] for key in out.keys(): outlist.append(out[key]) return topotest.json_cmp(outlist, expected) for rnum in range(1, 5): router = "r{}".format(rnum) logger.info('\tRouter "%s"', router) # Load expected results from the command reffile = os.path.join(CWD, "{}/zebra_mpls.json".format(router)) expected = json.loads(open(reffile).read()) # Run test function until we get an result. Wait at most 60 seconds. rt = tgen.gears[router] test_func = partial(show_mpls_table_json_cmp, rt, expected) rv, diff = topotest.run_and_expect(test_func, None, count=25, wait=3) assert rv, "OSPF did not properly instal MPLS table on {}:\n{}".format( router, diff )
def test_bgp_aggregate_address_match_and_suppress(): "Test that the command matching-MED-only with suppression works." tgen = get_topogen() if tgen.routers_have_failure(): pytest.skip(tgen.errors) tgen.gears["r1"].vtysh_multicmd(""" configure terminal router bgp 65000 address-family ipv4 unicast no aggregate-address 192.168.0.0/24 matching-MED-only no aggregate-address 192.168.1.0/24 matching-MED-only aggregate-address 192.168.0.0/24 matching-MED-only summary-only aggregate-address 192.168.1.0/24 matching-MED-only summary-only """) routes_expected = { # All MED matches, aggregation must exist. "192.168.0.0/24": [{ "protocol": "bgp", "metric": 0 }], "192.168.0.1/32": None, "192.168.0.2/32": None, "192.168.0.3/32": None, # Non matching MED: aggregation must not exist. "192.168.1.0/24": None, "192.168.1.1/32": [{ "protocol": "bgp", "metric": 10 }], "192.168.1.2/32": [{ "protocol": "bgp", "metric": 10 }], "192.168.1.3/32": [{ "protocol": "bgp", "metric": 20 }], } test_func = functools.partial( topotest.router_json_cmp, tgen.gears["r2"], "show ip route json", routes_expected, ) _, result = topotest.run_and_expect(test_func, None, count=120, wait=1) assertmsg = '"r2" BGP convergence failure' assert result is None, assertmsg
def test_evpn_uplink_tracking(): ''' 1. Wait for access ports to come out of startup-delay 2. disable uplinks and check if access ports have been protodowned 3. enable uplinks and check if access ports have been moved out of protodown ''' tgen = get_topogen() dut_name = "torm11" dut = tgen.gears[dut_name] # wait for protodown rc to clear after startup test_fn = partial(check_protodown_rc, dut, None) _, result = topotest.run_and_expect(test_fn, None, count=20, wait=3) assertmsg = '"{}" protodown rc incorrect'.format(dut_name) assert result is None, assertmsg # disable the uplinks dut.run("ip link set %s-eth0 down" % dut_name) dut.run("ip link set %s-eth1 down" % dut_name) # check if the access ports have been protodowned test_fn = partial(check_protodown_rc, dut, "uplinkDown") _, result = topotest.run_and_expect(test_fn, None, count=20, wait=3) assertmsg = '"{}" protodown rc incorrect'.format(dut_name) assert result is None, assertmsg # enable the uplinks dut.run("ip link set %s-eth0 up" % dut_name) dut.run("ip link set %s-eth1 up" % dut_name) # check if the access ports have been moved out of protodown test_fn = partial(check_protodown_rc, dut, None) _, result = topotest.run_and_expect(test_fn, None, count=20, wait=3) assertmsg = '"{}" protodown rc incorrect'.format(dut_name) assert result is None, assertmsg
def test_r1_receive_and_advertise_prefix_sid_type1(): tgen = get_topogen() router = tgen.gears["r1"] def _check_type1_r1(router, prefix, remoteLabel, labelIndex): output = router.vtysh_cmd( "show bgp ipv4 labeled-unicast {} json".format(prefix)) output = json.loads(output) expected = { "prefix": prefix, "advertisedTo": { "10.0.0.101": {}, "10.0.0.102": {} }, "paths": [{ "valid": True, "remoteLabel": remoteLabel, "labelIndex": labelIndex, }], } return topotest.json_cmp(output, expected) test_func = functools.partial(_check_type1_r1, router, "3.0.0.1/32", 800001, 1) success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert result is None, 'Failed _check_type1_r1 in "{}"'.format(router) test_func = functools.partial(_check_type1_r1, router, "3.0.0.2/32", 800002, 2) success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert result is None, 'Failed _check_type1_r1 in "{}"'.format(router)
def test_vrf_pimreg_interfaces(): "Adding PIM RP in VRF information and verify pimreg interfaces" tgen = get_topogen() r1 = tgen.gears["r1"] r1.vtysh_cmd("conf\ninterface blue\nip pim") r1.vtysh_cmd( "conf\nvrf blue\nip pim rp 192.168.0.11 239.100.0.1/32\nexit-vrf") # Check pimreg11 interface on R1, VRF blue reffile = os.path.join(CWD, "r1/pim_blue_pimreg11.json") expected = json.loads(open(reffile).read()) test_func = functools.partial( topotest.router_json_cmp, r1, "show ip pim vrf blue inter pimreg11 json", expected, ) _, res = topotest.run_and_expect(test_func, None, count=5, wait=2) assertmsg = "PIM router R1, VRF blue (table 11) pimreg11 interface missing or incorrect status" assert res is None, assertmsg r1.vtysh_cmd("conf\ninterface red\nip pim") r1.vtysh_cmd( "conf\nvrf red\nip pim rp 192.168.0.12 239.100.0.1/32\nexit-vrf") # Check pimreg12 interface on R1, VRF red reffile = os.path.join(CWD, "r1/pim_red_pimreg12.json") expected = json.loads(open(reffile).read()) test_func = functools.partial( topotest.router_json_cmp, r1, "show ip pim vrf red inter pimreg12 json", expected, ) _, res = topotest.run_and_expect(test_func, None, count=5, wait=2) assertmsg = "PIM router R1, VRF red (table 12) pimreg12 interface missing or incorrect status" assert res is None, assertmsg
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 isis 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 check_rib(name, cmd, expected_file): def _check(name, cmd, expected_file): logger.info("polling") tgen = get_topogen() router = tgen.gears[name] output = json.loads(router.vtysh_cmd(cmd)) expected = open_json_file("{}/{}".format(CWD, expected_file)) return topotest.json_cmp(output, expected) logger.info('[+] check {} "{}" {}'.format(name, cmd, expected_file)) tgen = get_topogen() func = functools.partial(_check, name, cmd, expected_file) success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed"
def cmp_json_output(rname, command, reference, exact=False): "Compare router JSON output" logger.info('Comparing router "%s" "%s" output', rname, command) tgen = get_topogen() filename = "{}/{}/{}".format(CWD, rname, reference) expected = json.loads(open(filename).read()) # Run test function until we get an result. Wait at most 60 seconds. test_func = partial(compare_json_test, tgen.gears[rname], command, expected, exact) _, diff = topotest.run_and_expect(test_func, None, count=120, wait=0.5) assertmsg = '"{}" JSON output mismatches the expected result'.format(rname) assert diff is None, assertmsg
def test_bgp_aggregate_address_matching_med_only(): "Test that the command matching-MED-only works." tgen = get_topogen() if tgen.routers_have_failure(): pytest.skip(tgen.errors) routes_expected = { # All MED matches, aggregation must exist. "192.168.0.0/24": [{ "protocol": "bgp", "metric": 0 }], "192.168.0.1/32": [{ "protocol": "bgp", "metric": 10 }], "192.168.0.2/32": [{ "protocol": "bgp", "metric": 10 }], "192.168.0.3/32": [{ "protocol": "bgp", "metric": 10 }], # Non matching MED: aggregation must not exist. "192.168.1.0/24": None, "192.168.1.1/32": [{ "protocol": "bgp", "metric": 10 }], "192.168.1.2/32": [{ "protocol": "bgp", "metric": 10 }], "192.168.1.3/32": [{ "protocol": "bgp", "metric": 20 }], } test_func = functools.partial( topotest.router_json_cmp, tgen.gears["r2"], "show ip route json", routes_expected, ) _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) assertmsg = '"r2" BGP convergence failure' assert result is None, assertmsg
def router_compare_json_output(rname, command, reference): "Compare router JSON output" logger.info('Comparing router "%s" "%s" output', rname, command) tgen = get_topogen() filename = '{}/{}/{}'.format(CWD, rname, reference) expected = json.loads(open(filename).read()) # Run test function until we get an result. Wait at most 80 seconds. test_func = partial(topotest.router_json_cmp, tgen.gears[rname], command, expected) _, diff = topotest.run_and_expect(test_func, None, count=160, wait=0.5) assertmsg = '"{}" JSON output mismatches the expected result'.format(rname) assert diff is None, assertmsg
def test_bgp_fast_convergence(): "Assert that BGP is converging before setting a link down." tgen = get_topogen() if tgen.routers_have_failure(): pytest.skip(tgen.errors) logger.info('waiting for bgp peers converge') for router in tgen.routers().values(): ref_file = '{}/{}/bgp_prefixes.json'.format(CWD, router.name) expected = json.loads(open(ref_file).read()) test_func = partial(topotest.router_json_cmp, router, 'show ip bgp vrf {}-cust1 json'.format(router.name), expected) _, res = topotest.run_and_expect(test_func, None, count=40, wait=0.5) assertmsg = '{}: bgp did not converge'.format(router.name) assert res is None, assertmsg
def test_bgp_convergence(): "Assert that BGP is converging." tgen = get_topogen() if tgen.routers_have_failure(): pytest.skip(tgen.errors) logger.info('waiting for bgp peers to go up') for router in tgen.routers().values(): ref_file = '{}/{}/bgp_summary.json'.format(CWD, router.name) expected = json.loads(open(ref_file).read()) test_func = partial(topotest.router_json_cmp, router, 'show ip bgp summary json', expected) _, res = topotest.run_and_expect(test_func, None, count=125, wait=1.0) assertmsg = '{}: bgp did not converge'.format(router.name) assert res is None, assertmsg
def test_bfd_connection(): "Assert that the BFD peers can find themselves." tgen = get_topogen() if tgen.routers_have_failure(): pytest.skip(tgen.errors) logger.info('waiting for bfd peers to go up') for router in tgen.routers().values(): json_file = '{}/{}/peers.json'.format(CWD, router.name) expected = json.loads(open(json_file).read()) test_func = partial(topotest.router_json_cmp, router, 'show bfd peers json', expected) _, result = topotest.run_and_expect(test_func, None, count=8, wait=0.5) assertmsg = '"{}" JSON output mismatches'.format(router.name) assert result is None, assertmsg
def test_ospf_kernel_route(): "Test OSPF kernel route installation" tgen = get_topogen() if tgen.routers_have_failure(): pytest.skip('skipped because of router(s) failure') rlist = tgen.routers().values() for router in rlist: logger.info('Checking OSPF IPv4 kernel routes in "%s"', router.name) reffile = os.path.join(CWD, '{}/zebraroute.txt'.format(router.name)) expected = open(reffile).read() # Run test function until we get an result. Wait at most 60 seconds. test_func = partial(compare_show_ip_route_vrf, router.name, expected) result, diff = topotest.run_and_expect(test_func, '', count=140, wait=0.5) assertmsg = 'OSPF IPv4 route mismatch in router "{}": {}'.format( router.name, diff) assert result, assertmsg
def test_lm_proxy(): logger.info('Test: label manager (LDP and BGP)') tgen = get_topogen() # Skip if previous fatal error condition is raised if tgen.routers_have_failure(): pytest.skip(tgen.errors) cmd = 'show mpls ldp binding' router = tgen.gears['p1'] def check_labels(router, cmd): output = router.vtysh_cmd(cmd, isjson=False) logger.info('chk_labels [' + cmd + ']: ' + output) return output.count('\n') test_func = partial(check_labels, router, cmd) result, diff = topotest.run_and_expect(test_func, 12, count=6, wait=30) assert result, 'wrong labels'
def test_ospf_convergence(): "Test OSPF daemon convergence" tgen = get_topogen() if tgen.routers_have_failure(): pytest.skip('skipped because of router(s) failure') for rname, router in tgen.routers().iteritems(): logger.info('Waiting for router "%s" convergence', rname) # Load expected results from the command reffile = os.path.join(CWD, '{}/ospfroute.txt'.format(rname)) expected = open(reffile).read() # Run test function until we get an result. Wait at most 60 seconds. test_func = partial(topotest.router_output_cmp, router, 'show ip ospf vrf {0}-cust1 route'.format(rname), expected) result, diff = topotest.run_and_expect(test_func, '', count=160, wait=0.5) assertmsg = 'OSPF did not converge on {}:\n{}'.format(rname, diff) assert result, assertmsg
def test_bfd_fast_convergence(): """ Assert that BFD notices the link down after simulating network failure. """ tgen = get_topogen() if tgen.routers_have_failure(): pytest.skip(tgen.errors) # Disable r2-eth0 link router2 = tgen.gears['r2'] topotest.interface_set_status(router2, 'r2-eth0', ifaceaction=False, vrf_name='r2-cust1') # Wait the minimum time we can before checking that BGP/BFD # converged. logger.info('waiting for BFD converge') # Check that BGP converged quickly. for router in tgen.routers().values(): json_file = '{}/{}/peers.json'.format(CWD, router.name) expected = json.loads(open(json_file).read()) # Load the same file as previous test, but expect R1 to be down. if router.name == 'r1': for peer in expected: if peer['peer'] == '192.168.0.2': peer['status'] = 'down' else: for peer in expected: if peer['peer'] == '192.168.0.1': peer['status'] = 'down' test_func = partial(topotest.router_json_cmp, router, 'show bfd peers json', expected) _, res = topotest.run_and_expect(test_func, None, count=20, wait=0.5) assertmsg = '"{}" JSON output mismatches'.format(router.name) assert res is None, assertmsg
def test_ospf_kernel_route(): "Test OSPF Segment Routing MPLS route installation" tgen = get_topogen() if tgen.routers_have_failure(): pytest.skip(tgen.errors) logger.info('--- test OSPF Segment Routing MPLS tables ---') for rnum in range(1, 5): router = 'r{}'.format(rnum) logger.info('\tRouter "%s"', router) # Load expected results from the command reffile = os.path.join(CWD, '{}/zebra_mpls.json'.format(router)) expected = open(reffile).read() # Run test function until we get an result. Wait at most 60 seconds. test_func = partial(compare_mpls_table, router, expected) result, diff = topotest.run_and_expect(test_func, '', count=25, wait=3) assert result, ( 'OSPF did not properly instal MPLS table on {}:\n{}' ).format(router, diff)
def test_bgp_vrf_netns(): tgen = get_topogen() # Skip if previous fatal error condition is raised if tgen.routers_have_failure(): pytest.skip(tgen.errors) expect = { 'routerId': '10.0.1.1', 'routes': { }, } for subnet in range(0, 10): netkey = '10.201.{}.0/24'.format(subnet) expect['routes'][netkey] = [] peer = {'valid': True} expect['routes'][netkey].append(peer) test_func = functools.partial(topotest.router_json_cmp, tgen.gears['r1'], 'show ip bgp vrf r1-cust1 ipv4 json', expect) _, res = topotest.run_and_expect(test_func, None, count=12, wait=0.5) assertmsg = 'expected routes in "show ip bgp vrf r1-cust1 ipv4" output' assert res is None, assertmsg
def test_ospf_sr(): "Test OSPF daemon Segment Routing" tgen = get_topogen() if tgen.routers_have_failure(): pytest.skip(tgen.errors) logger.info('--- test OSPF Segment Routing Data Base ---') for rnum in range(1, 5): router = 'r{}'.format(rnum) logger.info('\tRouter "%s"', router) # Load expected results from the command reffile = os.path.join(CWD, '{}/ospf_srdb.json'.format(router)) expected = open(reffile).read() # Run test function until we get an result. Wait at most 60 seconds. test_func = partial(compare_ospf_srdb, router, expected) result, diff = topotest.run_and_expect(test_func, '', count=25, wait=3) assert result, ( 'OSPF did not start Segment Routing on {}:\n{}' ).format(router, diff)
def test_bgp_convergence(): "Test for BGP topology convergence" tgen = get_topogen() # Skip if previous fatal error condition is raised if tgen.routers_have_failure(): pytest.skip(tgen.errors) # Expected result router = tgen.gears['r1'] if router.has_version('<', '3.0'): reffile = os.path.join(CWD, 'r1/summary20.txt') else: reffile = os.path.join(CWD, 'r1/summary.txt') expected = json.loads(open(reffile).read()) def _output_summary_cmp(router, cmd, data): """ Runs `cmd` that returns JSON data (normally the command ends with 'json') and compare with `data` contents. """ output = router.vtysh_cmd(cmd, isjson=True) if 'ipv4Unicast' in output: output['ipv4Unicast']['vrfName'] = \ output['ipv4Unicast']['vrfName'].replace( 'default', 'Default') elif 'vrfName' in output: output['vrfName'] = output['vrfName'].replace('default', 'Default') return topotest.json_cmp(output, data) test_func = functools.partial( _output_summary_cmp, router, 'show ip bgp summary json', expected) _, res = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assertmsg = 'BGP router network did not converge' assert res is None, assertmsg