Example #1
0
    def report_memory_leaks(self, filename_prefix, testscript):
        "Report Memory Leaks to file prefixed with given string"

        leakfound = False
        filename = filename_prefix + re.sub(r"\.py", "", testscript) + ".txt"
        for daemon in self.daemons:
            if (self.daemons[daemon] == 1):
                log = self.getStdErr(daemon)
                if "memstats" in log:
                    # Found memory leak
                    logger.info('\nRouter {} {} StdErr Log:\n{}'.format(
                        self.name, daemon, log))
                    if not leakfound:
                        leakfound = True
                        # Check if file already exists
                        fileexists = os.path.isfile(filename)
                        leakfile = open(filename, "a")
                        if not fileexists:
                            # New file - add header
                            leakfile.write("# Memory Leak Detection for topotest %s\n\n" % testscript)
                        leakfile.write("## Router %s\n" % self.name)
                    leakfile.write("### Process %s\n" % daemon)
                    log = re.sub("core_handler: ", "", log)
                    log = re.sub(r"(showing active allocations in memory group [a-zA-Z0-9]+)", r"\n#### \1\n", log)
                    log = re.sub("memstats:  ", "    ", log)
                    leakfile.write(log)
                    leakfile.write("\n")
        if leakfound:
            leakfile.close()
Example #2
0
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
Example #3
0
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
Example #4
0
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
Example #5
0
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
Example #6
0
def setup_module(mod):
    "Sets up the pytest environment"
    tgen = Topogen(ISISTopo1, mod.__name__)
    tgen.start_topology()

    # For all registered routers, load the zebra configuration file
    for rname, router in tgen.routers().iteritems():
        router.load_config(
            TopoRouter.RD_ZEBRA,
            os.path.join(CWD, '{}/zebra.conf'.format(rname))
        )
        router.load_config(
            TopoRouter.RD_ISIS,
            os.path.join(CWD, '{}/isisd.conf'.format(rname))
        )

    # After loading the configurations, this function loads configured daemons.
    tgen.start_router()

    has_version_20 = False
    for router in tgen.routers().values():
        if router.has_version('<', '3'):
            has_version_20 = True

    if has_version_20:
        logger.info('Skipping ISIS tests for FRR 2.0')
        tgen.set_error('ISIS has convergence problems with IPv6')
Example #7
0
    def checkRouterVersion(self, cmpop, version):
        """
        Compares router version using operation `cmpop` with `version`.
        Valid `cmpop` values:
        * `>=`: has the same version or greater
        * '>': has greater version
        * '=': has the same version
        * '<': has a lesser version
        * '<=': has the same version or lesser

        Usage example: router.checkRouterVersion('>', '1.0')
        """

        # Make sure we have version information first
        if self.version == None:
            self.version = self.cmd(os.path.join(self.daemondir, 'bgpd')+' -v').split()[2]
            logger.info('{}: running version: {}'.format(self.name,self.version))

        rversion = self.version
        if rversion is None:
            return False

        result = version_cmp(rversion, version)
        if cmpop == '>=':
            return result >= 0
        if cmpop == '>':
            return result > 0
        if cmpop == '=':
            return result == 0
        if cmpop == '<':
            return result < 0
        if cmpop == '<':
            return result < 0
        if cmpop == '<=':
            return result <= 0
Example #8
0
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
Example #9
0
def teardown_module(mod):
    "Teardown the pytest environment"

    tgen = get_topogen()
    tgen.stop_topology()

    logger.info('\n\n---- OSPF Segment Routing tests End ----\n')
Example #10
0
 def loadConf(self, daemon, source=None, param=None):
     # print "Daemons before:", self.daemons
     if daemon in self.daemons.keys():
         self.daemons[daemon] = 1
         if param is not None:
             self.daemons_options[daemon] = param
         if source is None:
             self.cmd('touch /etc/%s/%s.conf' % (self.routertype, daemon))
             self.waitOutput()
         else:
             self.cmd('cp %s /etc/%s/%s.conf' % (source, self.routertype, daemon))
             self.waitOutput()
         self.cmd('chmod 640 /etc/%s/%s.conf' % (self.routertype, daemon))
         self.waitOutput()
         self.cmd('chown %s:%s /etc/%s/%s.conf' % (self.routertype, self.routertype, self.routertype, daemon))
         self.waitOutput()
         if (daemon == 'zebra') and (self.daemons['staticd'] == 0):
             # Add staticd with zebra - if it exists
             staticd_path = os.path.join(self.daemondir, 'staticd')
             if os.path.isfile(staticd_path):
                 self.daemons['staticd'] = 1
                 self.daemons_options['staticd'] = ''
                 # Auto-Started staticd has no config, so it will read from zebra config
     else:
         logger.info('No daemon {} known'.format(daemon))
Example #11
0
    def _init_topo(self, cls):
        """
        Initialize the topogily provided by the user. The user topology class
        must call get_topogen() during build() to get the topogen object.
        """
        # Set the global variable so the test cases can access it anywhere
        set_topogen(self)

        # Test for MPLS Kernel modules available
        self.hasmpls = False
        if not topotest.module_present('mpls-router'):
            logger.info('MPLS tests will not run (missing mpls-router kernel module)')
        elif not topotest.module_present('mpls-iptunnel'):
            logger.info('MPLS tests will not run (missing mpls-iptunnel kernel module)')
        else:
            self.hasmpls = True
        # Load the default topology configurations
        self._load_config()

        # Initialize the API
        self._mininet_reset()
        cls()
        self.net = Mininet(controller=None, topo=self.topo)
        for gear in self.gears.values():
            gear.net = self.net
Example #12
0
def setup_module(module):
    tgen = Topogen(BGPECMPTopo1, module.__name__)
    tgen.start_topology()

    # Starting Routers
    router_list = tgen.routers()
    for rname, router in router_list.iteritems():
        router.load_config(
            TopoRouter.RD_ZEBRA,
            os.path.join(CWD, '{}/zebra.conf'.format(rname))
        )
        router.load_config(
            TopoRouter.RD_BGP,
            os.path.join(CWD, '{}/bgpd.conf'.format(rname))
        )
        router.start()

    # Starting Hosts and init ExaBGP on each of them
    topotest.sleep(10, 'starting BGP on all {} peers'.format(total_ebgp_peers))
    peer_list = tgen.exabgp_peers()
    for pname, peer in peer_list.iteritems():
        peer_dir = os.path.join(CWD, pname)
        env_file = os.path.join(CWD, 'exabgp.env')
        peer.start(peer_dir, env_file)
        logger.info(pname)
Example #13
0
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)
Example #14
0
def test_pim_send_mcast_stream():
    "Establish a Multicast stream from r2 -> r1 and then ensure S,G is created as appropriate"
    logger.info("Establish a Mcast stream from r2->r1 and then ensure S,G created")

    tgen = get_topogen()

    if tgen.routers_have_failure():
        pytest.skip(tgen.errors)

    r2 = tgen.gears['r2']
    r1 = tgen.gears['r1']

    # Let's establish a S,G stream from r2 -> r1
    CWD = os.path.dirname(os.path.realpath(__file__))
    r2.run("{}/mcast-tx.py --ttl 5 --count 5 --interval 10 229.1.1.1 r2-eth0 > /tmp/bar".format(CWD))

    # Let's see that it shows up and we have established some basic state
    out = r1.vtysh_cmd("show ip pim upstream json", isjson=True)
    expected = {
        '229.1.1.1': {
            '10.0.20.2': {
                'firstHopRouter': 1,
                'joinState': 'NotJoined',
                'regState': 'RegPrune',
                'inboundInterface': 'r1-eth0',
            }
        }
    }

    assert topotest.json_cmp(out, expected) is None, 'failed to converge pim'
Example #15
0
def test_pim_igmp_report():
    "Send a igmp report from r2->r1 and ensure that the *,G state is created on r1"
    logger.info("Send a igmp report from r2-r1 and ensure *,G created")

    tgen = get_topogen()

    if tgen.routers_have_failure():
        pytest.skip(tgen.errors)

    r2 = tgen.gears['r2']
    r1 = tgen.gears['r1']

    # Let's send a igmp report from r2->r1
    CWD = os.path.dirname(os.path.realpath(__file__))
    r2.run("{}/mcast-rx.py 229.1.1.2 r2-eth0 &".format(CWD))

    out = r1.vtysh_cmd("show ip pim upstream json", isjson=True)
    expected = {
        '229.1.1.2': {
            '*': {
                'sourceIgmp': 1,
                'joinState': 'Joined',
                'regState': 'RegNoInfo',
                'sptBit': 0,
            }
        }
    }

    assert topotest.json_cmp(out, expected) is None, 'failed to converge pim'
Example #16
0
def setup_module(mod):
    "Sets up the pytest environment"

    logger.info('\n\n---- Starting OSPF Segment Routing tests ----\n')

    tgen = Topogen(OspfSrTopo, mod.__name__)
    tgen.start_topology()

    router_list = tgen.routers()

    for rname, router in router_list.iteritems():
        router.load_config(
            TopoRouter.RD_ZEBRA,
            os.path.join(CWD, '{}/zebra.conf'.format(rname))
        )
        router.load_config(
            TopoRouter.RD_OSPF,
            os.path.join(CWD, '{}/ospfd.conf'.format(rname))
        )

    # Initialize all routers.
    tgen.start_router()

    # Verify that version, MPLS and Segment Routing are OK
    for router in router_list.values():
        # Check for Version
        if router.has_version('<', '4'):
            tgen.set_error('Unsupported FRR version')
            break
        # Check that Segment Routing is available
        output = tgen.gears[router.name].vtysh_cmd(
            "show ip ospf database segment-routing json")
        if output.find("Unknown") != -1:
            tgen.set_error('Segment Routing is not available')
Example #17
0
def test_isis_route6_installation():
    "Check whether all expected routes are present"
    tgen = get_topogen()
    # Don't run this test if we have any failure.
    if tgen.routers_have_failure():
        pytest.skip(tgen.errors)

    logger.info('Checking routers for installed ISIS IPv6 routes')

    # Check for routes in 'show ip route json'
    for rname, router in tgen.routers().iteritems():
        filename = '{0}/{1}/{1}_route6.json'.format(CWD, rname)
        expected = json.loads(open(filename, 'r').read())
        actual = router.vtysh_cmd('show ipv6 route json', isjson=True)

        # Older FRR versions don't list interfaces in some ISIS routes
        if router.has_version('<', '3.1'):
            for network, routes in expected.iteritems():
                for route in routes:
                    # Older versions display different metrics for IPv6 routes
                    route.pop('metric', None)

                    if route['protocol'] != 'isis':
                        continue

                    for nexthop in route['nexthops']:
                        nexthop.pop('interfaceIndex', None)
                        nexthop.pop('interfaceName', None)

        assertmsg = "Router '{}' routes mismatch".format(rname)
        assert topotest.json_cmp(actual, expected) is None, assertmsg
Example #18
0
def test_ospf_convergence():
    logger.info("Test: check OSPF adjacencies")
    tgen = get_topogen()

    # Skip if previous fatal error condition is raised
    if tgen.routers_have_failure():
        pytest.skip(tgen.errors)

    # Old output (before FRR PR1383) didn't show a list of neighbors.
    # Check for dict object and compare to old output if this is the case
    tgen = get_topogen()
    router = tgen.gears['r1']
    output = router.vtysh_cmd("show ip ospf neighbor json", isjson=True)

    # We could have either old format (without "neighbors" and direct list
    # of IP's or new format from PR1659 with "neighbors".
    # Trying old formats first and fall back to new format
    #
    # New format: neighbors have dict instead of list of dicts (PR1723).
    if output.has_key('neighbors'):
        if isinstance(output['neighbors'], dict):
            reffile = "show_ip_ospf_neighbor.json"
        else:
            reffile = "show_ip_ospf_neighbor.ref"
    else:
        if isinstance(output["2.2.2.2"], dict):
            reffile = "show_ip_ospf_neighbor.ref-old-nolist"
        else:
            reffile = "show_ip_ospf_neighbor.ref-no-neigh"

    for rname in ['r1', 'r2', 'r3']:
        router_compare_json_output(rname, "show ip ospf neighbor json", reffile)
Example #19
0
def test_call_mininet_cli():
    "Dummy test that just calls mininet CLI so we can interact with the build."
    tgen = get_topogen()
    # Don't run this test if we have any failure.
    if tgen.routers_have_failure():
        pytest.skip(tgen.errors)

    logger.info('calling mininet CLI')
    tgen.mininet_cli()
Example #20
0
def ltemplatePreRouterStartHook():
    cc = ltemplateRtrCmd()
    tgen = get_topogen()
    logger.info('pre router-start hook')
    #check for normal init
    if len(tgen.net) == 1:
        logger.info('Topology not configured, skipping setup')
        return False
    return True
Example #21
0
def test_ldp_pseudowires():
    logger.info("Test: verify LDP pseudowires")
    tgen = get_topogen()

    # Skip if previous fatal error condition is raised
    if tgen.routers_have_failure():
        pytest.skip(tgen.errors)

    for rname in ['r1', 'r2', 'r3']:
        router_compare_json_output(rname, "show l2vpn atom vc json", "show_l2vpn_vc.ref")
Example #22
0
    def set_error(self, message, code=None):
        "Sets an error message and signal other tests to skip."
        logger.info(message)

        # If no code is defined use a sequential number
        if code is None:
            code = len(self.errorsd)

        self.errorsd[code] = message
        self.errors += '\n{}: {}'.format(code, message)
Example #23
0
def test_rib():
    logger.info("Test: verify RIB")
    tgen = get_topogen()

    # Skip if previous fatal error condition is raised
    if tgen.routers_have_failure():
        pytest.skip(tgen.errors)

    for rname in ['r1', 'r2', 'r3']:
        router_compare_json_output(rname, "show ip route json", "show_ip_route.ref")
Example #24
0
def test_ldp_bindings():
    logger.info("Test: verify LDP bindings")
    tgen = get_topogen()

    # Skip if previous fatal error condition is raised
    if tgen.routers_have_failure():
        pytest.skip(tgen.errors)

    for rname in ['r1', 'r2', 'r3']:
        router_compare_json_output(rname, "show mpls ldp binding json", "show_ldp_binding.ref")
