mirror of
https://github.com/FRRouting/frr.git
synced 2025-04-30 13:37:17 +02:00
1154 lines
38 KiB
Python
1154 lines
38 KiB
Python
#!/usr/bin/env python
|
|
|
|
#
|
|
# Copyright (c) 2019 by VMware, Inc. ("VMware")
|
|
# Used Copyright (c) 2018 by Network Device Education Foundation,
|
|
# Inc. ("NetDEF") in this file.
|
|
#
|
|
# Permission to use, copy, modify, and/or distribute this software
|
|
# for any purpose with or without fee is hereby granted, provided
|
|
# that the above copyright notice and this permission notice appear
|
|
# in all copies.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
|
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
|
|
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
|
|
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
|
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
|
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
|
# OF THIS SOFTWARE.
|
|
#
|
|
|
|
"""
|
|
Following tests are covered to test BGP basic functionality:
|
|
|
|
Test steps
|
|
- Create topology (setup module)
|
|
Creating 4 routers topology, r1, r2, r3 are in IBGP and
|
|
r3, r4 are in EBGP
|
|
- Bring up topology
|
|
- Verify for bgp to converge
|
|
- Modify/Delete and verify router-id
|
|
- Modify and verify bgp timers
|
|
- Create and verify static routes
|
|
- Modify and verify admin distance for existing static routes
|
|
- Test advertise network using network command
|
|
- Verify clear bgp
|
|
- Test bgp convergence with loopback interface
|
|
- Test advertise network using network command
|
|
- Verify routes not installed in zebra when /32 routes received
|
|
with loopback BGP session subnet
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import json
|
|
import time
|
|
import pytest
|
|
from copy import deepcopy
|
|
|
|
# Save the Current Working Directory to find configuration files.
|
|
CWD = os.path.dirname(os.path.realpath(__file__))
|
|
sys.path.append(os.path.join(CWD, "../"))
|
|
sys.path.append(os.path.join(CWD, "../lib/"))
|
|
|
|
# Required to instantiate the topology builder class.
|
|
|
|
# pylint: disable=C0413
|
|
# Import topogen and topotest helpers
|
|
from lib.topogen import Topogen, get_topogen
|
|
from mininet.topo import Topo
|
|
|
|
from lib.common_config import (
|
|
step,
|
|
start_topology,
|
|
write_test_header,
|
|
write_test_footer,
|
|
reset_config_on_routers,
|
|
create_static_routes,
|
|
verify_rib,
|
|
verify_admin_distance_for_static_routes,
|
|
check_address_types,
|
|
apply_raw_config,
|
|
addKernelRoute,
|
|
verify_fib_routes,
|
|
create_prefix_lists,
|
|
create_route_maps,
|
|
verify_bgp_community,
|
|
required_linux_kernel_version,
|
|
)
|
|
from lib.topolog import logger
|
|
from lib.bgp import (
|
|
verify_bgp_convergence,
|
|
create_router_bgp,
|
|
verify_router_id,
|
|
modify_as_number,
|
|
verify_as_numbers,
|
|
clear_bgp_and_verify,
|
|
verify_bgp_timers_and_functionality,
|
|
verify_bgp_rib,
|
|
)
|
|
from lib.topojson import build_topo_from_json, build_config_from_json
|
|
|
|
# Reading the data from JSON File for topology creation
|
|
jsonFile = "{}/bgp_basic_functionality.json".format(CWD)
|
|
try:
|
|
with open(jsonFile, "r") as topoJson:
|
|
topo = json.load(topoJson)
|
|
except IOError:
|
|
assert False, "Could not read file {}".format(jsonFile)
|
|
|
|
# Global Variable
|
|
KEEPALIVETIMER = 2
|
|
HOLDDOWNTIMER = 6
|
|
r1_ipv4_loopback = "1.0.1.0/24"
|
|
r2_ipv4_loopback = "1.0.2.0/24"
|
|
r3_ipv4_loopback = "1.0.3.0/24"
|
|
r4_ipv4_loopback = "1.0.4.0/24"
|
|
r1_ipv6_loopback = "2001:db8:f::1:0/120"
|
|
r2_ipv6_loopback = "2001:db8:f::2:0/120"
|
|
r3_ipv6_loopback = "2001:db8:f::3:0/120"
|
|
r4_ipv6_loopback = "2001:db8:f::4:0/120"
|
|
NETWORK = {
|
|
"ipv4": ["100.1.1.1/32", "100.1.1.2/32"],
|
|
"ipv6": ["100::1/128", "100::2/128"],
|
|
}
|
|
|
|
|
|
class CreateTopo(Topo):
|
|
"""
|
|
Test BasicTopo - topology 1
|
|
|
|
* `Topo`: Topology object
|
|
"""
|
|
|
|
def build(self, *_args, **_opts):
|
|
"""Build function"""
|
|
tgen = get_topogen(self)
|
|
|
|
# Building topology from json file
|
|
build_topo_from_json(tgen, topo)
|
|
|
|
|
|
def setup_module(mod):
|
|
"""
|
|
Sets up the pytest environment
|
|
|
|
* `mod`: module name
|
|
"""
|
|
|
|
# Required linux kernel version for this suite to run.
|
|
result = required_linux_kernel_version("4.15")
|
|
if result is not True:
|
|
pytest.skip("Kernel requirements are not met")
|
|
|
|
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__)
|
|
# ... and here it calls Mininet initialization functions.
|
|
|
|
# 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)
|
|
|
|
global ADDR_TYPES
|
|
global BGP_CONVERGENCE
|
|
ADDR_TYPES = check_address_types()
|
|
BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
|
|
assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
|
|
BGP_CONVERGENCE
|
|
)
|
|
|
|
logger.info("Running setup_module() done")
|
|
|
|
|
|
def teardown_module():
|
|
"""Teardown the pytest environment"""
|
|
|
|
logger.info("Running teardown_module to delete topology")
|
|
|
|
tgen = get_topogen()
|
|
|
|
# Stop toplogy and Remove tmp files
|
|
tgen.stop_topology()
|
|
|
|
logger.info(
|
|
"Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
|
|
)
|
|
logger.info("=" * 40)
|
|
|
|
|
|
#####################################################
|
|
#
|
|
# Testcases
|
|
#
|
|
#####################################################
|
|
|
|
|
|
def test_modify_and_delete_router_id(request):
|
|
""" Test to modify, delete and verify router-id. """
|
|
|
|
tgen = get_topogen()
|
|
if BGP_CONVERGENCE is not True:
|
|
pytest.skip("skipped because of BGP Convergence failure")
|
|
|
|
# test case name
|
|
tc_name = request.node.name
|
|
write_test_header(tc_name)
|
|
|
|
# Modify router id
|
|
input_dict = {
|
|
"r1": {"bgp": {"router_id": "12.12.12.12"}},
|
|
"r2": {"bgp": {"router_id": "22.22.22.22"}},
|
|
"r3": {"bgp": {"router_id": "33.33.33.33"}},
|
|
}
|
|
result = create_router_bgp(tgen, topo, input_dict)
|
|
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
|
|
|
|
# Verifying router id once modified
|
|
result = verify_router_id(tgen, topo, input_dict)
|
|
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
|
|
|
|
# Delete router id
|
|
input_dict = {
|
|
"r1": {"bgp": {"del_router_id": True}},
|
|
"r2": {"bgp": {"del_router_id": True}},
|
|
"r3": {"bgp": {"del_router_id": True}},
|
|
}
|
|
result = create_router_bgp(tgen, topo, input_dict)
|
|
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
|
|
|
|
# Verifying router id once deleted
|
|
# Once router-id is deleted, highest interface ip should become
|
|
# router-id
|
|
result = verify_router_id(tgen, topo, input_dict)
|
|
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
|
|
|
|
write_test_footer(tc_name)
|
|
|
|
|
|
def test_bgp_config_with_4byte_as_number(request):
|
|
"""
|
|
Configure BGP with 4 byte ASN and verify it works fine
|
|
"""
|
|
|
|
tgen = get_topogen()
|
|
if BGP_CONVERGENCE is not True:
|
|
pytest.skip("skipped because of BGP Convergence failure")
|
|
|
|
# test case name
|
|
tc_name = request.node.name
|
|
write_test_header(tc_name)
|
|
|
|
input_dict = {
|
|
"r1": {"bgp": {"local_as": 131079}},
|
|
"r2": {"bgp": {"local_as": 131079}},
|
|
"r3": {"bgp": {"local_as": 131079}},
|
|
"r4": {"bgp": {"local_as": 131080}},
|
|
}
|
|
result = modify_as_number(tgen, topo, input_dict)
|
|
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
|
|
|
|
result = verify_as_numbers(tgen, topo, input_dict)
|
|
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
|
|
|
|
write_test_footer(tc_name)
|
|
|
|
|
|
def test_BGP_config_with_invalid_ASN_p2(request):
|
|
"""
|
|
Configure BGP with invalid ASN(ex - 0, reserved ASN) and verify test case
|
|
ended up with error
|
|
"""
|
|
|
|
tgen = get_topogen()
|
|
global BGP_CONVERGENCE
|
|
|
|
if BGP_CONVERGENCE != True:
|
|
pytest.skip("skipped because of BGP Convergence failure")
|
|
|
|
# test case name
|
|
tc_name = request.node.name
|
|
write_test_header(tc_name)
|
|
|
|
# Api call to modify AS number
|
|
input_dict = {
|
|
"r1": {"bgp": {"local_as": 0,}},
|
|
"r2": {"bgp": {"local_as": 0,}},
|
|
"r3": {"bgp": {"local_as": 0,}},
|
|
"r4": {"bgp": {"local_as": 64000,}},
|
|
}
|
|
result = modify_as_number(tgen, topo, input_dict)
|
|
try:
|
|
assert result is True
|
|
except AssertionError:
|
|
logger.info("Expected behaviour: {}".format(result))
|
|
logger.info("BGP config is not created because of invalid ASNs")
|
|
|
|
write_test_footer(tc_name)
|
|
|
|
|
|
def test_BGP_config_with_2byteAS_and_4byteAS_number_p1(request):
|
|
"""
|
|
Configure BGP with 4 byte and 2 byte ASN and verify BGP is converged
|
|
"""
|
|
|
|
tgen = get_topogen()
|
|
global BGP_CONVERGENCE
|
|
|
|
if BGP_CONVERGENCE != True:
|
|
pytest.skip("skipped because of BGP Convergence failure")
|
|
|
|
# test case name
|
|
tc_name = request.node.name
|
|
write_test_header(tc_name)
|
|
|
|
# Api call to modify AS number
|
|
input_dict = {
|
|
"r1": {"bgp": {"local_as": 131079}},
|
|
"r2": {"bgp": {"local_as": 131079}},
|
|
"r3": {"bgp": {"local_as": 131079}},
|
|
"r4": {"bgp": {"local_as": 111}},
|
|
}
|
|
result = modify_as_number(tgen, topo, input_dict)
|
|
if result != True:
|
|
assert False, "Testcase " + tc_name + " :Failed \n Error: {}".format(result)
|
|
|
|
result = verify_as_numbers(tgen, topo, input_dict)
|
|
if result != True:
|
|
assert False, "Testcase " + tc_name + " :Failed \n Error: {}".format(result)
|
|
|
|
# Api call verify whether BGP is converged
|
|
result = verify_bgp_convergence(tgen, topo)
|
|
if result != True:
|
|
assert False, "Testcase " + tc_name + " :Failed \n Error: {}".format(result)
|
|
|
|
write_test_footer(tc_name)
|
|
|
|
|
|
def test_bgp_timers_functionality(request):
|
|
"""
|
|
Test to modify bgp timers and verify timers functionality.
|
|
"""
|
|
|
|
tgen = get_topogen()
|
|
if BGP_CONVERGENCE is not True:
|
|
pytest.skip("skipped because of BGP Convergence failure")
|
|
|
|
# test case name
|
|
tc_name = request.node.name
|
|
write_test_header(tc_name)
|
|
|
|
# Creating configuration from JSON
|
|
reset_config_on_routers(tgen)
|
|
|
|
# Api call to modfiy BGP timerse
|
|
input_dict = {
|
|
"r1": {
|
|
"bgp": {
|
|
"address_family": {
|
|
"ipv4": {
|
|
"unicast": {
|
|
"neighbor": {
|
|
"r2": {
|
|
"dest_link": {
|
|
"r1": {
|
|
"keepalivetimer": KEEPALIVETIMER,
|
|
"holddowntimer": HOLDDOWNTIMER,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
result = create_router_bgp(tgen, topo, deepcopy(input_dict))
|
|
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
|
|
|
|
# Api call to clear bgp, so timer modification would take place
|
|
clear_bgp_and_verify(tgen, topo, "r1")
|
|
|
|
# Verifying bgp timers functionality
|
|
result = verify_bgp_timers_and_functionality(tgen, topo, input_dict)
|
|
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
|
|
|
|
write_test_footer(tc_name)
|
|
|
|
|
|
def test_static_routes(request):
|
|
""" Test to create and verify static routes. """
|
|
|
|
tgen = get_topogen()
|
|
if BGP_CONVERGENCE is not True:
|
|
pytest.skip("skipped because of BGP Convergence failure")
|
|
|
|
# test case name
|
|
tc_name = request.node.name
|
|
write_test_header(tc_name)
|
|
|
|
# Creating configuration from JSON
|
|
reset_config_on_routers(tgen)
|
|
|
|
# Api call to create static routes
|
|
input_dict = {
|
|
"r1": {
|
|
"static_routes": [
|
|
{
|
|
"network": "10.0.20.1/32",
|
|
"no_of_ip": 9,
|
|
"admin_distance": 100,
|
|
"next_hop": "10.0.0.2",
|
|
}
|
|
]
|
|
}
|
|
}
|
|
result = create_static_routes(tgen, input_dict)
|
|
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
|
|
|
|
# Api call to redistribute static routes
|
|
input_dict_1 = {
|
|
"r1": {
|
|
"bgp": {
|
|
"address_family": {
|
|
"ipv4": {
|
|
"unicast": {
|
|
"redistribute": [
|
|
{"redist_type": "static"},
|
|
{"redist_type": "connected"},
|
|
]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
result = create_router_bgp(tgen, topo, input_dict_1)
|
|
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
|
|
|
|
# Verifying RIB routes
|
|
dut = "r3"
|
|
protocol = "bgp"
|
|
next_hop = ["10.0.0.2", "10.0.0.5"]
|
|
result = verify_rib(
|
|
tgen, "ipv4", dut, input_dict, next_hop=next_hop, protocol=protocol
|
|
)
|
|
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
|
|
|
|
write_test_footer(tc_name)
|
|
|
|
|
|
def test_admin_distance_for_existing_static_routes(request):
|
|
""" Test to modify and verify admin distance for existing static routes."""
|
|
|
|
tgen = get_topogen()
|
|
if BGP_CONVERGENCE is not True:
|
|
pytest.skip("skipped because of BGP Convergence failure")
|
|
|
|
# test case name
|
|
tc_name = request.node.name
|
|
write_test_header(tc_name)
|
|
|
|
# Creating configuration from JSON
|
|
reset_config_on_routers(tgen)
|
|
|
|
input_dict = {
|
|
"r1": {
|
|
"static_routes": [
|
|
{
|
|
"network": "10.0.20.1/32",
|
|
"admin_distance": 10,
|
|
"next_hop": "10.0.0.2",
|
|
}
|
|
]
|
|
}
|
|
}
|
|
result = create_static_routes(tgen, input_dict)
|
|
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
|
|
|
|
# Verifying admin distance once modified
|
|
result = verify_admin_distance_for_static_routes(tgen, input_dict)
|
|
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
|
|
|
|
write_test_footer(tc_name)
|
|
|
|
|
|
def test_advertise_network_using_network_command(request):
|
|
""" Test advertise networks using network command."""
|
|
|
|
tgen = get_topogen()
|
|
if BGP_CONVERGENCE is not True:
|
|
pytest.skip("skipped because of BGP Convergence failure")
|
|
|
|
# test case name
|
|
tc_name = request.node.name
|
|
write_test_header(tc_name)
|
|
|
|
# Creating configuration from JSON
|
|
reset_config_on_routers(tgen)
|
|
|
|
# Api call to advertise networks
|
|
input_dict = {
|
|
"r1": {
|
|
"bgp": {
|
|
"address_family": {
|
|
"ipv4": {
|
|
"unicast": {
|
|
"advertise_networks": [
|
|
{"network": "20.0.0.0/32", "no_of_network": 10},
|
|
{"network": "30.0.0.0/32", "no_of_network": 10},
|
|
]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
result = create_router_bgp(tgen, topo, input_dict)
|
|
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
|
|
|
|
# Verifying RIB routes
|
|
dut = "r2"
|
|
protocol = "bgp"
|
|
result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
|
|
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
|
|
|
|
write_test_footer(tc_name)
|
|
|
|
|
|
def test_clear_bgp_and_verify(request):
|
|
"""
|
|
Created few static routes and verified all routes are learned via BGP
|
|
cleared BGP and verified all routes are intact
|
|
"""
|
|
|
|
tgen = get_topogen()
|
|
if BGP_CONVERGENCE is not True:
|
|
pytest.skip("skipped because of BGP Convergence failure")
|
|
|
|
# test case name
|
|
tc_name = request.node.name
|
|
write_test_header(tc_name)
|
|
|
|
# Creating configuration from JSON
|
|
reset_config_on_routers(tgen)
|
|
|
|
# clear ip bgp
|
|
result = clear_bgp_and_verify(tgen, topo, "r1")
|
|
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
|
|
|
|
write_test_footer(tc_name)
|
|
|
|
|
|
def test_BGP_attributes_with_vrf_default_keyword_p0(request):
|
|
"""
|
|
TC_9:
|
|
Verify BGP functionality for default vrf with
|
|
"vrf default" keyword.
|
|
"""
|
|
|
|
tc_name = request.node.name
|
|
write_test_header(tc_name)
|
|
tgen = get_topogen()
|
|
|
|
if tgen.routers_have_failure():
|
|
pytest.skip(tgen.errors)
|
|
|
|
# reset_config_on_routers(tgen)
|
|
|
|
step("Configure static routes and redistribute in BGP on R3")
|
|
for addr_type in ADDR_TYPES:
|
|
input_dict = {
|
|
"r3": {
|
|
"static_routes": [
|
|
{
|
|
"network": NETWORK[addr_type][0],
|
|
"no_of_ip": 4,
|
|
"next_hop": "Null0",
|
|
}
|
|
]
|
|
}
|
|
}
|
|
|
|
result = create_static_routes(tgen, input_dict)
|
|
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
|
tc_name, result
|
|
)
|
|
|
|
input_dict_2 = {
|
|
"r3": {
|
|
"bgp": {
|
|
"address_family": {
|
|
"ipv4": {"unicast": {"redistribute": [{"redist_type": "static"}]}},
|
|
"ipv6": {"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(
|
|
"Create a route-map to match a specific prefix and modify"
|
|
"BGP attributes for matched prefix"
|
|
)
|
|
input_dict_2 = {
|
|
"r3": {
|
|
"prefix_lists": {
|
|
"ipv4": {
|
|
"ABC": [
|
|
{
|
|
"seqid": 10,
|
|
"action": "permit",
|
|
"network": NETWORK["ipv4"][0],
|
|
}
|
|
]
|
|
},
|
|
"ipv6": {
|
|
"XYZ": [
|
|
{
|
|
"seqid": 100,
|
|
"action": "permit",
|
|
"network": NETWORK["ipv6"][0],
|
|
}
|
|
]
|
|
},
|
|
}
|
|
}
|
|
}
|
|
result = create_prefix_lists(tgen, input_dict_2)
|
|
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
|
|
|
|
for addr_type in ADDR_TYPES:
|
|
if addr_type == "ipv4":
|
|
pf_list = "ABC"
|
|
else:
|
|
pf_list = "XYZ"
|
|
|
|
input_dict_6 = {
|
|
"r3": {
|
|
"route_maps": {
|
|
"BGP_ATTR_{}".format(addr_type): [
|
|
{
|
|
"action": "permit",
|
|
"seq_id": 10,
|
|
"match": {addr_type: {"prefix_lists": pf_list}},
|
|
"set": {
|
|
"aspath": {"as_num": 500, "as_action": "prepend"},
|
|
"localpref": 500,
|
|
"origin": "egp",
|
|
"community": {"num": "500:500", "action": "additive"},
|
|
"large_community": {
|
|
"num": "500:500:500",
|
|
"action": "additive",
|
|
},
|
|
},
|
|
},
|
|
{"action": "permit", "seq_id": 20},
|
|
]
|
|
},
|
|
"BGP_ATTR_{}".format(addr_type): [
|
|
{
|
|
"action": "permit",
|
|
"seq_id": 100,
|
|
"match": {addr_type: {"prefix_lists": pf_list}},
|
|
"set": {
|
|
"aspath": {"as_num": 500, "as_action": "prepend"},
|
|
"localpref": 500,
|
|
"origin": "egp",
|
|
"community": {"num": "500:500", "action": "additive"},
|
|
"large_community": {
|
|
"num": "500:500:500",
|
|
"action": "additive",
|
|
},
|
|
},
|
|
},
|
|
{"action": "permit", "seq_id": 200},
|
|
],
|
|
}
|
|
}
|
|
|
|
result = create_route_maps(tgen, input_dict_6)
|
|
assert result is True, "Testcase {} : Failed \n Error: {}".format(
|
|
tc_name, result
|
|
)
|
|
|
|
step("Apply the route-map on R3 in outbound direction for peer R4")
|
|
|
|
input_dict_7 = {
|
|
"r3": {
|
|
"bgp": {
|
|
"address_family": {
|
|
"ipv4": {
|
|
"unicast": {
|
|
"neighbor": {
|
|
"r4": {
|
|
"dest_link": {
|
|
"r3": {
|
|
"route_maps": [
|
|
{
|
|
"name": "BGP_ATTR_ipv4",
|
|
"direction": "out",
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"ipv6": {
|
|
"unicast": {
|
|
"neighbor": {
|
|
"r4": {
|
|
"dest_link": {
|
|
"r3": {
|
|
"route_maps": [
|
|
{
|
|
"name": "BGP_ATTR_ipv6",
|
|
"direction": "out",
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
result = create_router_bgp(tgen, topo, input_dict_7)
|
|
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
|
|
|
|
step(
|
|
"verify modified attributes for specific prefix with 'vrf default'"
|
|
"keyword on R4"
|
|
)
|
|
for addr_type in ADDR_TYPES:
|
|
dut = "r4"
|
|
input_dict = {
|
|
"r3": {
|
|
"static_routes": [
|
|
{
|
|
"network": NETWORK[addr_type][0],
|
|
"vrf": "default",
|
|
"largeCommunity": "500:500:500",
|
|
}
|
|
]
|
|
}
|
|
}
|
|
|
|
result = verify_bgp_rib(tgen, addr_type, dut, input_dict)
|
|
assert result is True, "Testcase : Failed \n Error: {}".format(tc_name, result)
|
|
result = verify_rib(tgen, addr_type, dut, input_dict)
|
|
assert result is True, "Testcase : Failed \n Error: {}".format(tc_name, result)
|
|
|
|
for addr_type in ADDR_TYPES:
|
|
dut = "r4"
|
|
input_dict = {
|
|
"r3": {
|
|
"static_routes": [
|
|
{
|
|
"network": NETWORK[addr_type][0],
|
|
"vrf": "default",
|
|
"community": "500:500",
|
|
}
|
|
]
|
|
}
|
|
}
|
|
|
|
result = verify_bgp_rib(tgen, addr_type, dut, input_dict)
|
|
assert result is True, "Testcase : Failed \n Error: {}".format(tc_name, result)
|
|
result = verify_rib(tgen, addr_type, dut, input_dict)
|
|
assert result is True, "Testcase : Failed \n Error: {}".format(tc_name, result)
|
|
|
|
input_dict_4 = {"largeCommunity": "500:500:500", "community": "500:500"}
|
|
|
|
result = verify_bgp_community(
|
|
tgen, addr_type, dut, [NETWORK[addr_type][0]], input_dict_4
|
|
)
|
|
assert result is True, "Test case {} : Should fail \n Error: {}".format(
|
|
tc_name, result
|
|
)
|
|
|
|
write_test_footer(tc_name)
|
|
|
|
|
|
def test_bgp_with_loopback_interface(request):
|
|
"""
|
|
Test BGP with loopback interface
|
|
|
|
Adding keys:value pair "dest_link": "lo" and "source_link": "lo"
|
|
peer dict of input json file for all router's creating config using
|
|
loopback interface. Once BGP neighboship is up then verifying BGP
|
|
convergence
|
|
"""
|
|
|
|
tgen = get_topogen()
|
|
if BGP_CONVERGENCE is not True:
|
|
pytest.skip("skipped because of BGP Convergence failure")
|
|
|
|
# test case name
|
|
tc_name = request.node.name
|
|
write_test_header(tc_name)
|
|
|
|
# Creating configuration from JSON
|
|
reset_config_on_routers(tgen)
|
|
|
|
for routerN in sorted(topo["routers"].keys()):
|
|
for bgp_neighbor in topo["routers"][routerN]["bgp"]["address_family"]["ipv4"][
|
|
"unicast"
|
|
]["neighbor"].keys():
|
|
|
|
# Adding ['source_link'] = 'lo' key:value pair
|
|
topo["routers"][routerN]["bgp"]["address_family"]["ipv4"]["unicast"][
|
|
"neighbor"
|
|
][bgp_neighbor]["dest_link"] = {"lo": {"source_link": "lo",}}
|
|
|
|
# Creating configuration from JSON
|
|
build_config_from_json(tgen, topo)
|
|
|
|
input_dict = {
|
|
"r1": {
|
|
"static_routes": [
|
|
{"network": "1.0.2.17/32", "next_hop": "10.0.0.2"},
|
|
{"network": "1.0.3.17/32", "next_hop": "10.0.0.6"},
|
|
]
|
|
},
|
|
"r2": {
|
|
"static_routes": [
|
|
{"network": "1.0.1.17/32", "next_hop": "10.0.0.1"},
|
|
{"network": "1.0.3.17/32", "next_hop": "10.0.0.10"},
|
|
]
|
|
},
|
|
"r3": {
|
|
"static_routes": [
|
|
{"network": "1.0.1.17/32", "next_hop": "10.0.0.5"},
|
|
{"network": "1.0.2.17/32", "next_hop": "10.0.0.9"},
|
|
{"network": "1.0.4.17/32", "next_hop": "10.0.0.14"},
|
|
]
|
|
},
|
|
"r4": {"static_routes": [{"network": "1.0.3.17/32", "next_hop": "10.0.0.13"}]},
|
|
}
|
|
result = create_static_routes(tgen, input_dict)
|
|
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
|
|
|
|
# Api call verify whether BGP is converged
|
|
result = verify_bgp_convergence(tgen, topo)
|
|
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
|
|
|
|
write_test_footer(tc_name)
|
|
|
|
|
|
def test_bgp_with_loopback_with_same_subnet_p1(request):
|
|
"""
|
|
Verify routes not installed in zebra when /32 routes received
|
|
with loopback BGP session subnet
|
|
"""
|
|
|
|
tgen = get_topogen()
|
|
if BGP_CONVERGENCE is not True:
|
|
pytest.skip("skipped because of BGP Convergence failure")
|
|
|
|
# test case name
|
|
tc_name = request.node.name
|
|
write_test_header(tc_name)
|
|
|
|
# Creating configuration from JSON
|
|
reset_config_on_routers(tgen)
|
|
step("Delete BGP seesion created initially")
|
|
input_dict_r1 = {
|
|
"r1": {"bgp": {"delete": True}},
|
|
"r2": {"bgp": {"delete": True}},
|
|
"r3": {"bgp": {"delete": True}},
|
|
"r4": {"bgp": {"delete": True}},
|
|
}
|
|
result = create_router_bgp(tgen, topo, input_dict_r1)
|
|
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
|
|
|
|
step("Create BGP session over loop address")
|
|
topo_modify = deepcopy(topo)
|
|
|
|
for routerN in sorted(topo["routers"].keys()):
|
|
for addr_type in ADDR_TYPES:
|
|
for bgp_neighbor in topo_modify["routers"][routerN]["bgp"][
|
|
"address_family"
|
|
][addr_type]["unicast"]["neighbor"].keys():
|
|
|
|
# Adding ['source_link'] = 'lo' key:value pair
|
|
topo_modify["routers"][routerN]["bgp"]["address_family"][addr_type][
|
|
"unicast"
|
|
]["neighbor"][bgp_neighbor]["dest_link"] = {
|
|
"lo": {"source_link": "lo", "ebgp_multihop": 2}
|
|
}
|
|
|
|
result = create_router_bgp(tgen, topo_modify["routers"])
|
|
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
|
|
|
|
step("Disable IPv6 BGP nbr from ipv4 address family")
|
|
raw_config = {
|
|
"r1": {
|
|
"raw_config": [
|
|
"router bgp {}".format(topo["routers"]["r1"]["bgp"]["local_as"]),
|
|
"address-family ipv4 unicast",
|
|
"no neighbor {} activate".format(
|
|
topo["routers"]["r2"]["links"]["lo"]["ipv6"].split("/")[0]
|
|
),
|
|
"no neighbor {} activate".format(
|
|
topo["routers"]["r3"]["links"]["lo"]["ipv6"].split("/")[0]
|
|
),
|
|
]
|
|
},
|
|
"r2": {
|
|
"raw_config": [
|
|
"router bgp {}".format(topo["routers"]["r2"]["bgp"]["local_as"]),
|
|
"address-family ipv4 unicast",
|
|
"no neighbor {} activate".format(
|
|
topo["routers"]["r1"]["links"]["lo"]["ipv6"].split("/")[0]
|
|
),
|
|
"no neighbor {} activate".format(
|
|
topo["routers"]["r3"]["links"]["lo"]["ipv6"].split("/")[0]
|
|
),
|
|
]
|
|
},
|
|
"r3": {
|
|
"raw_config": [
|
|
"router bgp {}".format(topo["routers"]["r3"]["bgp"]["local_as"]),
|
|
"address-family ipv4 unicast",
|
|
"no neighbor {} activate".format(
|
|
topo["routers"]["r1"]["links"]["lo"]["ipv6"].split("/")[0]
|
|
),
|
|
"no neighbor {} activate".format(
|
|
topo["routers"]["r2"]["links"]["lo"]["ipv6"].split("/")[0]
|
|
),
|
|
"no neighbor {} activate".format(
|
|
topo["routers"]["r4"]["links"]["lo"]["ipv6"].split("/")[0]
|
|
),
|
|
]
|
|
},
|
|
"r4": {
|
|
"raw_config": [
|
|
"router bgp {}".format(topo["routers"]["r4"]["bgp"]["local_as"]),
|
|
"address-family ipv4 unicast",
|
|
"no neighbor {} activate".format(
|
|
topo["routers"]["r3"]["links"]["lo"]["ipv6"].split("/")[0]
|
|
),
|
|
]
|
|
},
|
|
}
|
|
|
|
step("Configure kernel routes")
|
|
result = apply_raw_config(tgen, raw_config)
|
|
assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
|
|
|
|
r1_ipv4_lo = topo["routers"]["r1"]["links"]["lo"]["ipv4"]
|
|
r1_ipv6_lo = topo["routers"]["r1"]["links"]["lo"]["ipv6"]
|
|
r2_ipv4_lo = topo["routers"]["r2"]["links"]["lo"]["ipv4"]
|
|
r2_ipv6_lo = topo["routers"]["r2"]["links"]["lo"]["ipv6"]
|
|
r3_ipv4_lo = topo["routers"]["r3"]["links"]["lo"]["ipv4"]
|
|
r3_ipv6_lo = topo["routers"]["r3"]["links"]["lo"]["ipv6"]
|
|
r4_ipv4_lo = topo["routers"]["r4"]["links"]["lo"]["ipv4"]
|
|
r4_ipv6_lo = topo["routers"]["r4"]["links"]["lo"]["ipv6"]
|
|
|
|
r1_r2 = topo["routers"]["r1"]["links"]["r2"]["ipv6"].split("/")[0]
|
|
r2_r1 = topo["routers"]["r2"]["links"]["r1"]["ipv6"].split("/")[0]
|
|
r1_r3 = topo["routers"]["r1"]["links"]["r3"]["ipv6"].split("/")[0]
|
|
r3_r1 = topo["routers"]["r3"]["links"]["r1"]["ipv6"].split("/")[0]
|
|
r2_r3 = topo["routers"]["r2"]["links"]["r3"]["ipv6"].split("/")[0]
|
|
r3_r2 = topo["routers"]["r3"]["links"]["r2"]["ipv6"].split("/")[0]
|
|
r3_r4 = topo["routers"]["r3"]["links"]["r4"]["ipv6"].split("/")[0]
|
|
r4_r3 = topo["routers"]["r4"]["links"]["r3"]["ipv6"].split("/")[0]
|
|
|
|
r1_r2_ipv4 = topo["routers"]["r1"]["links"]["r2"]["ipv4"].split("/")[0]
|
|
r2_r1_ipv4 = topo["routers"]["r2"]["links"]["r1"]["ipv4"].split("/")[0]
|
|
r1_r3_ipv4 = topo["routers"]["r1"]["links"]["r3"]["ipv4"].split("/")[0]
|
|
r3_r1_ipv4 = topo["routers"]["r3"]["links"]["r1"]["ipv4"].split("/")[0]
|
|
r2_r3_ipv4 = topo["routers"]["r2"]["links"]["r3"]["ipv4"].split("/")[0]
|
|
r3_r2_ipv4 = topo["routers"]["r3"]["links"]["r2"]["ipv4"].split("/")[0]
|
|
r3_r4_ipv4 = topo["routers"]["r3"]["links"]["r4"]["ipv4"].split("/")[0]
|
|
r4_r3_ipv4 = topo["routers"]["r4"]["links"]["r3"]["ipv4"].split("/")[0]
|
|
|
|
r1_r2_intf = topo["routers"]["r1"]["links"]["r2"]["interface"]
|
|
r2_r1_intf = topo["routers"]["r2"]["links"]["r1"]["interface"]
|
|
r1_r3_intf = topo["routers"]["r1"]["links"]["r3"]["interface"]
|
|
r3_r1_intf = topo["routers"]["r3"]["links"]["r1"]["interface"]
|
|
r2_r3_intf = topo["routers"]["r2"]["links"]["r3"]["interface"]
|
|
r3_r2_intf = topo["routers"]["r3"]["links"]["r2"]["interface"]
|
|
r3_r4_intf = topo["routers"]["r3"]["links"]["r4"]["interface"]
|
|
r4_r3_intf = topo["routers"]["r4"]["links"]["r3"]["interface"]
|
|
|
|
ipv4_list = [
|
|
("r1", r1_r2_intf, r2_ipv4_loopback),
|
|
("r1", r1_r3_intf, r3_ipv4_loopback),
|
|
("r2", r2_r1_intf, r1_ipv4_loopback),
|
|
("r2", r2_r3_intf, r3_ipv4_loopback),
|
|
("r3", r3_r1_intf, r1_ipv4_loopback),
|
|
("r3", r3_r2_intf, r2_ipv4_loopback),
|
|
("r3", r3_r4_intf, r4_ipv4_loopback),
|
|
("r4", r4_r3_intf, r3_ipv4_loopback),
|
|
]
|
|
|
|
ipv6_list = [
|
|
("r1", r1_r2_intf, r2_ipv6_loopback, r2_r1),
|
|
("r1", r1_r3_intf, r3_ipv6_loopback, r3_r1),
|
|
("r2", r2_r1_intf, r1_ipv6_loopback, r1_r2),
|
|
("r2", r2_r3_intf, r3_ipv6_loopback, r3_r2),
|
|
("r3", r3_r1_intf, r1_ipv6_loopback, r1_r3),
|
|
("r3", r3_r2_intf, r2_ipv6_loopback, r2_r3),
|
|
("r3", r3_r4_intf, r4_ipv6_loopback, r4_r3),
|
|
("r4", r4_r3_intf, r3_ipv6_loopback, r3_r4),
|
|
]
|
|
|
|
for dut, intf, loop_addr in ipv4_list:
|
|
result = addKernelRoute(tgen, dut, intf, loop_addr)
|
|
assert result is True, "Testcase {}:Failed \n Error: {}".format(tc_name, result)
|
|
|
|
for dut, intf, loop_addr, next_hop in ipv6_list:
|
|
result = addKernelRoute(tgen, dut, intf, loop_addr, next_hop)
|
|
assert result is True, "Testcase {}:Failed \n Error: {}".format(tc_name, result)
|
|
|
|
step("Configure static routes")
|
|
|
|
input_dict = {
|
|
"r1": {
|
|
"static_routes": [
|
|
{"network": r2_ipv4_loopback, "next_hop": r2_r1_ipv4},
|
|
{"network": r3_ipv4_loopback, "next_hop": r3_r1_ipv4},
|
|
{"network": r2_ipv6_loopback, "next_hop": r2_r1},
|
|
{"network": r3_ipv6_loopback, "next_hop": r3_r1},
|
|
]
|
|
},
|
|
"r2": {
|
|
"static_routes": [
|
|
{"network": r1_ipv4_loopback, "next_hop": r1_r2_ipv4},
|
|
{"network": r3_ipv4_loopback, "next_hop": r3_r2_ipv4},
|
|
{"network": r1_ipv6_loopback, "next_hop": r1_r2},
|
|
{"network": r3_ipv6_loopback, "next_hop": r3_r2},
|
|
]
|
|
},
|
|
"r3": {
|
|
"static_routes": [
|
|
{"network": r1_ipv4_loopback, "next_hop": r1_r3_ipv4},
|
|
{"network": r2_ipv4_loopback, "next_hop": r2_r3_ipv4},
|
|
{"network": r4_ipv4_loopback, "next_hop": r4_r3_ipv4},
|
|
{"network": r1_ipv6_loopback, "next_hop": r1_r3},
|
|
{"network": r2_ipv6_loopback, "next_hop": r2_r3},
|
|
{"network": r4_ipv6_loopback, "next_hop": r4_r3},
|
|
]
|
|
},
|
|
"r4": {
|
|
"static_routes": [
|
|
{"network": r3_ipv4_loopback, "next_hop": r3_r4_ipv4},
|
|
{"network": r3_ipv6_loopback, "next_hop": r3_r4},
|
|
]
|
|
},
|
|
}
|
|
result = create_static_routes(tgen, input_dict)
|
|
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
|
|
|
|
step("Verify BGP session convergence")
|
|
|
|
result = verify_bgp_convergence(tgen, topo_modify)
|
|
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
|
|
|
|
step("Configure redistribute connected on R2 and R4")
|
|
input_dict_1 = {
|
|
"r2": {
|
|
"bgp": {
|
|
"address_family": {
|
|
"ipv4": {
|
|
"unicast": {"redistribute": [{"redist_type": "connected"}]}
|
|
},
|
|
"ipv6": {
|
|
"unicast": {"redistribute": [{"redist_type": "connected"}]}
|
|
},
|
|
}
|
|
}
|
|
},
|
|
"r4": {
|
|
"bgp": {
|
|
"address_family": {
|
|
"ipv4": {
|
|
"unicast": {"redistribute": [{"redist_type": "connected"}]}
|
|
},
|
|
"ipv6": {
|
|
"unicast": {"redistribute": [{"redist_type": "connected"}]}
|
|
},
|
|
}
|
|
}
|
|
},
|
|
}
|
|
|
|
result = create_router_bgp(tgen, topo, input_dict_1)
|
|
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
|
|
|
|
step("Verify Ipv4 and Ipv6 network installed in R1 RIB but not in FIB")
|
|
input_dict_r1 = {
|
|
"r1": {
|
|
"static_routes": [
|
|
{"network": "1.0.2.17/32"},
|
|
{"network": "2001:db8:f::2:17/128"},
|
|
]
|
|
}
|
|
}
|
|
|
|
dut = "r1"
|
|
protocol = "bgp"
|
|
for addr_type in ADDR_TYPES:
|
|
result = verify_rib(tgen, addr_type, dut, input_dict_r1, protocol=protocol)
|
|
assert result is True, "Testcase {} :Failed \n Error: {}".format(
|
|
tc_name, result
|
|
)
|
|
|
|
result = verify_fib_routes(tgen, addr_type, dut, input_dict_r1, expected=False)
|
|
assert result is not True, "Testcase {} : Failed \n"
|
|
"Expected behavior: routes should not present in fib \n"
|
|
"Error: {}".format(tc_name, result)
|
|
|
|
step("Verify Ipv4 and Ipv6 network installed in r3 RIB but not in FIB")
|
|
input_dict_r3 = {
|
|
"r3": {
|
|
"static_routes": [
|
|
{"network": "1.0.4.17/32"},
|
|
{"network": "2001:db8:f::4:17/128"},
|
|
]
|
|
}
|
|
}
|
|
dut = "r3"
|
|
protocol = "bgp"
|
|
for addr_type in ADDR_TYPES:
|
|
result = verify_rib(
|
|
tgen, addr_type, dut, input_dict_r3, protocol=protocol, fib=None
|
|
)
|
|
assert result is True, "Testcase {} :Failed \n Error: {}".format(
|
|
tc_name, result
|
|
)
|
|
|
|
result = verify_fib_routes(tgen, addr_type, dut, input_dict_r1, expected=False)
|
|
assert result is not True, "Testcase {} : Failed \n"
|
|
"Expected behavior: routes should not present in fib \n"
|
|
"Error: {}".format(tc_name, result)
|
|
|
|
write_test_footer(tc_name)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
args = ["-s"] + sys.argv[1:]
|
|
sys.exit(pytest.main(args))
|