Example #25
0
def sleep(amount, reason=None):
    """
    Sleep wrapper that registers in the log the amount of sleep
    """
    if reason is None:
        logger.info('Sleeping for {} seconds'.format(amount))
    else:
        logger.info(reason + ' ({} seconds)'.format(amount))

    time.sleep(amount)
Example #26
0
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
Example #27
0
def ltemplatePreRouterStartHook():
    cc = ltemplateRtrCmd()
    tgen = get_topogen()
    logger.info('pre router-start hook')
    #check for mpls
    if tgen.hasmpls != True:
        logger.info('MPLS not available, skipping setup')
        return False
    #check for normal init
    if len(tgen.net) == 1:
        logger.info('Topology not configured, skipping setup')
        return False
    #configure r2 mpls interfaces
    intfs = ['lo', 'r2-eth0', 'r2-eth1', 'r2-eth2']
    for intf in intfs:
        cc.doCmd(tgen, 'r2', 'echo 1 > /proc/sys/net/mpls/conf/{}/input'.format(intf))
    #configure MPLS
    rtrs = ['r1', 'r3', 'r4']
    cmds = ['echo 1 > /proc/sys/net/mpls/conf/lo/input']
    for rtr in rtrs:
        router = tgen.gears[rtr]
        for cmd in cmds:
            cc.doCmd(tgen, rtr, cmd)
        intfs = ['lo', rtr+'-eth0', rtr+'-eth4']
        for intf in intfs:
            cc.doCmd(tgen, rtr, 'echo 1 > /proc/sys/net/mpls/conf/{}/input'.format(intf))
    logger.info('setup mpls input')
    return True
Example #28
0
def vrf_setup(router, eth_in, vrf, vrf_table):
    cmds = ['ip link set dev lo up',
            'echo 10000 > /proc/sys/net/mpls/platform_labels',
            'ip link add dev ' + vrf +  ' type vrf table ' + vrf_table,
            'ip link set ' + vrf + ' up',
            'ip link set ' + eth_in + ' vrf ' + vrf,
            'echo 1 > /proc/sys/net/mpls/conf/' + vrf + '/input'
           ]
    vrf_destroy(router, vrf)
    for cmd in cmds:
        logger.info('[vrf_setup] cmd: ' + cmd)
        out = router.run(cmd)
        if out != None and len(out) > 0:
            logger.info('[vrf_setup] "{}" error: out="{}"'.format(cmd, out))
Example #29
0
def test_bgp_vrf_learn():
    "Test daemon learnt VRF context"
    tgen = get_topogen()

    # Skip if previous fatal error condition is raised
    if tgen.routers_have_failure():
        pytest.skip(tgen.errors)

    # Expected result
    output = tgen.gears['r1'].vtysh_cmd("show vrf", isjson=False)
    logger.info('output is: {}'.format(output))

    output = tgen.gears['r1'].vtysh_cmd("show bgp vrfs", isjson=False)
    logger.info('output is: {}'.format(output))
Example #30
0
def test_ldp_pseudowires_after_link_down():
    logger.info("Test: verify LDP pseudowires after r1-r2 link goes down")
    tgen = get_topogen()

    # Skip if previous fatal error condition is raised
    if tgen.routers_have_failure():
        pytest.skip(tgen.errors)

    # Shut down r1-r2 link */
    tgen = get_topogen()
    tgen.gears['r1'].peer_link_enable('r1-eth1', False)

    # check if the pseudowire is still up (using an alternate path for nexthop resolution)
    for rname in ['r1', 'r2', 'r3']:
        router_compare_json_output(rname, "show l2vpn atom vc json", "show_l2vpn_vc.ref")
Example #31
0
 def _check_srv6_locator(router, expected_locator_file):
     logger.info("checking zebra locator status")
     output = json.loads(
         router.vtysh_cmd("show segment-routing srv6 locator json"))
     expected = open_json_file("{}/{}".format(CWD, expected_locator_file))
     return topotest.json_cmp(output, expected)
Example #32
0
def setup_module(module):
    tgen = Topogen(BGPVRFNETNSTopo1, module.__name__)
    tgen.start_topology()

    # Get r1 reference
    router = tgen.gears["r1"]

    # check for zebra capability
    if CustomizeVrfWithNetns == True:
        if router.check_capability(TopoRouter.RD_ZEBRA,
                                   "--vrfwnetns") == False:
            return pytest.skip(
                "Skipping BGP VRF NETNS Test. VRF NETNS backend not available on FRR"
            )
        if os.system("ip netns list") != 0:
            return pytest.skip(
                "Skipping BGP VRF NETNS Test. NETNS not available on System")
    # retrieve VRF backend kind
    if CustomizeVrfWithNetns == True:
        logger.info("Testing with VRF Namespace support")

    # create VRF r1-cust1
    # move r1-eth0 to VRF r1-cust1
    cmds = [
        "if [ -e /var/run/netns/{0}-cust1 ] ; then ip netns del {0}-cust1 ; fi",
        "ip netns add {0}-cust1",
        "ip link set dev {0}-eth0 netns {0}-cust1",
        "ip netns exec {0}-cust1 ifconfig {0}-eth0 up",
    ]
    for cmd in cmds:
        cmd = cmd.format("r1")
        logger.info("cmd: " + cmd)
        output = router.run(cmd.format("r1"))
        if output != None and len(output) > 0:
            logger.info(
                'Aborting due to unexpected output: cmd="{}" output=\n{}'.
                format(cmd, output))
            return pytest.skip(
                "Skipping BGP VRF NETNS Test. Unexpected output to command: " +
                cmd)
    # run daemons
    router.load_config(
        TopoRouter.RD_ZEBRA,
        os.path.join(CWD, "{}/zebra.conf".format("r1")),
        "--vrfwnetns",
    )
    router.load_config(TopoRouter.RD_BGP,
                       os.path.join(CWD, "{}/bgpd.conf".format("r1")))

    logger.info("Launching BGP and ZEBRA")
    # BGP and ZEBRA start without underlying VRF
    router.start()
    # Starting Hosts and init ExaBGP on each of them
    logger.info("starting exaBGP on peer1")
    peer_list = tgen.exabgp_peers()
    for pname, peer in peer_list.items():
        peer_dir = os.path.join(CWD, pname)
        env_file = os.path.join(CWD, "exabgp.env")
        logger.info("Running ExaBGP peer")
        peer.start(peer_dir, env_file)
        logger.info(pname)
def test_bgp_flowspec():
    tgen = get_topogen()

    # Skip if previous fatal error condition is raised
    if tgen.routers_have_failure():
        pytest.skip(tgen.errors)

    router = tgen.gears["r1"]

    logger.info("Check BGP FS entry for 3.3.3.3 with redirect IP")
    output = router.vtysh_cmd(
        "show bgp ipv4 flowspec 3.3.3.3", isjson=False, daemon="bgpd"
    )
    logger.info(output)
    if (
        "NH 50.0.0.2" not in output
        or "FS:redirect IP" not in output
        or "Packet Length < 200" not in output
    ):
        assertmsg = "traffic to 3.3.3.3 should have been detected as FS entry. NOK"
        assert 0, assertmsg
    else:
        logger.info("Check BGP FS entry for 3.3.3.3 with redirect IP OK")

    logger.info("Check BGP FS entry for 3::3 with redirect IP")
    output = router.vtysh_cmd(
        "show bgp ipv6 flowspec 3::3", isjson=False, daemon="bgpd"
    )
    logger.info(output)
    if (
        "NH 50::2" not in output
        or "FS:redirect IP" not in output
        or "Packet Length < 200" not in output
    ):
        assertmsg = "traffic to 3::3 should have been detected as FS entry. NOK"
        assert 0, assertmsg
    else:
        logger.info("Check BGP FS entry for 3::3 with redirect IP OK")
Example #34
0
def diagnose_env_linux(rundir):
    """
    Run diagnostics in the running environment. Returns `True` when everything
    is ok, otherwise `False`.
    """
    ret = True

    # Load configuration
    config = configparser.ConfigParser(defaults=tgen_defaults)
    pytestini_path = os.path.join(CWD, "../pytest.ini")
    config.read(pytestini_path)

    # Test log path exists before installing handler.
    os.system("mkdir -p " + rundir)
    # Log diagnostics to file so it can be examined later.
    fhandler = logging.FileHandler(
        filename="{}/diagnostics.txt".format(rundir))
    fhandler.setLevel(logging.DEBUG)
    fhandler.setFormatter(logging.Formatter(fmt=topolog.FORMAT))
    logger.addHandler(fhandler)

    logger.info("Running environment diagnostics")

    # Assert that we are running as root
    if os.getuid() != 0:
        logger.error("you must run topotest as root")
        ret = False

    # Assert that we have mininet
    # if os.system("which mn >/dev/null 2>/dev/null") != 0:
    #     logger.error("could not find mininet binary (mininet is not installed)")
    #     ret = False

    # Assert that we have iproute installed
    if os.system("which ip >/dev/null 2>/dev/null") != 0:
        logger.error("could not find ip binary (iproute is not installed)")
        ret = False

    # Assert that we have gdb installed
    if os.system("which gdb >/dev/null 2>/dev/null") != 0:
        logger.error("could not find gdb binary (gdb is not installed)")
        ret = False

    # Assert that FRR utilities exist
    frrdir = config.get("topogen", "frrdir")
    if not os.path.isdir(frrdir):
        logger.error("could not find {} directory".format(frrdir))
        ret = False
    else:
        try:
            pwd.getpwnam("frr")[2]
        except KeyError:
            logger.warning('could not find "frr" user')

        try:
            grp.getgrnam("frr")[2]
        except KeyError:
            logger.warning('could not find "frr" group')

        try:
            if "frr" not in grp.getgrnam("frrvty").gr_mem:
                logger.error(
                    '"frr" user and group exist, but user is not under "frrvty"'
                )
        except KeyError:
            logger.warning('could not find "frrvty" group')

        for fname in [
                "zebra",
                "ospfd",
                "ospf6d",
                "bgpd",
                "ripd",
                "ripngd",
                "isisd",
                "pimd",
                "ldpd",
                "pbrd",
        ]:
            path = os.path.join(frrdir, fname)
            if not os.path.isfile(path):
                # LDPd is an exception
                if fname == "ldpd":
                    logger.info(
                        "could not find {} in {}".format(fname, frrdir) +
                        "(LDPd tests will not run)")
                    continue

                logger.warning("could not find {} in {}".format(fname, frrdir))
                ret = False
            else:
                if fname != "zebra":
                    continue

                os.system("{} -v 2>&1 >{}/frr_zebra.txt".format(path, rundir))

    # Test MPLS availability
    krel = platform.release()
    if topotest.version_cmp(krel, "4.5") < 0:
        logger.info(
            'LDPd tests will not run (have kernel "{}", but it requires 4.5)'.
            format(krel))

    # Test for MPLS Kernel modules available
    if not topotest.module_present("mpls-router", load=False) != 0:
        logger.info(
            "LDPd tests will not run (missing mpls-router kernel module)")
    if not topotest.module_present("mpls-iptunnel", load=False) != 0:
        logger.info(
            "LDPd tests will not run (missing mpls-iptunnel kernel module)")

    if not get_exabgp_cmd():
        logger.warning("Failed to find exabgp < 4")

    logger.removeHandler(fhandler)
    fhandler.close()

    return ret
Example #35
0
 def start_topology(self):
     """Starts the topology class."""
     logger.info("starting topology: {}".format(self.modname))
     self.net.start()
Example #36
0
def setup_module(mod):
    """
    Sets up the pytest environment.

    * `mod`: module name
    """
    global NEXT_HOPS, INTF_LIST_R3, INTF_LIST_R2, TEST_STATIC
    global ADDR_TYPES

    testsuite_run_time = time.asctime(time.localtime(time.time()))
    logger.info("Testsuite start time: {}".format(testsuite_run_time))
    logger.info("=" * 40)

    logger.info("Running setup_module to create topology")

    # This function initiates the topology build with Topogen...
    tgen = Topogen(CreateTopo, mod.__name__)

    # Starting topology, create tmp files which are loaded to routers
    #  to start deamons and then start routers
    start_topology(tgen)

    # Creating configuration from JSON
    build_config_from_json(tgen, topo)

    # Don't run this test if we have any failure.
    if tgen.routers_have_failure():
        pytest.skip(tgen.errors)

    # tgen.mininet_cli()
    # Api call verify whether BGP is converged
    ADDR_TYPES = check_address_types()

    for addr_type in ADDR_TYPES:
        BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
        assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error:" " {}".format(
            BGP_CONVERGENCE)

    link_data = [
        val for links, val in topo["routers"]["r2"]["links"].iteritems()
        if "r3" in links
    ]
    for adt in ADDR_TYPES:
        NEXT_HOPS[adt] = [val[adt].split("/")[0] for val in link_data]
        if adt == "ipv4":
            NEXT_HOPS[adt] = sorted(NEXT_HOPS[adt],
                                    key=lambda x: int(x.split(".")[2]))
        elif adt == "ipv6":
            NEXT_HOPS[adt] = sorted(NEXT_HOPS[adt],
                                    key=lambda x: int(x.split(":")[-3], 16))

    INTF_LIST_R2 = [val["interface"].split("/")[0] for val in link_data]
    INTF_LIST_R2 = sorted(INTF_LIST_R2, key=lambda x: int(x.split("eth")[1]))

    link_data = [
        val for links, val in topo["routers"]["r3"]["links"].iteritems()
        if "r2" in links
    ]
    INTF_LIST_R3 = [val["interface"].split("/")[0] for val in link_data]
    INTF_LIST_R3 = sorted(INTF_LIST_R3, key=lambda x: int(x.split("eth")[1]))

    # STATIC_ROUTE = True
    logger.info("Running setup_module() done")
Example #37
0
 def start(self):
     "Basic start function that just reports equipment start"
     logger.info('starting "{}"'.format(self.name))
Example #38
0
def test_bgp_remove_metric_rmaps():
    "Test removing route-maps with metric changes again"

    tgen = get_topogen()

    # Skip if previous fatal error condition is raised
    if tgen.routers_have_failure():
        pytest.skip(tgen.errors)

    logger.info("Test absolute metric")

    # Remove metric route-maps and relevant comfiguration

    tgen.net['r1'].cmd(
        'vtysh -c "conf t" -c "router bgp 65000" ' +
        '-c "address-family ipv4 unicast" ' +
        '-c "no neighbor 192.168.0.2 route-map addmetric-in in" ' +
        '-c "no neighbor 192.168.0.2 route-map addmetric-out out" ' +
        '-c "no neighbor 192.168.101.2 route-map setmetric-in in" ' +
        '-c "no neighbor 192.168.101.2 route-map setmetric-out out" ')
    tgen.net['r1'].cmd('vtysh -c "conf t" ' + '-c "no ip prefix-list net1" ' +
                       '-c "no ip prefix-list net2"')
    tgen.net['r1'].cmd('vtysh -c "conf t" ' +
                       '-c "no route-map setmetric-in" ')
    tgen.net['r1'].cmd('vtysh -c "conf t" ' +
                       '-c "no route-map setmetric-out" ')
    tgen.net['r1'].cmd('vtysh -c "conf t" ' +
                       '-c "no route-map addmetric-in" ')
    tgen.net['r1'].cmd('vtysh -c "conf t" ' +
                       '-c "no route-map addmetric-out" ')

    tgen.net['r2'].cmd(
        'vtysh -c "conf t" -c "router bgp 65000" ' +
        '-c "address-family ipv4 unicast" ' +
        '-c "no neighbor 192.168.0.1 route-map subtractmetric-in in" ' +
        '-c "no neighbor 192.168.0.1 route-map subtractmetric-out out" ' +
        '-c "no neighbor 192.168.201.2 route-map setmetric-in in" ' +
        '-c "no neighbor 192.168.201.2 route-map setmetric-out out" ')
    tgen.net['r2'].cmd('vtysh -c "conf t" ' + '-c "no ip prefix-list net1" ' +
                       '-c "no ip prefix-list net2" ')
    tgen.net['r2'].cmd('vtysh -c "conf t" ' +
                       '-c "no route-map setmetric-in" ')
    tgen.net['r2'].cmd('vtysh -c "conf t" ' +
                       '-c "no route-map setmetric-out" ')
    tgen.net['r2'].cmd('vtysh -c "conf t" ' +
                       '-c "no route-map addmetric-in" ')
    tgen.net['r2'].cmd('vtysh -c "conf t" ' +
                       '-c "no route-map addmetric-out" ')

    # Clear IN the bgp neighbors to make sure the route-maps are applied
    tgen.net['r1'].cmd('vtysh -c "clear ip bgp 192.168.0.2 in" ' +
                       '-c "clear ip bgp 192.168.101.2 in"')
    tgen.net['r2'].cmd('vtysh -c "clear ip bgp 192.168.0.1 in" ' +
                       '-c "clear ip bgp 192.168.201.2 in"')

    # tgen.mininet_cli()

    # Check BGP Summary on local and remote routers
    for rtrNum in [1, 2]:
        logger.info("Checking metrics of BGP router on r{}".format(rtrNum))

        router = tgen.gears["r{}".format(rtrNum)]
        reffile = os.path.join(CWD, "r{}/show_bgp.json".format(rtrNum))
        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=60, wait=2)
        assertmsg = "BGP routes on router r{} are wrong after removing metric route-maps".format(
            rtrNum)
        assert res is None, assertmsg
Example #39
0
def test_bgp_metric_config():
    "Test BGP Changing metric values in route-maps"

    tgen = get_topogen()

    # Skip if previous fatal error condition is raised
    if tgen.routers_have_failure():
        pytest.skip(tgen.errors)

    logger.info(
        "Configuring bgp route-maps on router r1 and r2 to update metric")

    # # Adding the following configuration to r1:
    # router bgp 65000
    #  address-family ipv4 unicast
    #   neighbor 192.168.0.2 route-map addmetric-in in
    #   neighbor 192.168.0.2 route-map addmetric-out out
    #   neighbor 192.168.101.2 route-map setmetric-in in
    #   neighbor 192.168.101.2 route-map setmetric-out out
    #  exit-address-family
    # !
    # ip prefix-list net1 seq 10 permit 192.168.101.0/24
    # ip prefix-list net2 seq 20 permit 192.168.1.0/24
    # !
    # route-map setmetric-in permit 10
    #  match ip address prefix-list net1
    #  set metric 111
    # !
    # route-map setmetric-in permit 20
    # !
    # route-map setmetric-out permit 10
    #  match ip address prefix-list net2
    #  set metric 1011
    # !
    # route-map setmetric-out permit 20
    # !
    # route-map addmetric-in permit 10
    #  set metric +11
    # !
    # route-map addmetric-out permit 10
    #  set metric +12
    # !

    tgen.net['r1'].cmd(
        'vtysh -c "conf t" -c "router bgp 65000" ' +
        '-c "address-family ipv4 unicast" ' +
        '-c "neighbor 192.168.0.2 route-map addmetric-in in" ' +
        '-c "neighbor 192.168.0.2 route-map addmetric-out out" ' +
        '-c "neighbor 192.168.101.2 route-map setmetric-in in" ' +
        '-c "neighbor 192.168.101.2 route-map setmetric-out out" ')
    tgen.net['r1'].cmd(
        'vtysh -c "conf t" ' +
        '-c "ip prefix-list net1 seq 10 permit 192.168.101.0/24" ' +
        '-c "ip prefix-list net2 seq 20 permit 192.168.1.0/24"')
    tgen.net['r1'].cmd('vtysh -c "conf t" ' +
                       '-c "route-map setmetric-in permit 10" ' +
                       '-c "match ip address prefix-list net1" ' +
                       '-c "set metric 111" ' +
                       '-c "route-map setmetric-in permit 20"')
    tgen.net['r1'].cmd('vtysh -c "conf t" ' +
                       '-c "route-map setmetric-out permit 10" ' +
                       '-c "match ip address prefix-list net2" ' +
                       '-c "set metric 1011" ' +
                       '-c "route-map setmetric-out permit 20"')
    tgen.net['r1'].cmd('vtysh -c "conf t" ' +
                       '-c "route-map addmetric-in permit 10" ' +
                       '-c "set metric +11"')
    tgen.net['r1'].cmd('vtysh -c "conf t" ' +
                       '-c "route-map addmetric-out permit 10" ' +
                       '-c "set metric +12"')

    # # Adding the following configuration to r2:
    # router bgp 65000
    #  address-family ipv4 unicast
    # neighbor 192.168.0.1 route-map subtractmetric-in in
    # neighbor 192.168.0.1 route-map subtractmetric-out out
    # neighbor 192.168.201.2 route-map setmetric-in in
    # neighbor 192.168.201.2 route-map setmetric-out out
    #  exit-address-family
    # !
    # ip prefix-list net1 seq 10 permit 192.168.201.0/24
    # ip prefix-list net2 seq 20 permit 192.168.2.0/24
    # !
    # route-map setmetric-in permit 10
    #  match ip address prefix-list net1
    #  set metric 222
    # !
    # route-map setmetric-in permit 20
    # !
    # route-map setmetric-out permit 10
    #  match ip address prefix-list net2
    #  set metric 2022
    # !
    # route-map setmetric-out permit 20
    # !
    # route-map subtractmetric-in permit 10
    #  set metric -22
    # !
    # route-map subtractmetric-out permit 10
    #  set metric -23
    # !

    tgen.net['r2'].cmd(
        'vtysh -c "conf t" -c "router bgp 65000" ' +
        '-c "address-family ipv4 unicast" ' +
        '-c "neighbor 192.168.0.1 route-map subtractmetric-in in" ' +
        '-c "neighbor 192.168.0.1 route-map subtractmetric-out out" ' +
        '-c "neighbor 192.168.201.2 route-map setmetric-in in" ' +
        '-c "neighbor 192.168.201.2 route-map setmetric-out out" ')
    tgen.net['r2'].cmd(
        'vtysh -c "conf t" ' +
        '-c "ip prefix-list net1 seq 10 permit 192.168.201.0/24" ' +
        '-c "ip prefix-list net2 seq 20 permit 192.168.2.0/24" ')
    tgen.net['r2'].cmd('vtysh -c "conf t" ' +
                       '-c "route-map setmetric-in permit 10" ' +
                       '-c "match ip address prefix-list net1" ' +
                       '-c "set metric 222" ' +
                       '-c "route-map setmetric-in permit 20"')
    tgen.net['r2'].cmd('vtysh -c "conf t" ' +
                       '-c "route-map setmetric-out permit 10" ' +
                       '-c "match ip address prefix-list net2" ' +
                       '-c "set metric 2022" ' +
                       '-c "route-map setmetric-out permit 20"')
    tgen.net['r2'].cmd('vtysh -c "conf t" ' +
                       '-c "route-map subtractmetric-in permit 10" ' +
                       '-c "set metric -22"')
    tgen.net['r2'].cmd('vtysh -c "conf t" ' +
                       '-c "route-map subtractmetric-out permit 10" ' +
                       '-c "set metric -23"')

    # Clear IN the bgp neighbors to make sure the route-maps are applied
    tgen.net['r1'].cmd('vtysh -c "clear ip bgp 192.168.0.2 in" ' +
                       '-c "clear ip bgp 192.168.101.2 in"')
    tgen.net['r2'].cmd('vtysh -c "clear ip bgp 192.168.0.1 in" ' +
                       '-c "clear ip bgp 192.168.201.2 in"')

    # tgen.mininet_cli()

    # Checking BGP config - should show the bgp metric settings in the route-maps
    logger.info("Checking BGP configuration for correct 'set metric' values")

    setmetric111 = tgen.net['r1'].cmd(
        'vtysh -c "show running" | grep "^ set metric 111"').rstrip()
    assertmsg = "'set metric 111' configuration applied to R1, but not visible in configuration"
    assert setmetric111 == ' set metric 111', assertmsg

    setmetric222 = tgen.net['r2'].cmd(
        'vtysh -c "show running" | grep "^ set metric 222"').rstrip()
    assertmsg = "'set metric 222' configuration applied to R2, but not visible in configuration"
    assert setmetric222 == ' set metric 222', assertmsg
def test_static_route_2nh_admin_dist_p0_tc_2_ibgp(request):
    """
    Verify static route functionality with 2 next hop & different AD value

    """
    tc_name = request.node.name
    write_test_header(tc_name)
    tgen = get_topogen()
    # Don't run this test if we have any failure.
    if tgen.routers_have_failure():
        pytest.skip(tgen.errors)

    reset_config_on_routers(tgen)
    NEXT_HOP_IP = populate_nh()
    step("Configure IPv4 static route (10.1.1.1) in R2 with next hop N1"
         "(28.1.1.2 ) AD 10 and N2 (29.1.1.2) AD 20 , Static route next-hop"
         "present on R1 \n ex :- ip route 10.1.1.1/24 28.1.1.2 10 & "
         "ip route 10.1.1.1/24 29.1.1.2 20")

    reset_config_on_routers(tgen)
    NEXT_HOP_IP = populate_nh()
    for addr_type in ADDR_TYPES:
        input_dict_4 = {
            "r2": {
                "static_routes": [
                    {
                        "network": NETWORK2[addr_type],
                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
                        "admin_distance": 10,
                    },
                    {
                        "network": NETWORK2[addr_type],
                        "next_hop": NEXT_HOP_IP["nh2"][addr_type],
                        "admin_distance": 20,
                    },
                ]
            }
        }
        logger.info("Configure static routes")
        result = create_static_routes(tgen, input_dict_4)
        assert result is True, "Testcase {} : Failed \n Error: {}".format(
            tc_name, result)

        step("On R2, static route installed in RIB using "
             "show ip route with 2 next hop , lowest AD nexthop is active ")
        rte1_nh1 = {
            "r2": {
                "static_routes": [{
                    "network": NETWORK2[addr_type],
                    "next_hop": NEXT_HOP_IP["nh1"][addr_type],
                    "admin_distance": 10,
                }]
            }
        }
        nh = [NEXT_HOP_IP["nh1"][addr_type]]
        dut = "r2"
        protocol = "static"
        result = verify_rib(tgen,
                            addr_type,
                            dut,
                            rte1_nh1,
                            next_hop=nh,
                            protocol=protocol,
                            fib=True)
        assert result is True, "Testcase {} : Failed \nError: Routes is"
        "missing in RIB".format(tc_name)

        rte2_nh2 = {
            "r2": {
                "static_routes": [{
                    "network": NETWORK2[addr_type],
                    "next_hop": NEXT_HOP_IP["nh2"][addr_type],
                    "admin_distance": 20,
                }]
            }
        }
        nh = [NEXT_HOP_IP["nh2"][addr_type]]
        dut = "r2"
        protocol = "static"
        result = verify_rib(
            tgen,
            addr_type,
            dut,
            rte2_nh2,
            next_hop=nh,
            protocol=protocol,
            fib=True,
            expected=False,
        )
        assert result is not True, "Testcase {} : Failed \nError: Routes is"
        "not active in RIB".format(tc_name)

        step("Configure IBGP IPv4 peering between R2 and R3 router.")
        step("Explicit route is added in R3 for R2 nexthop rechability")
        rt3_rtes = {
            "r3": {
                "static_routes": [
                    {
                        "network":
                        NEXT_HOP_IP["nh1"][addr_type] + "/32",
                        "next_hop":
                        topo["routers"]["r2"]["links"]["r3"][addr_type],
                    },
                    {
                        "network":
                        NEXT_HOP_IP["nh2"][addr_type] + "/32",
                        "next_hop":
                        topo["routers"]["r2"]["links"]["r3"][addr_type],
                    },
                ]
            }
        }
        logger.info("Configure static routes")
        result = create_static_routes(tgen, rt3_rtes)
        assert result is True, "Testcase {} : Failed \n Error: {}".format(
            tc_name, result)
        step("Configure redistribute static in BGP on R2 router")

        input_dict_2 = {
            "r2": {
                "bgp": {
                    "address_family": {
                        addr_type: {
                            "unicast": {
                                "redistribute": [{
                                    "redist_type": "static"
                                }]
                            }
                        }
                    }
                }
            }
        }
        result = create_router_bgp(tgen, topo, input_dict_2)
        assert result is True, "Testcase {} : Failed \n Error: {}".format(
            tc_name, result)

        step(
            "Remove the static route configured with nexthop N1 from running config"
        )
        rt1_nh1 = {
            "r2": {
                "static_routes": [{
                    "network": NETWORK[addr_type],
                    "next_hop": NEXT_HOP_IP["nh1"][addr_type],
                    "admin_distance": 10,
                    "delete": True,
                }]
            }
        }

        logger.info("Configure static routes")
        result = create_static_routes(tgen, rt1_nh1)
        assert result is True, "Testcase {} : Failed \n Error: {}".format(
            tc_name, result)

        step("On R2, after removing the static route with N1 , "
             "route become active with nexthop N2 and vice versa.")
        rte1_nh1 = {
            "r2": {
                "static_routes": [{
                    "network": NETWORK2[addr_type],
                    "next_hop": NEXT_HOP_IP["nh1"][addr_type],
                    "admin_distance": 10,
                }]
            }
        }
        nh = [NEXT_HOP_IP["nh1"][addr_type]]
        dut = "r2"
        protocol = "static"
        result = verify_rib(
            tgen,
            addr_type,
            dut,
            rte1_nh1,
            next_hop=nh,
            protocol=protocol,
            fib=True,
            expected=False,
        )
        assert result is not True, "Testcase {} : Failed \nError: Routes is"
        "missing in RIB".format(tc_name)

        rte2_nh2 = {
            "r2": {
                "static_routes": [{
                    "network": NETWORK2[addr_type],
                    "next_hop": NEXT_HOP_IP["nh2"][addr_type],
                    "admin_distance": 20,
                }]
            }
        }
        nh = [NEXT_HOP_IP["nh2"][addr_type]]
        result = verify_rib(tgen,
                            addr_type,
                            dut,
                            rte2_nh2,
                            next_hop=nh,
                            protocol=protocol,
                            fib=True)
        assert result is True, "Testcase {} : Failed \nError: Routes is"
        "not active in RIB".format(tc_name)

        step("Configure the static route with nexthop N1")
        rte1_nh1 = {
            "r2": {
                "static_routes": [{
                    "network": NETWORK[addr_type],
                    "next_hop": NEXT_HOP_IP["nh1"][addr_type],
                    "admin_distance": 10,
                }]
            }
        }
        logger.info("Configure static routes")
        result = create_static_routes(tgen, rte1_nh1)
        assert result is True, "Testcase {} : Failed \n Error: {}".format(
            tc_name, result)

        step(
            "Remove the static route configured with nexthop N2 from running config"
        )
        rte2_nh2 = {
            "r2": {
                "static_routes": [{
                    "network": NETWORK[addr_type],
                    "next_hop": NEXT_HOP_IP["nh2"][addr_type],
                    "admin_distance": 20,
                    "delete": True,
                }]
            }
        }
        logger.info("Configure static routes")
        result = create_static_routes(tgen, rte2_nh2)
        assert result is True, "Testcase {} : Failed \n Error: {}".format(
            tc_name, result)

        step("On R2, after removing the static route with N2 , "
             "route become active with nexthop N1 and vice versa.")
        nh = NEXT_HOP_IP["nh2"][addr_type]
        result = verify_rib(
            tgen,
            addr_type,
            dut,
            rte2_nh2,
            next_hop=nh,
            protocol=protocol,
            expected=False,
        )
        assert result is not True, "Testcase {} : Failed \nError: Routes is"
        " still present in RIB".format(tc_name)

        nh = [NEXT_HOP_IP["nh1"][addr_type]]
        result = verify_rib(tgen,
                            addr_type,
                            dut,
                            rte1_nh1,
                            next_hop=nh,
                            protocol=protocol)
        assert result is True, "Testcase {} : Failed \nError: Routes is"
        " missing in RIB".format(tc_name)

        step("Configure the static route with nexthop N2")
        rte2_nh2 = {
            "r2": {
                "static_routes": [{
                    "network": NETWORK[addr_type],
                    "next_hop": NEXT_HOP_IP["nh2"][addr_type],
                    "admin_distance": 20,
                }]
            }
        }

        logger.info("Configure static routes")
        result = create_static_routes(tgen, rte2_nh2)
        assert result is True, "Testcase {} : Failed \n Error: {}".format(
            tc_name, result)

        step("Shut nexthop interface N1")
        intf = topo["routers"]["r2"]["links"]["r1-link0"]["interface"]

        shutdown_bringup_interface(tgen, dut, intf, False)

        step("after shut of nexthop N1 , route become active with nexthop N2")

        nh = NEXT_HOP_IP["nh1"][addr_type]
        result = verify_rib(
            tgen,
            addr_type,
            dut,
            rte1_nh1,
            next_hop=nh,
            protocol=protocol,
            expected=False,
        )
        assert result is not True, "Testcase {} : Failed \nError: Routes is"
        " still present in RIB".format(tc_name)

        nh = [NEXT_HOP_IP["nh2"][addr_type]]
        result = verify_rib(tgen,
                            addr_type,
                            dut,
                            rte2_nh2,
                            next_hop=nh,
                            protocol=protocol,
                            fib=True)
        assert result is True, "Testcase {} : Failed \nError: Routes is"
        " missing in RIB".format(tc_name)

        step("No shut the nexthop interface N1")
        shutdown_bringup_interface(tgen, dut, intf, True)

        step("after shut of nexthop N1 , route become active "
             "with nexthop N2 and vice versa.")
        nh = [NEXT_HOP_IP["nh1"][addr_type]]

        result = verify_rib(tgen,
                            addr_type,
                            dut,
                            rte1_nh1,
                            next_hop=nh,
                            protocol=protocol,
                            fib=True)
        assert result is True, "Testcase {} : Failed \nError: Routes is"
        " missing in RIB".format(tc_name)

        step("Shut nexthop interface N2")
        intf = topo["routers"]["r2"]["links"]["r1-link1"]["interface"]

        shutdown_bringup_interface(tgen, dut, intf, False)

        step(" after shut of nexthop N1 , route become active with "
             "nexthop N2 and vice versa.")
        nh = NEXT_HOP_IP["nh2"][addr_type]

        result = verify_rib(
            tgen,
            addr_type,
            dut,
            rte2_nh2,
            next_hop=nh,
            protocol=protocol,
            expected=False,
        )
        assert result is not True, "Testcase {} : Failed \nError: Routes is"
        " still present in RIB".format(tc_name)

        nh = [NEXT_HOP_IP["nh1"][addr_type]]
        result = verify_rib(tgen,
                            addr_type,
                            dut,
                            rte1_nh1,
                            next_hop=nh,
                            protocol=protocol)
        assert result is True, "Testcase {} : Failed \nError: Routes is"
        " missing in RIB".format(tc_name)

        step("No shut nexthop interface N2")
        shutdown_bringup_interface(tgen, dut, intf, True)

        step("after shut of nexthop N1 , route become active "
             "with nexthop N2 and vice versa.")
        rte1_nh1 = {
            "r2": {
                "static_routes": [{
                    "network": NETWORK2[addr_type],
                    "next_hop": NEXT_HOP_IP["nh1"][addr_type],
                    "admin_distance": 10,
                }]
            }
        }
        nh = [NEXT_HOP_IP["nh1"][addr_type]]
        dut = "r2"
        protocol = "static"
        result = verify_rib(tgen,
                            addr_type,
                            dut,
                            rte1_nh1,
                            next_hop=nh,
                            protocol=protocol,
                            fib=True)
        assert result is True, "Testcase {} : Failed \nError: Routes is"
        "missing in RIB".format(tc_name)

        rte2_nh2 = {
            "r2": {
                "static_routes": [{
                    "network": NETWORK2[addr_type],
                    "next_hop": NEXT_HOP_IP["nh2"][addr_type],
                    "admin_distance": 20,
                }]
            }
        }
        nh = [NEXT_HOP_IP["nh2"][addr_type]]
        dut = "r2"
        protocol = "static"
        result = verify_rib(
            tgen,
            addr_type,
            dut,
            rte2_nh2,
            next_hop=nh,
            protocol=protocol,
            fib=True,
            expected=False,
        )
        assert result is not True, "Testcase {} : Failed \nError: Routes is"
        "not active in RIB".format(tc_name)

        dut = "r3"
        protocol = "bgp"

        result = verify_rib(
            tgen,
            addr_type,
            dut,
            rte2_nh2,
            next_hop=nh,
            protocol=protocol,
            fib=True,
            expected=False,
        )
        assert result is not True, "Testcase {} : Failed \nError: Routes is"
        "not active in RIB".format(tc_name)

        dut = "r2"
        step("Reload the FRR router")
        # stop/start -> restart FRR router and verify
        stop_router(tgen, "r2")

        start_router(tgen, "r2")

        step("After reload of FRR router , static route installed"
             " in RIB and FIB properly .")
        rte1_nh1 = {
            "r2": {
                "static_routes": [{
                    "network": NETWORK2[addr_type],
                    "next_hop": NEXT_HOP_IP["nh1"][addr_type],
                    "admin_distance": 10,
                }]
            }
        }
        nh = [NEXT_HOP_IP["nh1"][addr_type]]
        dut = "r2"
        protocol = "static"
        result = verify_rib(tgen,
                            addr_type,
                            dut,
                            rte1_nh1,
                            next_hop=nh,
                            protocol=protocol,
                            fib=True)
        assert result is True, "Testcase {} : Failed \nError: Routes is"
        "missing in RIB".format(tc_name)

        dut = "r3"
        protocol = "bgp"
        result = verify_bgp_rib(tgen, addr_type, dut, rte1_nh1, next_hop=nh)
        assert result is True, "Testcase {} : Failed \nError: Routes is"
        "missing in RIB".format(tc_name)

        rte2_nh2 = {
            "r2": {
                "static_routes": [{
                    "network": NETWORK2[addr_type],
                    "next_hop": NEXT_HOP_IP["nh2"][addr_type],
                    "admin_distance": 20,
                }]
            }
        }
        nh = [NEXT_HOP_IP["nh2"][addr_type]]
        dut = "r2"
        protocol = "static"
        result = verify_rib(
            tgen,
            addr_type,
            dut,
            rte2_nh2,
            next_hop=nh,
            protocol=protocol,
            fib=True,
            expected=False,
        )
        assert result is not True, "Testcase {} : Failed \nError: Routes is"
        "not active in RIB".format(tc_name)

        dut = "r3"
        protocol = "bgp"
        result = verify_bgp_rib(tgen, addr_type, dut, rte2_nh2, next_hop=nh)
        assert result is True, "Testcase {} : Failed \nError: Routes is"
        "not active in RIB".format(tc_name)

        result = verify_rib(
            tgen,
            addr_type,
            dut,
            rte2_nh2,
            next_hop=nh,
            protocol=protocol,
            fib=True,
            expected=False,
        )
        assert result is not True, "Testcase {} : Failed \nError: Routes is"
        "not active in RIB".format(tc_name)

    write_test_footer(tc_name)
Example #41
0
def test_RT_verification_auto_p0(request):
    """
    RT verification(auto)
    """

    tgen = get_topogen()
    tc_name = request.node.name
    write_test_header(tc_name)
    check_router_status(tgen)
    reset_config_on_routers(tgen)
    add_default_routes(tgen)

    if tgen.routers_have_failure():
        pytest.skip(tgen.errors)

    step(
        "Advertise overlapping prefixes from VNFs R1 and R2 in all VRFs "
        "RED, GREEN and BLUE 100.1.1.1/32 and 100::100/128"
    )

    for addr_type in ADDR_TYPES:
        input_dict_1 = {
            "r1": {
                "static_routes": [
                    {
                        "network": NETWORK4_1[addr_type],
                        "next_hop": NEXT_HOP_IP[addr_type],
                        "vrf": "RED",
                    }
                ]
            },
            "r2": {
                "static_routes": [
                    {
                        "network": NETWORK4_1[addr_type],
                        "next_hop": NEXT_HOP_IP[addr_type],
                        "vrf": "BLUE",
                    },
                    {
                        "network": NETWORK4_1[addr_type],
                        "next_hop": NEXT_HOP_IP[addr_type],
                        "vrf": "GREEN",
                    },
                ]
            },
        }

        result = create_static_routes(tgen, input_dict_1)
        assert result is True, "Testcase {} : Failed \n Error: {}".format(
            tc_name, result
        )

    step(
        "Verify that Edge-1 receives same prefixes in all 3 VRFs via "
        "corresponding next-hop in associated VRF sh bgp vrf all"
    )

    for addr_type in ADDR_TYPES:
        input_routes = {
            "r1": {
                "static_routes": [
                    {
                        "network": NETWORK4_1[addr_type],
                        "next_hop": NEXT_HOP_IP[addr_type],
                        "vrf": "RED",
                    }
                ]
            },
            "r2": {
                "static_routes": [
                    {
                        "network": NETWORK4_1[addr_type],
                        "next_hop": NEXT_HOP_IP[addr_type],
                        "vrf": "BLUE",
                    },
                    {
                        "network": NETWORK4_1[addr_type],
                        "next_hop": NEXT_HOP_IP[addr_type],
                        "vrf": "GREEN",
                    },
                ]
            },
        }

        result = verify_rib(tgen, addr_type, "e1", input_routes)
        assert result is True, "Testcase {} : Failed \n Error: {}".format(
            tc_name, result
        )

    step(
        "Configure 4-byte local AS number on Edge-1 and establish EVPN "
        "neighborship with DCG-1 & DCG-2."
    )

    topo_local = deepcopy(topo)

    step("Delete BGP config for vrf RED.")

    input_dict_vni = {
        "e1": {
            "vrfs": [
                {"name": "RED", "no_vni": VNI_1},
                {"name": "BLUE", "no_vni": VNI_2},
                {"name": "GREEN", "no_vni": VNI_3},
            ]
        }
    }
    result = create_vrf_cfg(tgen, topo, input_dict=input_dict_vni)
    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)

    input_dict_2 = {}
    for dut in ["e1"]:
        temp = {dut: {"bgp": []}}
        input_dict_2.update(temp)

        INDEX = [0, 1, 2, 3]
        VRFS = ["RED", "BLUE", "GREEN", None]
        AS_NUM = [100, 100, 100, 100]

        for index, vrf, as_num in zip(INDEX, VRFS, AS_NUM):
            topo_local["routers"][dut]["bgp"][index]["local_as"] = 4294967293
            if vrf:
                temp[dut]["bgp"].append(
                    {"local_as": as_num, "vrf": vrf, "delete": True}
                )
            else:
                temp[dut]["bgp"].append({"local_as": as_num, "delete": True})

    result = create_router_bgp(tgen, topo, input_dict_2)
    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)

    result = create_router_bgp(tgen, topo_local["routers"])
    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)

    input_dict_vni = {
        "e1": {
            "vrfs": [
                {"name": "RED", "vni": VNI_1},
                {"name": "BLUE", "vni": VNI_2},
                {"name": "GREEN", "vni": VNI_3},
            ]
        }
    }
    result = create_vrf_cfg(tgen, topo, input_dict=input_dict_vni)
    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)

    step(
        "Verify that all overlapping prefixes across different VRFs are "
        "advertised in EVPN with unique RD value(auto derived)."
    )
    step(
        "Verify that FRR uses only the lower 2 bytes of ASN+VNI for auto "
        "derived RT value."
    )

    for addr_type in ADDR_TYPES:
        input_routes_1 = {
            "r1": {"static_routes": [{"network": NETWORK4_1[addr_type], "vrf": "RED"}]}
        }
        input_routes_2 = {
            "r2": {"static_routes": [{"network": NETWORK4_1[addr_type], "vrf": "BLUE"}]}
        }
        input_routes_3 = {
            "r2": {
                "static_routes": [{"network": NETWORK4_1[addr_type], "vrf": "GREEN"}]
            }
        }

        result = verify_attributes_for_evpn_routes(
            tgen, topo, "e1", input_routes_1, rd="auto", rd_peer="e1"
        )
        assert result is True, "Testcase {} :Failed \n Error: {}".format(
            tc_name, result
        )

        result = verify_attributes_for_evpn_routes(
            tgen, topo, "e1", input_routes_1, rt="auto", rt_peer="e1"
        )
        assert result is True, "Testcase {} :Failed \n Error: {}".format(
            tc_name, result
        )

        result = verify_attributes_for_evpn_routes(
            tgen, topo, "e1", input_routes_2, rd="auto", rd_peer="e1"
        )
        assert result is True, "Testcase {} :Failed \n Error: {}".format(
            tc_name, result
        )

        result = verify_attributes_for_evpn_routes(
            tgen, topo, "e1", input_routes_2, rt="auto", rt_peer="e1"
        )
        assert result is True, "Testcase {} :Failed \n Error: {}".format(
            tc_name, result
        )

        result = verify_attributes_for_evpn_routes(
            tgen, topo, "e1", input_routes_3, rd="auto", rd_peer="e1"
        )
        assert result is True, "Testcase {} :Failed \n Error: {}".format(
            tc_name, result
        )

        result = verify_attributes_for_evpn_routes(
            tgen, topo, "e1", input_routes_3, rt="auto", rt_peer="e1"
        )
        assert result is True, "Testcase {} :Failed \n Error: {}".format(
            tc_name, result
        )

    step(
        "Verify that DCG-1(iBGP peer) automatically imports the prefixes"
        " from EVPN address-family to respective VRFs."
    )
    step(
        "Verify if DCG-2(eBGP peer) automatically imports the prefixes "
        "from EVPN address-family to respective VRFs or not."
    )

    for addr_type in ADDR_TYPES:
        input_routes = {
            "r1": {
                "static_routes": [
                    {
                        "network": NETWORK4_1[addr_type],
                        "next_hop": NEXT_HOP_IP[addr_type],
                        "vrf": "RED",
                    }
                ]
            },
            "r2": {
                "static_routes": [
                    {
                        "network": NETWORK4_1[addr_type],
                        "next_hop": NEXT_HOP_IP[addr_type],
                        "vrf": "BLUE",
                    },
                    {
                        "network": NETWORK4_1[addr_type],
                        "next_hop": NEXT_HOP_IP[addr_type],
                        "vrf": "GREEN",
                    },
                ]
            },
        }

        result = verify_rib(tgen, addr_type, "d1", input_routes)
        assert result is True, "Testcase {} : Failed \n Error: {}".format(
            tc_name, result
        )

        result = verify_rib(tgen, addr_type, "d2", input_routes)
        assert result is True, "Testcase {} : Failed \n Error: {}".format(
            tc_name, result
        )

    step(
        "Change the VNI number for all 3 VRFs on Edge-1 as:"
        "RED : 75400, GREEN: 75500, BLUE: 75600"
    )

    input_dict_vni = {
        "e1": {
            "vrfs": [
                {"name": "RED", "no_vni": VNI_1},
                {"name": "BLUE", "no_vni": VNI_2},
                {"name": "GREEN", "no_vni": VNI_3},
            ]
        }
    }
    result = create_vrf_cfg(tgen, topo, input_dict=input_dict_vni)
    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)

    input_dict_vni = {
        "e1": {
            "vrfs": [
                {"name": "RED", "vni": 75400},
                {"name": "BLUE", "vni": 75500},
                {"name": "GREEN", "vni": 75600},
            ]
        }
    }
    result = create_vrf_cfg(tgen, topo, input_dict=input_dict_vni)
    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)

    step("Delete configured vxlan")
    dut = "e1"
    vxlan_input = {
        dut: {
            "vxlan": [
                {
                    "vxlan_name": VXLAN["vxlan_name"],
                    "vxlan_id": VXLAN["vxlan_id"],
                    "dstport": VXLAN["dstport"],
                    "local_addr": VXLAN["local_addr"][dut],
                    "learning": VXLAN["learning"],
                    "delete": True,
                }
            ]
        }
    }

    result = configure_vxlan(tgen, vxlan_input)
    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)

    step("Configured vxlan")
    VXLAN["vxlan_id"] = [75400, 75500, 75600]
    vxlan_input = {
        dut: {
            "vxlan": [
                {
                    "vxlan_name": VXLAN["vxlan_name"],
                    "vxlan_id": VXLAN["vxlan_id"],
                    "dstport": VXLAN["dstport"],
                    "local_addr": VXLAN["local_addr"][dut],
                    "learning": VXLAN["learning"],
                }
            ]
        }
    }

    result = configure_vxlan(tgen, vxlan_input)
    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)

    step("Configure bridge interface")
    brctl_input = {
        dut: {
            "brctl": [
                {
                    "brctl_name": BRCTL["brctl_name"],
                    "addvxlan": BRCTL["addvxlan"],
                    "vrf": BRCTL["vrf"],
                    "stp": BRCTL["stp"],
                }
            ]
        }
    }
    result = configure_brctl(tgen, topo, brctl_input)
    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)

    step(
        "Verify on Edge-1 that auto derived RT value has changed for "
        "each VRF based on VNI number.."
    )

    input_dict = {
        "e1": {
            "vrfs": [
                {"RED": {"vni": 75400}},
                {"BLUE": {"vni": 75500}},
                {"GREEN": {"vni": 75600}},
            ]
        }
    }

    result = verify_vrf_vni(tgen, input_dict)
    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)

    step(
        "Verify on Edge-1 that auto derived RT value has changed for "
        "each VRF based on VNI number."
    )

    for addr_type in ADDR_TYPES:
        input_routes = {
            "r1": {"static_routes": [{"network": NETWORK4_1[addr_type], "vrf": "RED"}]}
        }

        result = verify_attributes_for_evpn_routes(
            tgen, topo, "e1", input_routes, rt="auto", rt_peer="e1"
        )
        assert result is True, "Testcase {} :Failed \n Error: {}".format(
            tc_name, result
        )

    step(
        "Verify on DCG-2 that prefixes are not imported from EVPN "
        "address-family to VRFs as RT values are different on sending("
        "edge-1) and receiving(DCG-2) end."
    )

    for addr_type in ADDR_TYPES:
        input_routes = {
            "r1": {"static_routes": [{"network": NETWORK4_1[addr_type], "vrf": "RED"}]}
        }

        result = verify_rib(tgen, addr_type, "d2", input_routes, expected=False)
        assert result is not True, "Testcase {} :Failed \n "
        "Routes are still present: {}".format(tc_name, result)
        logger.info("Expected Behavior: {}".format(result))

    step(
        "Revert back to original VNI number for all 3 VRFs on Edge-1 "
        "as: RED : 75100, GREEN: 75200, BLUE: 75300"
    )

    input_dict_vni = {
        "e1": {
            "vrfs": [
                {"name": "RED", "no_vni": 75400},
                {"name": "BLUE", "no_vni": 75500},
                {"name": "GREEN", "no_vni": 75600},
            ]
        }
    }
    result = create_vrf_cfg(tgen, topo, input_dict=input_dict_vni)
    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)

    input_dict_vni = {
        "e1": {
            "vrfs": [
                {"name": "RED", "vni": VNI_1},
                {"name": "BLUE", "vni": VNI_2},
                {"name": "GREEN", "vni": VNI_3},
            ]
        }
    }
    result = create_vrf_cfg(tgen, topo, input_dict=input_dict_vni)
    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)

    step("Delete configured vxlan")
    dut = "e1"
    vxlan_input = {
        dut: {
            "vxlan": [
                {
                    "vxlan_name": VXLAN["vxlan_name"],
                    "vxlan_id": VXLAN["vxlan_id"],
                    "dstport": VXLAN["dstport"],
                    "local_addr": VXLAN["local_addr"][dut],
                    "learning": VXLAN["learning"],
                    "delete": True,
                }
            ]
        }
    }
    result = configure_vxlan(tgen, vxlan_input)
    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)

    step("Configured vxlan")
    VXLAN["vxlan_id"] = [75100, 75200, 75300]
    vxlan_input = {
        dut: {
            "vxlan": [
                {
                    "vxlan_name": VXLAN["vxlan_name"],
                    "vxlan_id": VXLAN["vxlan_id"],
                    "dstport": VXLAN["dstport"],
                    "local_addr": VXLAN["local_addr"][dut],
                    "learning": VXLAN["learning"],
                }
            ]
        }
    }
    result = configure_vxlan(tgen, vxlan_input)
    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)

    step("Configure bridge interface")
    brctl_input = {
        dut: {
            "brctl": [
                {
                    "brctl_name": BRCTL["brctl_name"],
                    "addvxlan": BRCTL["addvxlan"],
                    "vrf": BRCTL["vrf"],
                    "stp": BRCTL["stp"],
                }
            ]
        }
    }
    result = configure_brctl(tgen, topo, brctl_input)
    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)

    step(
        "Verify on Edge-1 that auto derived RT value has changed for "
        "each VRF based on VNI number."
    )
    step(
        "Verify that DCG-1(iBGP peer) automatically imports the prefixes"
        " from EVPN address-family to respective VRFs."
    )

    for addr_type in ADDR_TYPES:
        input_routes = {
            "r1": {"static_routes": [{"network": NETWORK4_1[addr_type], "vrf": "RED"}]}
        }

        result = verify_attributes_for_evpn_routes(
            tgen, topo, "e1", input_routes, rt="auto", rt_peer="e1"
        )
        assert result is True, "Testcase {} :Failed \n Error: {}".format(
            tc_name, result
        )

        result = verify_rib(tgen, addr_type, "d1", input_routes)
        assert result is True, "Testcase {} :Failed \n Error: {}".format(
            tc_name, result
        )

    step("Test with smaller VNI numbers (1-75000)")

    input_dict_vni = {"e1": {"vrfs": [{"name": "RED", "no_vni": VNI_1}]}}
    result = create_vrf_cfg(tgen, topo, input_dict=input_dict_vni)
    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)

    input_dict_vni = {"e1": {"vrfs": [{"name": "RED", "vni": 111}]}}
    result = create_vrf_cfg(tgen, topo, input_dict=input_dict_vni)
    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)

    step(
        "Verify that DCG-2 receives EVPN prefixes along with auto "
        "derived RT values(based on smaller VNI numbers)"
    )

    for addr_type in ADDR_TYPES:
        input_routes_1 = {
            "r1": {"static_routes": [{"network": NETWORK4_1[addr_type], "vrf": "RED"}]}
        }

        result = verify_attributes_for_evpn_routes(
            tgen, topo, "d2", input_routes_1, rt="auto", rt_peer="e1", expected=False
        )
        assert result is not True, "Testcase {} :Failed \n "
        "Malfaromed Auto-RT value accepted: {}".format(tc_name, result)
        logger.info("Expected Behavior: {}".format(result))

    step("Configure VNI number more than boundary limit (16777215)")

    input_dict_vni = {"e1": {"vrfs": [{"name": "RED", "no_vni": 111}]}}
    result = create_vrf_cfg(tgen, topo, input_dict=input_dict_vni)
    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)

    input_dict_vni = {"e1": {"vrfs": [{"name": "RED", "vni": 16777215}]}}
    result = create_vrf_cfg(tgen, topo, input_dict=input_dict_vni)
    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)

    step("CLI error for malformed VNI.")
    input_dict = {
        "e1": {
            "vrfs": [{"RED": {"vni": 16777215, "routerMac": "None", "state": "Down"}}]
        }
    }

    result = verify_vrf_vni(tgen, input_dict)
    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)

    for addr_type in ADDR_TYPES:
        input_routes_1 = {
            "r1": {"static_routes": [{"network": NETWORK4_1[addr_type], "vrf": "RED"}]}
        }

        result = verify_attributes_for_evpn_routes(
            tgen, topo, "d2", input_routes_1, rt="auto", rt_peer="e1", expected=False
        )
        assert result is not True, "Testcase {} :Failed \n "
        "Malfaromed Auto-RT value accepted: {}".format(tc_name, result)
        logger.info("Expected Behavior: {}".format(result))

    step("Un-configure VNI number more than boundary limit (16777215)")

    input_dict_vni = {"e1": {"vrfs": [{"name": "RED", "no_vni": 16777215}]}}
    result = create_vrf_cfg(tgen, topo, input_dict=input_dict_vni)
    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)

    write_test_footer(tc_name)
def setup_module(mod):
    "Sets up the pytest environment"

    tgen = Topogen(build_topo, mod.__name__)
    tgen.start_topology()

    router_list = tgen.routers()

    krel = platform.release()
    if topotest.version_cmp(krel, "4.18") < 0:
        logger.info(
            'BGP EVPN RT5 NETNS tests will not run (have kernel "{}", but it requires 4.18)'.format(
                krel
            )
        )
        return pytest.skip("Skipping BGP EVPN RT5 NETNS Test. Kernel not supported")

    # create VRF vrf-101 on R1 and R2
    # create loop101
    cmds_vrflite = [
        "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",
        "ip link add loop101 type dummy",
        "ip link set dev loop101 master {}-vrf-101",
        "ip link set dev loop101 up",
    ]

    cmds_r2 = [  # config routing 101
        "ip link add name bridge-101 up type bridge stp_state 0",
        "ip link set bridge-101 master {}-vrf-101",
        "ip link set dev bridge-101 up",
        "ip link add name vxlan-101 type vxlan id 101 dstport 4789 dev r2-eth0 local 192.168.100.41",
        "ip link set dev vxlan-101 master bridge-101",
        "ip link set vxlan-101 up type bridge_slave learning off flood off mcast_flood off",
    ]

    # cmds_r1_netns_method3 = [
    #     "ip link add name vxlan-{1} type vxlan id {1} dstport 4789 dev {0}-eth0 local 192.168.100.21",
    #     "ip link set dev vxlan-{1} netns {0}-vrf-{1}",
    #     "ip netns exec {0}-vrf-{1} ip li set dev lo up",
    #     "ip netns exec {0}-vrf-{1} ip link add name bridge-{1} up type bridge stp_state 0",
    #     "ip netns exec {0}-vrf-{1} ip link set dev vxlan-{1} master bridge-{1}",
    #     "ip netns exec {0}-vrf-{1} ip link set bridge-{1} up",
    #     "ip netns exec {0}-vrf-{1} ip link set vxlan-{1} up",
    # ]

    router = tgen.gears["r1"]

    ns = "r1-vrf-101"
    tgen.net["r1"].add_netns(ns)
    tgen.net["r1"].cmd_raises("ip link add loop101 type dummy")
    tgen.net["r1"].set_intf_netns("loop101", ns, up=True)

    router = tgen.gears["r2"]
    for cmd in cmds_vrflite:
        logger.info("cmd to r2: " + cmd.format("r2"))
        output = router.cmd_raises(cmd.format("r2"))
        logger.info("result: " + output)

    for cmd in cmds_r2:
        logger.info("cmd to r2: " + cmd.format("r2"))
        output = router.cmd_raises(cmd.format("r2"))
        logger.info("result: " + output)

    tgen.net["r1"].cmd_raises(
        "ip link add name vxlan-101 type vxlan id 101 dstport 4789 dev r1-eth0 local 192.168.100.21"
    )
    tgen.net["r1"].set_intf_netns("vxlan-101", "r1-vrf-101", up=True)
    tgen.net["r1"].cmd_raises("ip -n r1-vrf-101 link set lo up")
    tgen.net["r1"].cmd_raises(
        "ip -n r1-vrf-101 link add name bridge-101 up type bridge stp_state 0"
    )
    tgen.net["r1"].cmd_raises(
        "ip -n r1-vrf-101 link set dev vxlan-101 master bridge-101"
    )
    tgen.net["r1"].cmd_raises("ip -n r1-vrf-101 link set bridge-101 up")
    tgen.net["r1"].cmd_raises("ip -n r1-vrf-101 link set vxlan-101 up")

    for rname, router in router_list.items():
        if rname == "r1":
            router.load_config(
                TopoRouter.RD_ZEBRA,
                os.path.join(CWD, "{}/zebra.conf".format(rname)),
                "--vrfwnetns",
            )
        else:
            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))
        )

    # Initialize all routers.
    tgen.start_router()
Example #43
0
def ltemplatePostRouterStartHook():
    logger.info('post router-start hook')
    return True
def test_vrf_route_leak():
    logger.info("Ensure that routes are leaked back and forth")
    tgen = get_topogen()
    # Don't run this test if we have any failure.
    if tgen.routers_have_failure():
        pytest.skip(tgen.errors)

    r1 = tgen.gears["r1"]

    # Test DONNA VRF.
    expect = {
        "10.0.0.0/24": [{
            "protocol": "connected",
        }],
        "10.0.1.0/24": [{
            "protocol": "bgp",
            "selected": True,
            "nexthops": [{
                "fib": True
            }]
        }],
        "10.0.2.0/24": [{
            "protocol": "connected"
        }],
        "10.0.3.0/24": [{
            "protocol": "bgp",
            "selected": True,
            "nexthops": [{
                "fib": True
            }]
        }],
    }

    test_func = partial(topotest.router_json_cmp, r1,
                        "show ip route vrf DONNA json", expect)
    result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
    assert result, "BGP VRF DONNA check failed:\n{}".format(diff)

    # Test EVA VRF.
    expect = {
        "10.0.0.0/24": [{
            "protocol": "bgp",
            "selected": True,
            "nexthops": [{
                "fib": True
            }]
        }],
        "10.0.1.0/24": [{
            "protocol": "connected",
        }],
        "10.0.2.0/24": [{
            "protocol": "bgp",
            "selected": True,
            "nexthops": [{
                "fib": True
            }]
        }],
        "10.0.3.0/24": [{
            "protocol": "connected",
        }],
    }

    test_func = partial(topotest.router_json_cmp, r1,
                        "show ip route vrf EVA json", expect)
    result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
    assert result, "BGP VRF EVA check failed:\n{}".format(diff)
Example #45
0
def test_ecmp_remove_nw_advertise(request):
    """
    Verify routes are cleared from BGP and RIB table of DUT,
    when advertise network configuration is removed
    """

    tc_name = request.node.name
    write_test_header(tc_name)
    tgen = get_topogen()

    # Verifying RIB routes
    dut = "r3"
    protocol = "bgp"

    reset_config_on_routers(tgen)
    static_or_nw(tgen, topo, tc_name, "advertise_nw", "r2")
    for addr_type in ADDR_TYPES:
        input_dict = {
            "r3": {
                "static_routes": [{
                    "network": NETWORK[addr_type]
                }]
            }
        }

        logger.info("Verifying %s routes on r3", addr_type)
        result = verify_rib(
            tgen,
            addr_type,
            dut,
            input_dict,
            next_hop=NEXT_HOPS[addr_type],
            protocol=protocol,
        )
        assert result is True, "Testcase {} : Failed \n Error: {}".format(
            tc_name, result)

    input_dict_3 = {
        "r2": {
            "bgp": {
                "address_family": {
                    "ipv4": {
                        "unicast": {
                            "advertise_networks": [{
                                "network": NETWORK["ipv4"],
                                "delete": True
                            }]
                        }
                    },
                    "ipv6": {
                        "unicast": {
                            "advertise_networks": [{
                                "network": NETWORK["ipv6"],
                                "delete": True
                            }]
                        }
                    },
                }
            }
        }
    }

    logger.info("Withdraw advertised networks")
    result = create_router_bgp(tgen, topo, input_dict_3)
    assert result is True, "Testcase {} : Failed \n Error: {}".format(
        tc_name, result)

    for addr_type in ADDR_TYPES:
        input_dict = {
            "r3": {
                "static_routes": [{
                    "network": NETWORK[addr_type]
                }]
            }
        }

        logger.info("Verifying %s routes on r3", addr_type)
        result = verify_rib(
            tgen,
            addr_type,
            dut,
            input_dict,
            next_hop=[],
            protocol=protocol,
            expected=False,
        )
        assert (
            result is not True
        ), "Testcase {} : Failed \n Routes still" " present in RIB".format(
            tc_name)

    static_or_nw(tgen, topo, tc_name, "advertise_nw", "r2")
    for addr_type in ADDR_TYPES:
        input_dict = {
            "r3": {
                "static_routes": [{
                    "network": NETWORK[addr_type]
                }]
            }
        }
        logger.info("Verifying %s routes on r3", addr_type)
        result = verify_rib(
            tgen,
            addr_type,
            dut,
            input_dict,
            next_hop=NEXT_HOPS[addr_type],
            protocol=protocol,
        )
        assert result is True, "Testcase {} : Failed \n Error: {}".format(
            tc_name, result)
Example #46
0
 def stop(self, wait=True, assertOnError=True):
     "Basic start function that just reports equipment stop"
     logger.info('stopping "{}"'.format(self.name))
     return ""
Example #47
0
 def stop(self, wait=True, assertOnError=True):
     "Basic stop function that just reports equipment stop"
     logger.info('"{}" base stop called'.format(self.name))
     return ""
Example #48
0
def diagnose_env_linux():
    """
    Run diagnostics in the running environment. Returns `True` when everything
    is ok, otherwise `False`.
    """
    ret = True

    # Test log path exists before installing handler.
    if not os.path.isdir("/tmp"):
        logger.warning("could not find /tmp for logs")
    else:
        os.system("mkdir /tmp/topotests")
        # Log diagnostics to file so it can be examined later.
        fhandler = logging.FileHandler(
            filename="/tmp/topotests/diagnostics.txt")
        fhandler.setLevel(logging.DEBUG)
        fhandler.setFormatter(
            logging.Formatter(fmt="%(asctime)s %(levelname)s: %(message)s"))
        logger.addHandler(fhandler)

    logger.info("Running environment diagnostics")

    # Load configuration
    config = configparser.ConfigParser(tgen_defaults)
    pytestini_path = os.path.join(CWD, "../pytest.ini")
    config.read(pytestini_path)

    # Assert that we are running as root
    if os.getuid() != 0:
        logger.error("you must run topotest as root")
        ret = False

    # Assert that we have mininet
    if os.system("which mn >/dev/null 2>/dev/null") != 0:
        logger.error(
            "could not find mininet binary (mininet is not installed)")
        ret = False

    # Assert that we have iproute installed
    if os.system("which ip >/dev/null 2>/dev/null") != 0:
        logger.error("could not find ip binary (iproute is not installed)")
        ret = False

    # Assert that we have gdb installed
    if os.system("which gdb >/dev/null 2>/dev/null") != 0:
        logger.error("could not find gdb binary (gdb is not installed)")
        ret = False

    # Assert that FRR utilities exist
    frrdir = config.get("topogen", "frrdir")
    if not os.path.isdir(frrdir):
        logger.error("could not find {} directory".format(frrdir))
        ret = False
    else:
        try:
            pwd.getpwnam("frr")[2]
        except KeyError:
            logger.warning('could not find "frr" user')

        try:
            grp.getgrnam("frr")[2]
        except KeyError:
            logger.warning('could not find "frr" group')

        try:
            if "frr" not in grp.getgrnam("frrvty").gr_mem:
                logger.error(
                    '"frr" user and group exist, but user is not under "frrvty"'
                )
        except KeyError:
            logger.warning('could not find "frrvty" group')

        for fname in [
                "zebra", "ospfd", "ospf6d", "bgpd", "ripd", "ripngd", "isisd",
                "pimd", "ldpd", "pbrd"
        ]:
            path = os.path.join(frrdir, fname)
            if not os.path.isfile(path):
                # LDPd is an exception
                if fname == "ldpd":
                    logger.info(
                        "could not find {} in {}".format(fname, frrdir) +
                        "(LDPd tests will not run)")
                    continue

                logger.warning("could not find {} in {}".format(fname, frrdir))
                ret = False
            else:
                if fname != "zebra":
                    continue

                os.system(
                    "{} -v 2>&1 >/tmp/topotests/frr_zebra.txt".format(path))

    # Test MPLS availability
    krel = platform.release()
    if topotest.version_cmp(krel, "4.5") < 0:
        logger.info(
            'LDPd tests will not run (have kernel "{}", but it requires 4.5)'.
            format(krel))

    # Test for MPLS Kernel modules available
    if not topotest.module_present("mpls-router", load=False) != 0:
        logger.info(
            "LDPd tests will not run (missing mpls-router kernel module)")
    if not topotest.module_present("mpls-iptunnel", load=False) != 0:
        logger.info(
            "LDPd tests will not run (missing mpls-iptunnel kernel module)")

    # TODO remove me when we start supporting exabgp >= 4
    try:
        output = subprocess.check_output(["exabgp", "-v"])
        line = output.split("\n")[0]
        version = line.split(" ")[2]
        if topotest.version_cmp(version, "4") >= 0:
            logger.warning(
                "BGP topologies are still using exabgp version 3, expect failures"
            )

    # We want to catch all exceptions
    # pylint: disable=W0702
    except:
        logger.warning("failed to find exabgp or returned error")

    # After we logged the output to file, remove the handler.
    logger.removeHandler(fhandler)

    return ret
Example #49
0
    def _init_topo(self, topodef):
        """
        Initialize the topogily provided by the user. The user topology class
        must call get_topogen() during build() to get the topogen object.
        """
        # Set the global variable so the test cases can access it anywhere
        set_topogen(self)

        # Increase host based limits
        topotest.fix_host_limits()

        # Test for MPLS Kernel modules available
        self.hasmpls = False
        if not topotest.module_present("mpls-router"):
            logger.info(
                "MPLS tests will not run (missing mpls-router kernel module)")
        elif not topotest.module_present("mpls-iptunnel"):
            logger.info(
                "MPLS tests will not run (missing mpls-iptunnel kernel module)"
            )
        else:
            self.hasmpls = True

        # Load the default topology configurations
        self._load_config()

        # Create new log directory
        self.logdir = topotest.get_logs_path(g_extra_config["rundir"])
        subprocess.check_call("mkdir -p {0} && chmod 1777 {0}".format(
            self.logdir),
                              shell=True)
        try:
            routertype = self.config.get(self.CONFIG_SECTION, "routertype")
            # Only allow group, if it exist.
            gid = grp.getgrnam(routertype)[2]
            os.chown(self.logdir, 0, gid)
            os.chmod(self.logdir, 0o775)
        except KeyError:
            # Allow anyone, but set the sticky bit to avoid file deletions
            os.chmod(self.logdir, 0o1777)

        # Remove old twisty way of creating sub-classed topology object which has it's
        # build method invoked which calls Topogen methods which then call Topo methods
        # to create a topology within the Topo object, which is then used by
        # Mininet(Micronet) to build the actual topology.
        assert not inspect.isclass(topodef)

        self.net = Mininet(controller=None)

        # New direct way: Either a dictionary defines the topology or a build function
        # is supplied, or a json filename all of which build the topology by calling
        # Topogen methods which call Mininet(Micronet) methods to create the actual
        # topology.
        if not inspect.isclass(topodef):
            if callable(topodef):
                topodef(self)
                self.net.configure_hosts()
            elif is_string(topodef):
                # topojson imports topogen in one function too,
                # switch away from this use here to the topojson
                # fixutre and remove this case
                from lib.topojson import build_topo_from_json

                with open(topodef, "r") as topof:
                    self.json_topo = json.load(topof)
                build_topo_from_json(self, self.json_topo)
                self.net.configure_hosts()
            elif topodef:
                self.add_topology_from_dict(topodef)
Example #50
0
def test_ecmp_fast_convergence(request, test_type, tgen, topo):
    """This test is to verify bgp fast-convergence cli functionality"""

    tc_name = request.node.name
    write_test_header(tc_name)

    # Verifying RIB routes
    dut = "r3"
    protocol = "bgp"

    reset_config_on_routers(tgen)
    static_or_nw(tgen, topo, tc_name, test_type, "r2")

    for addr_type in ADDR_TYPES:
        input_dict = {
            "r3": {
                "static_routes": [{
                    "network": NETWORK[addr_type]
                }]
            }
        }

        logger.info("Verifying %s routes on r3", addr_type)
        result = verify_rib(
            tgen,
            addr_type,
            dut,
            input_dict,
            protocol=protocol,
        )
        assert result is True, "Testcase {} : Failed \n Error: {}".format(
            tc_name, result)

    intf1 = topo["routers"]["r2"]["links"]["r3-link1"]["interface"]
    intf2 = topo["routers"]["r2"]["links"]["r3-link2"]["interface"]

    logger.info("Shutdown one of the link b/w r2 and r3")
    shutdown_bringup_interface(tgen, "r2", intf1, False)

    logger.info("Verify bgp neighbors are still up")
    result = verify_bgp_convergence(tgen, topo)
    assert result is True, "Testcase {} : Failed \n Error: {}".format(
        tc_name, result)

    logger.info("Shutdown another link b/w r2 and r3")
    shutdown_bringup_interface(tgen, "r2", intf2, False)

    logger.info("Wait for 10 sec and make sure bgp neighbors are still up")
    sleep(10)
    result = verify_bgp_convergence(tgen, topo)
    assert result is True, "Testcase {} : Failed \n Error: {}".format(
        tc_name, result)

    logger.info("No shut links b/w r2 and r3")
    shutdown_bringup_interface(tgen, "r2", intf1, True)
    shutdown_bringup_interface(tgen, "r2", intf2, True)

    logger.info("Ensure that the links are still up")
    result = verify_bgp_convergence(tgen, topo)

    logger.info("Enable bgp fast-convergence cli")
    raw_config = {
        "r2": {
            "raw_config": [
                "router bgp {}".format(
                    topo["routers"]["r2"]["bgp"]["local_as"]),
                "bgp fast-convergence",
            ]
        }
    }
    result = apply_raw_config(tgen, raw_config)
    assert result is True, "Testcase {} : Failed Error: {}".format(
        tc_name, result)

    logger.info("Ensure BGP has processed the cli")
    r2 = tgen.gears["r2"]
    output = r2.vtysh_cmd("show run")
    verify = re.search(r"fast-convergence", output)
    assert verify is not None, (
        "r2 does not have the fast convergence command yet")

    logger.info("Shutdown one link b/w r2 and r3")
    shutdown_bringup_interface(tgen, "r2", intf1, False)

    logger.info("Verify bgp neighbors goes down immediately")
    result = verify_bgp_convergence(tgen, topo, dut="r2", expected=False)
    assert result is not True, "Testcase {} : Failed \n Error: {}".format(
        tc_name, result)

    logger.info("Shutdown second link b/w r2 and r3")
    shutdown_bringup_interface(tgen, "r2", intf2, False)

    logger.info("Verify bgp neighbors goes down immediately")
    result = verify_bgp_convergence(tgen, topo, dut="r2", expected=False)
    assert result is not True, "Testcase {} : Failed \n Error: {}".format(
        tc_name, result)

    write_test_footer(tc_name)
Example #51
0
def static_or_nw(tgen, topo, tc_name, test_type, dut):

    if test_type == "redist_static":
        input_dict_static = {
            dut: {
                "static_routes": [
                    {
                        "network": NETWORK["ipv4"],
                        "next_hop": NEXT_HOP_IP["ipv4"]
                    },
                    {
                        "network": NETWORK["ipv6"],
                        "next_hop": NEXT_HOP_IP["ipv6"]
                    },
                ]
            }
        }
        logger.info("Configuring static route on router %s", dut)
        result = create_static_routes(tgen, input_dict_static)
        assert result is True, "Testcase {} : Failed \n Error: {}".format(
            tc_name, result)

        input_dict_2 = {
            dut: {
                "bgp": {
                    "address_family": {
                        "ipv4": {
                            "unicast": {
                                "redistribute": [{
                                    "redist_type": "static"
                                }]
                            }
                        },
                        "ipv6": {
                            "unicast": {
                                "redistribute": [{
                                    "redist_type": "static"
                                }]
                            }
                        },
                    }
                }
            }
        }

        logger.info("Configuring redistribute static route on router %s", dut)
        result = create_router_bgp(tgen, topo, input_dict_2)
        assert result is True, "Testcase {} : Failed \n Error: {}".format(
            tc_name, result)

    elif test_type == "advertise_nw":
        input_dict_nw = {
            dut: {
                "bgp": {
                    "address_family": {
                        "ipv4": {
                            "unicast": {
                                "advertise_networks": [{
                                    "network":
                                    NETWORK["ipv4"]
                                }]
                            }
                        },
                        "ipv6": {
                            "unicast": {
                                "advertise_networks": [{
                                    "network":
                                    NETWORK["ipv6"]
                                }]
                            }
                        },
                    }
                }
            }
        }

        logger.info(
            "Advertising networks %s %s from router %s",
            NETWORK["ipv4"],
            NETWORK["ipv6"],
            dut,
        )
        result = create_router_bgp(tgen, topo, input_dict_nw)
        assert result is True, "Testcase {} : Failed \n Error: {}".format(
            tc_name, result)
Example #52
0
def test_modify_ecmp_max_paths(request, ecmp_num, test_type):
    """
    Verify routes installed as per maximum-paths
    configuration (8/16/32).
    """

    tc_name = request.node.name
    write_test_header(tc_name)
    tgen = get_topogen()

    reset_config_on_routers(tgen)

    static_or_nw(tgen, topo, tc_name, test_type, "r2")

    input_dict = {
        "r3": {
            "bgp": {
                "address_family": {
                    "ipv4": {
                        "unicast": {
                            "maximum_paths": {
                                "ibgp": ecmp_num,
                            }
                        }
                    },
                    "ipv6": {
                        "unicast": {
                            "maximum_paths": {
                                "ibgp": ecmp_num,
                            }
                        }
                    },
                }
            }
        }
    }

    logger.info("Configuring bgp maximum-paths %s on router r3", ecmp_num)
    result = create_router_bgp(tgen, topo, input_dict)
    assert result is True, "Testcase {} : Failed \n Error: {}".format(
        tc_name, result)

    # Verifying RIB routes
    dut = "r3"
    protocol = "bgp"

    for addr_type in ADDR_TYPES:
        input_dict_1 = {
            "r3": {
                "static_routes": [{
                    "network": NETWORK[addr_type]
                }]
            }
        }

        logger.info("Verifying %s routes on r3", addr_type)
        result = verify_rib(
            tgen,
            addr_type,
            dut,
            input_dict_1,
            next_hop=NEXT_HOPS[addr_type][:int(ecmp_num)],
            protocol=protocol,
        )
        assert result is True, "Testcase {} : Failed \n Error: {}".format(
            tc_name, result)

    write_test_footer(tc_name)
Example #53
0
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
Example #54
0
def test_ecmp_after_clear_bgp(request, test_type):
    """ Verify BGP table and RIB in DUT after clear BGP routes and neighbors"""

    tc_name = request.node.name
    write_test_header(tc_name)
    tgen = get_topogen()

    reset_config_on_routers(tgen)

    # Verifying RIB routes
    dut = "r3"
    protocol = "bgp"

    static_or_nw(tgen, topo, tc_name, test_type, "r2")
    for addr_type in ADDR_TYPES:
        input_dict_1 = {
            "r3": {
                "static_routes": [{
                    "network": NETWORK[addr_type]
                }]
            }
        }

        logger.info("Verifying %s routes on r3", addr_type)
        result = verify_rib(
            tgen,
            addr_type,
            dut,
            input_dict_1,
            next_hop=NEXT_HOPS[addr_type],
            protocol=protocol,
        )
        assert result is True, "Testcase {} : Failed \n Error: {}".format(
            tc_name, result)

    # Clear BGP
    for addr_type in ADDR_TYPES:
        clear_bgp(tgen, addr_type, dut)

    # Verify BGP convergence
    result = verify_bgp_convergence(tgen, topo)
    assert result is True, "Testcase {} : Failed \n Error: {}".format(
        tc_name, result)

    for addr_type in ADDR_TYPES:
        input_dict_1 = {
            "r3": {
                "static_routes": [{
                    "network": NETWORK[addr_type]
                }]
            }
        }
        logger.info("Verifying %s routes on r3", addr_type)
        result = verify_rib(
            tgen,
            addr_type,
            dut,
            input_dict_1,
            next_hop=NEXT_HOPS[addr_type],
            protocol=protocol,
        )
        assert result is True, "Testcase {} : Failed \n Error: {}".format(
            tc_name, result)

    write_test_footer(tc_name)
Example #55
0
 def _check_sharpd_chunk(router, expected_chunk_file):
     logger.info("checking sharpd locator chunk status")
     output = json.loads(
         router.vtysh_cmd("show sharp segment-routing srv6 json"))
     expected = open_json_file("{}/{}".format(CWD, expected_chunk_file))
     return topotest.json_cmp(output, expected)
Example #56
0
def test_ecmp_shut_bgp_neighbor(request, test_type):
    """ Shut BGP neigbors one by one and verify BGP and routing table updated
        accordingly in DUT """

    tc_name = request.node.name
    write_test_header(tc_name)
    tgen = get_topogen()

    logger.info(INTF_LIST_R2)
    # Verifying RIB routes
    dut = "r3"
    protocol = "bgp"

    reset_config_on_routers(tgen)
    static_or_nw(tgen, topo, tc_name, test_type, "r2")

    for addr_type in ADDR_TYPES:
        input_dict = {
            "r3": {
                "static_routes": [{
                    "network": NETWORK[addr_type]
                }]
            }
        }

        logger.info("Verifying %s routes on r3", addr_type)
        result = verify_rib(
            tgen,
            addr_type,
            dut,
            input_dict,
            next_hop=NEXT_HOPS[addr_type],
            protocol=protocol,
        )
        assert result is True, "Testcase {} : Failed \n Error: {}".format(
            tc_name, result)

    for intf_num in range(len(INTF_LIST_R2) + 1, 16):
        intf_val = INTF_LIST_R2[intf_num:intf_num + 16]

        input_dict_1 = {"r2": {"interface_list": [intf_val], "status": "down"}}
        logger.info(
            "Shutting down neighbor interface {} on r2".format(intf_val))
        result = interface_status(tgen, topo, input_dict_1)
        assert result is True, "Testcase {} : Failed \n Error: {}".format(
            tc_name, result)

        for addr_type in ADDR_TYPES:
            if intf_num + 16 < 32:
                check_hops = NEXT_HOPS[addr_type]
            else:
                check_hops = []

            input_dict = {
                "r3": {
                    "static_routes": [{
                        "network": NETWORK[addr_type]
                    }]
                }
            }
            logger.info("Verifying %s routes on r3", addr_type)
            result = verify_rib(tgen,
                                addr_type,
                                dut,
                                input_dict,
                                next_hop=check_hops,
                                protocol=protocol)
            assert result is True, "Testcase {} : Failed \n Error: {}".format(
                tc_name, result)

    input_dict_1 = {"r2": {"interface_list": INTF_LIST_R2, "status": "up"}}

    logger.info("Enabling all neighbor interface {} on r2")
    result = interface_status(tgen, topo, input_dict_1)
    assert result is True, "Testcase {} : Failed \n Error: {}".format(
        tc_name, result)

    static_or_nw(tgen, topo, tc_name, test_type, "r2")
    for addr_type in ADDR_TYPES:
        input_dict = {
            "r3": {
                "static_routes": [{
                    "network": NETWORK[addr_type]
                }]
            }
        }

        logger.info("Verifying %s routes on r3", addr_type)
        result = verify_rib(
            tgen,
            addr_type,
            dut,
            input_dict,
            next_hop=NEXT_HOPS[addr_type],
            protocol=protocol,
        )
        assert result is True, "Testcase {} : Failed \n Error: {}".format(
            tc_name, result)

    write_test_footer(tc_name)
Example #57
0
def test_srv6():
    tgen = get_topogen()
    if tgen.routers_have_failure():
        pytest.skip(tgen.errors)
    router = tgen.gears['r1']

    def _check_srv6_locator(router, expected_locator_file):
        logger.info("checking zebra locator status")
        output = json.loads(
            router.vtysh_cmd("show segment-routing srv6 locator json"))
        expected = open_json_file("{}/{}".format(CWD, expected_locator_file))
        return topotest.json_cmp(output, expected)

    def _check_sharpd_chunk(router, expected_chunk_file):
        logger.info("checking sharpd locator chunk status")
        output = json.loads(
            router.vtysh_cmd("show sharp segment-routing srv6 json"))
        expected = open_json_file("{}/{}".format(CWD, expected_chunk_file))
        return topotest.json_cmp(output, expected)

    def check_srv6_locator(router, expected_file):
        func = functools.partial(_check_srv6_locator, router, expected_file)
        success, result = topotest.run_and_expect(func,
                                                  None,
                                                  count=5,
                                                  wait=0.5)
        assert result is None, 'Failed'

    def check_sharpd_chunk(router, expected_file):
        func = functools.partial(_check_sharpd_chunk, router, expected_file)
        success, result = topotest.run_and_expect(func,
                                                  None,
                                                  count=5,
                                                  wait=0.5)
        assert result is None, 'Failed'

    logger.info("Test1 for Locator Configuration")
    check_srv6_locator(router, "expected_locators1.json")
    check_sharpd_chunk(router, "expected_chunks1.json")

    logger.info("Test2 get chunk for locator loc1")
    router.vtysh_cmd("sharp srv6-manager get-locator-chunk loc1")
    check_srv6_locator(router, "expected_locators2.json")
    check_sharpd_chunk(router, "expected_chunks2.json")

    logger.info("Test3 release chunk for locator loc1")
    router.vtysh_cmd("sharp srv6-manager release-locator-chunk loc1")
    check_srv6_locator(router, "expected_locators3.json")
    check_sharpd_chunk(router, "expected_chunks3.json")

    logger.info("Test4 get chunk for non-exist locator by zclient")
    router.vtysh_cmd("sharp srv6-manager get-locator-chunk loc3")
    check_srv6_locator(router, "expected_locators4.json")
    check_sharpd_chunk(router, "expected_chunks4.json")

    logger.info("Test5 Test for Zclient. after locator loc3 was configured")
    router.vtysh_cmd("""
        configure terminal
         segment-routing
          srv6
           locators
            locator loc3
             prefix 2001:db8:3:3::/64
        """)
    check_srv6_locator(router, "expected_locators5.json")
    check_sharpd_chunk(router, "expected_chunks5.json")
Example #58
0
def test_ecmp_remove_static_route(request):
    """
    Delete static routes and verify routers are cleared from BGP table,
    and RIB of DUT.
    """

    tc_name = request.node.name
    write_test_header(tc_name)
    tgen = get_topogen()

    # Verifying RIB routes
    dut = "r3"
    protocol = "bgp"

    reset_config_on_routers(tgen)

    static_or_nw(tgen, topo, tc_name, "redist_static", "r2")
    for addr_type in ADDR_TYPES:
        input_dict_1 = {
            "r3": {
                "static_routes": [{
                    "network": NETWORK[addr_type]
                }]
            }
        }

        logger.info("Verifying %s routes on r3", addr_type)
        result = verify_rib(
            tgen,
            addr_type,
            dut,
            input_dict_1,
            next_hop=NEXT_HOPS[addr_type],
            protocol=protocol,
        )
        assert result is True, "Testcase {} : Failed \n Error: {}".format(
            tc_name, result)

    for addr_type in ADDR_TYPES:
        input_dict_2 = {
            "r2": {
                "static_routes": [{
                    "network": NETWORK[addr_type],
                    "next_hop": NEXT_HOP_IP[addr_type],
                    "delete": True,
                }]
            }
        }

        logger.info("Remove static routes")
        result = create_static_routes(tgen, input_dict_2)
        assert result is True, "Testcase {} : Failed \n Error: {}".format(
            tc_name, result)

        logger.info("Verifying %s routes on r3 are removed", addr_type)
        result = verify_rib(
            tgen,
            addr_type,
            dut,
            input_dict_2,
            next_hop=[],
            protocol=protocol,
            expected=False,
        )
        assert (
            result is not True
        ), "Testcase {} : Failed \n Routes still" " present in RIB".format(
            tc_name)

    for addr_type in ADDR_TYPES:
        # Enable static routes
        input_dict_4 = {
            "r2": {
                "static_routes": [{
                    "network": NETWORK[addr_type],
                    "next_hop": NEXT_HOP_IP[addr_type]
                }]
            }
        }

        logger.info("Enable static route")
        result = create_static_routes(tgen, input_dict_4)
        assert result is True, "Testcase {} : Failed \n Error: {}".format(
            tc_name, result)

        logger.info("Verifying %s routes on r3", addr_type)
        result = verify_rib(
            tgen,
            addr_type,
            dut,
            input_dict_4,
            next_hop=NEXT_HOPS[addr_type],
            protocol=protocol,
        )
        assert result is True, "Testcase {} : Failed \n Error: {}".format(
            tc_name, result)

    write_test_footer(tc_name)
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)
    topotest.sleep(4, "waiting 4 seconds for bgp convergence")
    # Check IPv4/IPv6 routing tables.
    output = tgen.gears["r1"].vtysh_cmd("show bgp l2vpn evpn", isjson=False)
    logger.info("==== result from show bgp l2vpn evpn")
    logger.info(output)
    output = tgen.gears["r1"].vtysh_cmd(
        "show bgp l2vpn evpn route detail", isjson=False
    )
    logger.info("==== result from show bgp l2vpn evpn route detail")
    logger.info(output)
    output = tgen.gears["r1"].vtysh_cmd("show bgp vrf r1-vrf-101 ipv4", isjson=False)
    logger.info("==== result from show bgp vrf r1-vrf-101 ipv4")
    logger.info(output)
    output = tgen.gears["r1"].vtysh_cmd("show bgp vrf r1-vrf-101", isjson=False)
    logger.info("==== result from show bgp vrf r1-vrf-101 ")
    logger.info(output)
    output = tgen.gears["r1"].vtysh_cmd("show ip route vrf r1-vrf-101", isjson=False)
    logger.info("==== result from show ip route vrf r1-vrf-101")
    logger.info(output)
    output = tgen.gears["r1"].vtysh_cmd("show evpn vni detail", isjson=False)
    logger.info("==== result from show evpn vni detail")
    logger.info(output)
    output = tgen.gears["r1"].vtysh_cmd("show evpn next-hops vni all", isjson=False)
    logger.info("==== result from show evpn next-hops vni all")
    logger.info(output)
    output = tgen.gears["r1"].vtysh_cmd("show evpn rmac vni all", isjson=False)
    logger.info("==== result from show evpn next-hops vni all")
    logger.info(output)
    # Check IPv4 and IPv6 connectivity between r1 and r2 ( routing vxlan evpn)
    pingrouter = tgen.gears["r1"]
    logger.info(
        "Check Ping IPv4 from  R1(r1-vrf-101) to R2(r2-vrf-101 = 192.168.101.41)"
    )
    output = pingrouter.run("ip netns exec r1-vrf-101 ping 192.168.101.41 -f -c 1000")
    logger.info(output)
    if "1000 packets transmitted, 1000 received" not in output:
        assertmsg = (
            "expected ping IPv4 from R1(r1-vrf-101) to R2(192.168.101.41) should be ok"
        )
        assert 0, assertmsg
    else:
        logger.info("Check Ping IPv4 from R1(r1-vrf-101) to R2(192.168.101.41) OK")
Example #60
0
def test_bgp_gshut():
    tgen = get_topogen()

    if tgen.routers_have_failure():
        pytest.skip(tgen.errors)

    r1 = tgen.gears["r1"]
    r2 = tgen.gears["r2"]
    r3 = tgen.gears["r3"]
    r4 = tgen.gears["r4"]
    r5 = tgen.gears["r5"]

    # Verify initial route states
    logger.info("\nVerify initial route states")

    _, result = _run_cmd_and_check(r1, "show ip bgp 13.1.1.1/32 json",
                                   "r1/bgp_route_1.json")
    assertmsg = "R1: Route 13.1.1.1/32 not present or has unexpected params"
    assert result is None, assertmsg

    _, result = _run_cmd_and_check(r3, "show ip bgp 11.1.1.1/32 json",
                                   "r3/bgp_route_1.json")
    assertmsg = "R3: Route 11.1.1.1/32 not present or has unexpected params"
    assert result is None, assertmsg

    _, result = _run_cmd_and_check(r5, "show ip bgp 14.1.1.1/32 json",
                                   "r5/bgp_route_1.json")
    assertmsg = "R5: Route 14.1.1.1/32 not present or has unexpected params"
    assert result is None, assertmsg

    logger.info("\nInitial route states are as expected")

    # "Test #1: Enable BGP-wide graceful-shutdown on R2 and check routes on peers"
    logger.info(
        "\nTest #1: Enable BGP-wide graceful-shutdown on R2 and check routes on peers"
    )

    r2.vtysh_cmd("""
          configure terminal
            bgp graceful-shutdown
        """)

    # R1, R3 and R5 should see routes from R2 with GSHUT. In addition,
    # R1 should see LOCAL_PREF of 0
    _, result = _run_cmd_and_check(r1, "show ip bgp 13.1.1.1/32 json",
                                   "r1/bgp_route_2.json")
    assertmsg = "R1: Route 13.1.1.1/32 not present or has unexpected params"
    assert result is None, assertmsg

    _, result = _run_cmd_and_check(r3, "show ip bgp 11.1.1.1/32 json",
                                   "r3/bgp_route_2.json")
    assertmsg = "R3: Route 11.1.1.1/32 not present or has unexpected params"
    assert result is None, assertmsg

    _, result = _run_cmd_and_check(r5, "show ip bgp 14.1.1.1/32 json",
                                   "r5/bgp_route_2.json")
    assertmsg = "R5: Route 14.1.1.1/32 not present or has unexpected params"
    assert result is None, assertmsg

    logger.info(
        "\nTest #1: Successful, routes have GSHUT and/or LPREF of 0 as expected"
    )

    # "Test #2: Turn off BGP-wide graceful-shutdown on R2 and check routes on peers"
    logger.info(
        "\nTest #2: Turn off BGP-wide graceful-shutdown on R2 and check routes on peers"
    )

    r2.vtysh_cmd("""
          configure terminal
            no bgp graceful-shutdown
        """)

    # R1, R3 and R5 should see routes from R2 with their original attributes
    _, result = _run_cmd_and_check(r1, "show ip bgp 13.1.1.1/32 json",
                                   "r1/bgp_route_1.json")
    assertmsg = "R1: Route 13.1.1.1/32 not present or has unexpected params"
    assert result is None, assertmsg

    _, result = _run_cmd_and_check(r3, "show ip bgp 11.1.1.1/32 json",
                                   "r3/bgp_route_1.json")
    assertmsg = "R3: Route 11.1.1.1/32 not present or has unexpected params"
    assert result is None, assertmsg

    _, result = _run_cmd_and_check(r5, "show ip bgp 14.1.1.1/32 json",
                                   "r5/bgp_route_1.json")
    assertmsg = "R5: Route 14.1.1.1/32 not present or has unexpected params"
    assert result is None, assertmsg

    logger.info(
        "\nTest #2: Successful, routes have their original attributes with default LPREF and without GSHUT"
    )

    # "Test #3: Enable graceful-shutdown on R2 only in VRF1 and check routes on peers"
    logger.info(
        "\nTest #3: Enable graceful-shutdown on R2 only in VRF1 and check routes on peers"
    )

    r2.vtysh_cmd("""
          configure terminal
            router bgp 65001 vrf vrf1
              bgp graceful-shutdown
        """)

    # R1 and R3 should see no change to their routes
    _, result = _run_cmd_and_check(r1, "show ip bgp 13.1.1.1/32 json",
                                   "r1/bgp_route_1.json")
    assertmsg = "R1: Route 13.1.1.1/32 not present or has unexpected params"
    assert result is None, assertmsg

    _, result = _run_cmd_and_check(r3, "show ip bgp 11.1.1.1/32 json",
                                   "r3/bgp_route_1.json")
    assertmsg = "R3: Route 11.1.1.1/32 not present or has unexpected params"
    assert result is None, assertmsg

    # R5 should see routes from R2 with GSHUT.
    _, result = _run_cmd_and_check(r5, "show ip bgp 14.1.1.1/32 json",
                                   "r5/bgp_route_2.json")
    assertmsg = "R5: Route 14.1.1.1/32 not present or has unexpected params"
    assert result is None, assertmsg

    logger.info(
        "\nTest #3: Successful, only VRF peers like R5 see routes with GSHUT")

    # "Test #4: Try to enable BGP-wide graceful-shutdown on R2 while it is configured in VRF1"
    logger.info(
        "\nTest #4: Try to enable BGP-wide graceful-shutdown on R2 while it is configured in VRF1"
    )

    ret = r2.vtysh_cmd("""
          configure terminal
            bgp graceful-shutdown
        """)

    # This should fail
    assertmsg = "R2: BGP-wide graceful-shutdown config not rejected even though it is enabled in VRF1"
    assert (re.search("global graceful-shutdown not permitted", ret)
            is not None), assertmsg

    logger.info(
        "\nTest #4: Successful, BGP-wide graceful-shutdown rejected as it is enabled in VRF"
    )

    # "Test #5: Turn off graceful-shutdown on R2 in VRF1 and check routes on peers"
    logger.info(
        "\nTest #5: Turn off graceful-shutdown on R2 in VRF1 and check routes on peers"
    )

    r2.vtysh_cmd("""
          configure terminal
            router bgp 65001 vrf vrf1
              no bgp graceful-shutdown
        """)

    # R1 and R3 should see no change to their routes
    _, result = _run_cmd_and_check(r1, "show ip bgp 13.1.1.1/32 json",
                                   "r1/bgp_route_1.json")
    assertmsg = "R1: Route 13.1.1.1/32 not present or has unexpected params"
    assert result is None, assertmsg

    _, result = _run_cmd_and_check(r3, "show ip bgp 11.1.1.1/32 json",
                                   "r3/bgp_route_1.json")
    assertmsg = "R3: Route 11.1.1.1/32 not present or has unexpected params"
    assert result is None, assertmsg

    # R5 should see routes from R2 with original attributes.
    _, result = _run_cmd_and_check(r5, "show ip bgp 14.1.1.1/32 json",
                                   "r5/bgp_route_1.json")
    assertmsg = "R5: Route 14.1.1.1/32 not present or has unexpected params"
    assert result is None, assertmsg

    logger.info(
        "\nTest #5: Successful, routes have their original attributes with default LPREF and without GSHUT"
    )