diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index ddeaf55b33..13c794f182 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -21,6 +21,7 @@ from copy import deepcopy from time import sleep import traceback +import ipaddr import ipaddress import os import sys @@ -2115,8 +2116,8 @@ def verify_bgp_attributes( errormsg(str) or True """ - logger.debug("Entering lib API: verify_bgp_attributes()") - for router, rnode in tgen.routers().items(): + logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name)) + for router, rnode in tgen.routers().iteritems(): if router != dut: continue @@ -2194,7 +2195,7 @@ def verify_bgp_attributes( ) return errormsg - logger.debug("Exiting lib API: verify_bgp_attributes()") + logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name)) return True @@ -2550,6 +2551,7 @@ def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None, aspath=None) additional_nexthops_in_required_nhs = [] list1 = [] list2 = [] + found_hops = [] for routerInput in input_dict.keys(): for router, rnode in router_list.items(): if router != dut: @@ -2616,20 +2618,29 @@ def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None, aspath=None) st_found = True found_routes.append(st_rt) - if next_hop: + if next_hop and multi_nh and st_found: if not isinstance(next_hop, list): next_hop = [next_hop] list1 = next_hop - found_hops = [ - rib_r["ip"] - for rib_r in rib_routes_json["routes"][st_rt][0][ - "nexthops" - ] - ] - list2 = found_hops - - missing_list_of_nexthops = set(list2).difference(list1) + for mnh in range( + 0, len(rib_routes_json["routes"][st_rt]) + ): + found_hops.append( + [ + rib_r["ip"] + for rib_r in rib_routes_json["routes"][ + st_rt + ][mnh]["nexthops"] + ] + ) + for mnh in found_hops: + for each_nh_in_multipath in mnh: + list2.append(each_nh_in_multipath) + if found_hops[0]: + missing_list_of_nexthops = set(list2).difference( + list1 + ) additional_nexthops_in_required_nhs = set( list1 ).difference(list2) @@ -2643,17 +2654,37 @@ def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None, aspath=None) st_rt, dut, ) - errormsg = ( - "Nexthop {} is Missing for " - "route {} in RIB of router {}\n".format( - additional_nexthops_in_required_nhs, - st_rt, - dut, - ) - ) return errormsg else: nh_found = True + + elif next_hop and multi_nh is None: + if not isinstance(next_hop, list): + next_hop = [next_hop] + list1 = next_hop + found_hops = [rib_r["ip"] for rib_r in + rib_routes_json["routes"][ + st_rt][0]["nexthops"]] + list2 = found_hops + missing_list_of_nexthops = \ + set(list2).difference(list1) + additional_nexthops_in_required_nhs = \ + set(list1).difference(list2) + + if list2: + if additional_nexthops_in_required_nhs: + logger.info("Missing nexthop %s for route"\ + " %s in RIB of router %s\n", \ + additional_nexthops_in_required_nhs, \ + st_rt, dut) + errormsg=("Nexthop {} is Missing for "\ + "route {} in RIB of router {}\n".format( + additional_nexthops_in_required_nhs, + st_rt, dut)) + return errormsg + else: + nh_found = True + if aspath: found_paths = rib_routes_json["routes"][st_rt][0][ "path" diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index 6c24b6ddbb..cc6e783f9b 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -1156,10 +1156,16 @@ def generate_ips(network, no_of_ips): addr_type = validate_ip_address(start_ip) if addr_type == "ipv4": - start_ip = ipaddress.IPv4Address(frr_unicode(start_ip)) + if start_ip == "0.0.0.0" and mask == 0 and no_of_ips == 1: + ipaddress_list.append("{}/{}".format(start_ip, mask)) + return ipaddress_list + start_ip = ipaddr.IPv4Address(unicode(start_ip)) step = 2 ** (32 - mask) if addr_type == "ipv6": - start_ip = ipaddress.IPv6Address(frr_unicode(start_ip)) + if start_ip == "0::0" and mask == 0 and no_of_ips == 1: + ipaddress_list.append("{}/{}".format(start_ip, mask)) + return ipaddress_list + start_ip = ipaddr.IPv6Address(unicode(start_ip)) step = 2 ** (128 - mask) next_ip = start_ip @@ -2240,6 +2246,51 @@ def shutdown_bringup_interface(tgen, dut, intf_name, ifaceaction=False): interface_set_status(router_list[dut], intf_name, ifaceaction) +def stop_router(tgen, router): + """ + Router's current config would be saved to /tmp/topotest// + for each deamon and router and its deamons would be stopped. + + * `tgen` : topogen object + * `router`: Device under test + """ + + router_list = tgen.routers() + + # Saving router config to /etc/frr, which will be loaded to router + # when it starts + router_list[router].vtysh_cmd("write memory") + + # Stop router + router_list[router].stop() + + +def start_router(tgen, router): + """ + Router will be started and config would be loaded from + /tmp/topotest// for each deamon + + * `tgen` : topogen object + * `router`: Device under test + """ + + logger.debug("Entering lib API: start_router") + + try: + router_list = tgen.routers() + + # Router and its deamons would be started and config would + # be loaded to router for each deamon from /etc/frr + router_list[router].start() + + except Exception as e: + errormsg = traceback.format_exc() + logger.error(errormsg) + return errormsg + + logger.debug("Exiting lib API: start_router()") + + def addKernelRoute( tgen, router, intf, group_addr_range, next_hop=None, src=None, del_action=None ): @@ -3327,7 +3378,12 @@ def verify_prefix_lists(tgen, input_dict): for addr_type in prefix_lists_addr: if not check_address_types(addr_type): continue - + # show ip prefix list + if addr_type == "ipv4": + cmd = "show ip prefix-list" + else: + cmd = "show {} prefix-list".format(addr_type) + show_prefix_list = run_frr_cmd(rnode, cmd) for prefix_list in prefix_lists_addr[addr_type].keys(): if prefix_list in show_prefix_list: errormsg = ( diff --git a/tests/topotests/lib/topojson.py b/tests/topotests/lib/topojson.py index f2fafa5e2a..0e59f90a20 100644 --- a/tests/topotests/lib/topojson.py +++ b/tests/topotests/lib/topojson.py @@ -96,6 +96,7 @@ def build_topo_from_json(tgen, topo): for router in listRouters: topo["routers"][router]["nextIfname"] = 0 + router_count = 0 while listRouters != []: curRouter = listRouters.pop(0) # Physical Interfaces @@ -116,13 +117,14 @@ def build_topo_from_json(tgen, topo): currRouter_lo_json = topo["routers"][curRouter]["links"][destRouterLink] # Loopback interfaces if "type" in data and data["type"] == "loopback": + router_count += 1 if ( "ipv4" in currRouter_lo_json and currRouter_lo_json["ipv4"] == "auto" ): currRouter_lo_json["ipv4"] = "{}{}.{}/{}".format( topo["lo_prefix"]["ipv4"], - number_to_row(curRouter), + router_count, number_to_column(curRouter), topo["lo_prefix"]["v4mask"], ) @@ -132,7 +134,7 @@ def build_topo_from_json(tgen, topo): ): currRouter_lo_json["ipv6"] = "{}{}:{}/{}".format( topo["lo_prefix"]["ipv6"], - number_to_row(curRouter), + router_count, number_to_column(curRouter), topo["lo_prefix"]["v6mask"], ) @@ -167,6 +169,14 @@ def build_topo_from_json(tgen, topo): destRouter, curRouter, topo["routers"][destRouter]["nextIfname"] ) + # add link interface + destRouter_link_json["peer-interface"] = "{}-{}-eth{}".format( + curRouter, destRouter, topo["routers"][curRouter]["nextIfname"] + ) + currRouter_link_json["peer-interface"] = "{}-{}-eth{}".format( + destRouter, curRouter, topo["routers"][destRouter]["nextIfname"] + ) + topo["routers"][curRouter]["nextIfname"] += 1 topo["routers"][destRouter]["nextIfname"] += 1 diff --git a/tests/topotests/static_routing_with_ebgp/static_routes_topo1_ebgp.json b/tests/topotests/static_routing_with_ebgp/static_routes_topo1_ebgp.json new file mode 100644 index 0000000000..9d337f6cdf --- /dev/null +++ b/tests/topotests/static_routing_with_ebgp/static_routes_topo1_ebgp.json @@ -0,0 +1,145 @@ +{ + "address_types": [ + "ipv4", + "ipv6" + ], + "ipv4base": "10.0.0.0", + "ipv4mask": 30, + "ipv6base": "fd00::", + "ipv6mask": 64, + "link_ip_start": { + "ipv4": "10.0.0.0", + "v4mask": 30, + "ipv6": "fd00::", + "v6mask": 64 + }, + "lo_prefix": { + "ipv4": "1.0.", + "v4mask": 32, + "ipv6": "2001:db8:f::", + "v6mask": 128 + }, + "routers": { + "r1": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link1": { + "ipv4": "auto", + "ipv6": "auto" + } + } + }, + "r2": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r1-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2": {} + } + } + } + } + } + } + } + }, + "r3": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link1": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "200", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3": {} + } + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/tests/topotests/static_routing_with_ebgp/static_routes_topo2_ebgp.json b/tests/topotests/static_routing_with_ebgp/static_routes_topo2_ebgp.json new file mode 100644 index 0000000000..fc849d807c --- /dev/null +++ b/tests/topotests/static_routing_with_ebgp/static_routes_topo2_ebgp.json @@ -0,0 +1,267 @@ +{ + "address_types": [ + "ipv4", + "ipv6" + ], + "ipv4base": "10.0.0.0", + "ipv4mask": 30, + "ipv6base": "fd00::", + "ipv6mask": 64, + "link_ip_start": { + "ipv4": "10.0.0.0", + "v4mask": 30, + "ipv6": "fd00::", + "v6mask": 64 + }, + "lo_prefix": { + "ipv4": "1.0.", + "v4mask": 32, + "ipv6": "2001:db8:f::", + "v6mask": 128 + }, + "routers": { + "r1": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link4": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link5": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link6": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link7": { + "ipv4": "auto", + "ipv6": "auto" + } + } + }, + "r2": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r1-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link4": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link5": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link6": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link7": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link4": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link5": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link6": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link7": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "200", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link0": {}, + "r2-link1": {}, + "r2-link2": {}, + "r2-link3": {}, + "r2-link4": {}, + "r2-link5": {}, + "r2-link6": {}, + "r2-link7": {} + } + } + }, + "redistribute": [{ + "redist_type": "static" + }] + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link0": {}, + "r2-link1": {}, + "r2-link2": {}, + "r2-link3": {}, + "r2-link4": {}, + "r2-link5": {}, + "r2-link6": {}, + "r2-link7": {} + } + } + }, + "redistribute": [{ + "redist_type": "static" + }] + } + } + } + } + }, + "r3": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link4": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link5": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link6": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link7": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "300", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3-link0": {}, + "r3-link1": {}, + "r3-link2": {}, + "r3-link3": {}, + "r3-link4": {}, + "r3-link5": {}, + "r3-link6": {}, + "r3-link7": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3-link0": {}, + "r3-link1": {}, + "r3-link2": {}, + "r3-link3": {}, + "r3-link4": {}, + "r3-link5": {}, + "r3-link6": {}, + "r3-link7": {} + } + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/tests/topotests/static_routing_with_ebgp/static_routes_topo3_ebgp.json b/tests/topotests/static_routing_with_ebgp/static_routes_topo3_ebgp.json new file mode 100644 index 0000000000..7c1d7f8793 --- /dev/null +++ b/tests/topotests/static_routing_with_ebgp/static_routes_topo3_ebgp.json @@ -0,0 +1,177 @@ +{ + "address_types": [ + "ipv4", + "ipv6" + ], + "ipv4base": "10.0.0.0", + "ipv4mask": 30, + "ipv6base": "fd00::", + "ipv6mask": 64, + "link_ip_start": { + "ipv4": "10.0.0.0", + "v4mask": 29, + "ipv6": "fd00::", + "v6mask": 64 + }, + "lo_prefix": { + "ipv4": "1.0.", + "v4mask": 32, + "ipv6": "2001:db8:f::", + "v6mask": 128 + }, + "routers": { + "r1": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link4": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link5": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link6": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link7": { + "ipv4": "auto", + "ipv6": "auto" + } + } + }, + "r2": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r1-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link4": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link5": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link6": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link7": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link0": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link0": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link0": {} + } + } + } + } + } + } + } + }, + "r3": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2-link0": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "200", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3-link0": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3-link0": {} + } + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/tests/topotests/static_routing_with_ebgp/static_routes_topo4_ebgp.json b/tests/topotests/static_routing_with_ebgp/static_routes_topo4_ebgp.json new file mode 100644 index 0000000000..bb72578ff3 --- /dev/null +++ b/tests/topotests/static_routing_with_ebgp/static_routes_topo4_ebgp.json @@ -0,0 +1,428 @@ +{ + "address_types": [ + "ipv4", + "ipv6" + ], + "ipv4base": "10.0.0.0", + "ipv4mask": 30, + "ipv6base": "fd00::", + "ipv6mask": 64, + "link_ip_start": { + "ipv4": "10.0.0.0", + "v4mask": 30, + "ipv6": "fd00::", + "v6mask": 64 + }, + "lo_prefix": { + "ipv4": "1.0.", + "v4mask": 32, + "ipv6": "2001:db8:f::", + "v6mask": 128 + }, + "routers": { + "r1": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "vm4": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link0": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r1-link1": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r1-link2": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r1-link3": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link0": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r1-link1": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r1-link2": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r1-link3": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + } + } + } + } + } + } + } + } + }, + "r2": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r1-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "vm1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "vm2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "vm3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "vm6": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link3": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "200", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link0": { + "password": "r1" + }, + "r2-link1": { + "password": "r1" + }, + "r2-link2": { + "password": "r1" + }, + "r2-link3": { + "password": "r1" + } + } + }, + "r3": { + "dest_link": { + "r2-link0": { + "password": "r1" + }, + "r2-link1": { + "password": "r1" + }, + "r2-link2": { + "password": "r1" + }, + "r2-link3": { + "password": "r1" + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link0": { + "password": "r1" + }, + "r2-link1": { + "password": "r1" + }, + "r2-link2": { + "password": "r1" + }, + "r2-link3": { + "password": "r1" + } + } + }, + "r3": { + "dest_link": { + "r2-link0": { + "password": "r1" + }, + "r2-link1": { + "password": "r1" + }, + "r2-link2": { + "password": "r1" + }, + "r2-link3": { + "password": "r1" + } + } + } + } + } + } + } + } + }, + "r3": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "vm5": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "300", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3-link0": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r3-link1": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r3-link2": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r3-link3": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3-link0": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r3-link1": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r3-link2": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r3-link3": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + } + } + } + } + } + } + } + } + }, + "vm1": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + } + } + }, + "vm2": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + } + } + }, + "vm3": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + } + } + }, + "vm4": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r1": { + "ipv4": "auto", + "ipv6": "auto" + } + } + }, + "vm5": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r3": { + "ipv4": "auto", + "ipv6": "auto" + } + } + }, + "vm6": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + } + } + } + } +} \ No newline at end of file diff --git a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo1_ebgp.py b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo1_ebgp.py new file mode 100644 index 0000000000..7a31ec53c8 --- /dev/null +++ b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo1_ebgp.py @@ -0,0 +1,1343 @@ +#!/usr/bin/python + +# +# Copyright (c) 2020 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. +# +""" + + -Verify static route ECMP functionality with 2 next hop. + + -Verify static route functionality with 2 next hop and different AD + value. + + -Verify RIB status when same route advertise via BGP and static route. + +""" +import sys +import json +import time +import os +import pytest +import ipaddr +from time import sleep + +# 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/")) +# pylint: disable=C0413 +# Import topogen and topotest helpers +from mininet.topo import Topo +from lib.topogen import Topogen, get_topogen + +# Import topoJson from lib, to create topology and initial configuration +from lib.common_config import ( + start_topology, + write_test_header, + write_test_footer, + reset_config_on_routers, + verify_rib, + create_static_routes, + check_address_types, + step, + create_interfaces_cfg, + shutdown_bringup_interface, + stop_router, + start_router, +) +from lib.topolog import logger +from lib.bgp import verify_bgp_convergence, create_router_bgp, 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 = "{}/static_routes_topo1_ebgp.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 variables +BGP_CONVERGENCE = False +ADDR_TYPES = check_address_types() +NETWORK = {"ipv4": ["11.0.20.1/32", "11.0.20.2/32"], "ipv6": ["2::1/128", "2::2/128"]} +NETWORK2 = {"ipv4": "11.0.20.1/32", "ipv6": "2::1/128"} + +PREFIX1 = {"ipv4": "110.0.20.1/32", "ipv6": "20::1/128"} + + +class CreateTopo(Topo): + """ + Test CreateTopo - 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 + """ + global topo + 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) + + # Checking BGP convergence + global BGP_CONVERGENCE + global ADDR_TYPES + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + # Api call verify whether BGP is converged + 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(mod): + """ + Teardown the pytest environment. + + * `mod`: module name + """ + + 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) + + +def populate_nh(): + NEXT_HOP_IP = { + "nh1": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link0"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link0"]["ipv6"].split("/")[0], + }, + "nh2": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link1"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link1"]["ipv6"].split("/")[0], + }, + } + return NEXT_HOP_IP + + +##################################################### +# +# Testcases +# +##################################################### + + +def test_static_route_2nh_p0_tc_1_ebgp(request): + """ + Verify static route ECMP functionality with 2 next hop. + + """ + 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 ) and N2 (29.1.1.2) , Static route next-hop present on" + "R1" + ) + step("ex :- ip route 10.1.1.1/24 28.1.1.2 & ip route 10.1.1.1/24 29.1.1.1") + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + }, + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh2"][addr_type], + }, + ] + } + } + + 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 ECMP next hop " + ) + nh = [NEXT_HOP_IP["nh1"][addr_type], NEXT_HOP_IP["nh2"][addr_type]] + dut = "r2" + protocol = "static" + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol + ) + assert ( + result is True + ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name) + + step("Configure IBGP IPv4 peering between R2 and R3 router.") + 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") + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "delete": True, + } + ] + } + } + 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, after removing the static route with N1 , " + "route become active with nexthop N2 and vice versa." + ) + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert ( + result is not True + ), "Testcase {} : Failed" "Error: Routes is still present in RIB".format( + tc_name + ) + + nh = [NEXT_HOP_IP["nh2"][addr_type]] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, 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 N1") + + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + } + ] + } + } + + 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("Remove the static route configured with nexthop N2 from" "running config") + + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh2"][addr_type], + "delete": True, + } + ] + } + } + + 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, 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, + input_dict_4, + 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, input_dict_4, 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") + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh2"][addr_type], + } + ] + } + } + + 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("Shut nexthop interface N1") + intf = topo["routers"]["r2"]["links"]["r1-link0"]["interface"] + + shutdown_bringup_interface(tgen, dut, intf, False) + + step("Only one the nexthops should be active in RIB.") + + nh = NEXT_HOP_IP["nh2"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \nError: Routes is" + " missing in RIB".format(tc_name) + + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes is" + " still present in RIB".format(tc_name) + + dut = "r3" + result = verify_bgp_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + protocol=protocol, + next_hop=nh, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + dut = "r2" + nh = [NEXT_HOP_IP["nh2"][addr_type]] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \nError: Routes is" + " missing in RIB".format(tc_name) + + dut = "r3" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Route is" + " missing in RIB".format(tc_name) + + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + dut = "r2" + 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], NEXT_HOP_IP["nh2"][addr_type]] + + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol + ) + 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"] + dut = "r2" + 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, + input_dict_4, + 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]] + dut = "r2" + protocol = "static" + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \nError: Routes is" + " missing in RIB".format(tc_name) + + dut = "r3" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Route is" + " missing in RIB".format(tc_name) + + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + step("No shut nexthop interface N2") + dut = "r2" + 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], NEXT_HOP_IP["nh2"][addr_type]] + + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \nError: Routes is" + " missing in RIB".format(tc_name) + + dut = "r3" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Route is" + " missing in RIB".format(tc_name) + + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + step("Reload the FRR router") + # stop/start -> restart FRR router and verify + stop_router(tgen, "r2") + sleep(5) + start_router(tgen, "r2") + + dut = "r2" + step( + "After reload of FRR router , static route installed" + " in RIB and FIB properly ." + ) + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \nError: Routes is" + " missing in RIB".format(tc_name) + + dut = "r3" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + write_test_footer(tc_name) + + +def test_static_route_2nh_admin_dist_p0_tc_2_ebgp(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], + "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], + "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") + sleep(5) + 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) + + +def test_same_rte_from_bgp_static_p0_tc5_ebgp(request): + """ + Verify RIB status when same route advertise via BGP and static + route + + """ + 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 EBGP IPv4 peering between R2 and R3 router.") + + step( + "Configure IPv4 static route (10.1.1.1/24) in R2 with next hop" + "N1 (28.1.1.2 ) and N2 (29.1.1.2) , Static route next-hop present" + "on R1" + ) + + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + }, + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh2"][addr_type], + }, + ] + } + } + 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("Configure redistribute static in BGP.") + for addr_type in ADDR_TYPES: + 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("Verify on R3 , route receive on R3 BGP table ") + dut = "r3" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + step("Verify route installed in the RIB and FIB of R3") + protocol = "bgp" + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + step( + "Configure 2 links/interfaces between R1 and R3 , keep one" + "interface in shut (active) state and other interface in no shut" + "(inactive) state" + ) + dut = "r3" + intf = topo["routers"]["r3"]["links"]["r1-link0"]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + + step( + "Configure same static route (10.1.1.1/24) in R3 with inactive" + "nexthop interface" + ) + + step( + "Configure same static route 10.1.1.1/24) again in R3 with" + "active nexthop interface" + ) + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r3": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": topo["routers"]["r1"]["links"]["r3-link0"][ + addr_type + ], + }, + { + "network": NETWORK[addr_type], + "next_hop": topo["routers"]["r1"]["links"]["r3-link1"][ + addr_type + ], + }, + ] + } + } + 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( + "Verify when static route configure with inactive nexthop , " + "verify BGP received route is active in the RIB and FIB" + ) + dut = "r3" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Route is" + " missing in BGP RIB".format(tc_name) + + protocol = "bgp" + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Route is" + " missing in RIB".format(tc_name) + + step("Remove the redistribute static knob from R2 router") + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "redistribute": [ + {"redist_type": "static", "delete": True} + ] + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "After removing /adding the redistribute static knob , " + "BGP received route is deleted and added in RIB of R3 " + ) + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + }, + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh2"][addr_type], + }, + ] + } + } + dut = "r3" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is not True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + protocol = "bgp" + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + step("Configure the redistribute static knob again on R2 router") + for addr_type in ADDR_TYPES: + 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 + ) + dut = "r3" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Route is" + " missing in BGP RIB".format(tc_name) + + protocol = "bgp" + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Route is" + " missing in RIB".format(tc_name) + + step("Remove the static route on R3 configured with active" "interface") + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r3": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": topo["routers"]["r1"]["links"]["r3-link0"][ + addr_type + ], + "delete": True, + }, + { + "network": NETWORK[addr_type], + "next_hop": topo["routers"]["r1"]["links"]["r3-link1"][ + addr_type + ], + "delete": True, + }, + ] + } + } + 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( + "After removing the static route with active nexthop verify " + "BGP received route is became active in RIB and FIB" + ) + dut = "r3" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Route is" + " missing in BGP RIB".format(tc_name) + + protocol = "bgp" + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Route is" + " missing in RIB".format(tc_name) + + write_test_footer(tc_name) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py new file mode 100644 index 0000000000..e9ca4d7ae3 --- /dev/null +++ b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py @@ -0,0 +1,2338 @@ +#!/usr/bin/python + +# +# Copyright (c) 2020 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. +# + + +""" + -Verify static route functionality with 8 next hop different AD value + and BGP ECMP + + -Verify 8 static route functionality with 8 next hop different AD + + -Verify static route with 8 next hop with different AD value and 8 + EBGP neighbors + + -Verify static route with 8 next hop with different AD value and 8 + IBGP neighbors + + -Delete the static route and verify the RIB and FIB state + + -Verify 8 static route functionality with 8 ECMP next hop +""" +import sys +import json +import time +import os +import pytest +import ipaddr +from time import sleep +from copy import deepcopy +import random + +# 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/")) +# pylint: disable=C0413 +# Import topogen and topotest helpers +from mininet.topo import Topo +from lib.topogen import Topogen, get_topogen + +# Import topoJson from lib, to create topology and initial configuration +from lib.common_config import ( + start_topology, + write_test_header, + write_test_footer, + reset_config_on_routers, + verify_rib, + create_static_routes, + check_address_types, + step, + create_interfaces_cfg, + shutdown_bringup_interface, + stop_router, + start_router, +) +from lib.topolog import logger +from lib.bgp import verify_bgp_convergence, create_router_bgp, 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 = "{}/static_routes_topo2_ebgp.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 variables +BGP_CONVERGENCE = False +ADDR_TYPES = check_address_types() +NETWORK = { + "ipv4": [ + "11.0.20.1/32", + "11.0.20.2/32", + "11.0.20.3/32", + "11.0.20.4/32", + "11.0.20.5/32", + "11.0.20.6/32", + "11.0.20.7/32", + "11.0.20.8/32", + ], + "ipv6": [ + "2::1/128", + "2::2/128", + "2::3/128", + "2::4/128", + "2::5/128", + "2::6/128", + "2::7/128", + "2::8/128", + ], +} +PREFIX1 = {"ipv4": "110.0.20.1/32", "ipv6": "20::1/128"} +PREFIX2 = {"ipv4": "110.0.20.2/32", "ipv6": "20::2/128"} +NEXT_HOP_IP = [] +topo_diag = """ + Please view in a fixed-width font such as Courier. + +------+ +------+ +------+ + | +--------------+ +--------------+ | + | | | | | | + | R1 +---8 links----+ R2 +---8 links----+ R3 | + | | | | | | + | +--------------+ +--------------+ | + +------+ +------+ +------+ + +""" + + +class CreateTopo(Topo): + """ + Test CreateTopo - 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): + """ + + Set up the pytest environment. + + * `mod`: module name + """ + global topo + 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) + + # Checking BGP convergence + global BGP_CONVERGENCE + global ADDR_TYPES + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + # Api call verify whether BGP is converged + 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(mod): + """ + Teardown the pytest environment + + * `mod`: module name + """ + + 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) + + +def populate_nh(): + NEXT_HOP_IP = { + "nh1": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link0"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link0"]["ipv6"].split("/")[0], + }, + "nh2": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link1"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link1"]["ipv6"].split("/")[0], + }, + "nh3": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link2"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link2"]["ipv6"].split("/")[0], + }, + "nh4": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link3"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link3"]["ipv6"].split("/")[0], + }, + "nh5": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link4"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link4"]["ipv6"].split("/")[0], + }, + "nh6": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link5"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link5"]["ipv6"].split("/")[0], + }, + "nh7": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link6"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link6"]["ipv6"].split("/")[0], + }, + "nh8": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link7"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link7"]["ipv6"].split("/")[0], + }, + } + return NEXT_HOP_IP + + +##################################################### +# +# Testcases +# +##################################################### + + +def test_static_rte_with_8ecmp_nh_p1_tc9_ebgp(request): + """ + Verify 8 static route functionality with 8 ECMP next hop + + """ + 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) + NEXT_HOP_IP = populate_nh() + step("Configure 8 interfaces / links between R1 and R2") + step("Configure 8 interfaces / links between R2 and R3") + step("Configure 8 IBGP IPv4 peering between R2 and R3 router.") + reset_config_on_routers(tgen) + + step( + "Configure 8 IPv4 static route in R2 with 8 next hop" + "N1(21.1.1.2) , N2(22.1.1.2) , N3(23.1.1.2) , N4(24.1.1.2) ," + "N5(25.1.1.2) , N6(26.1.1.2) , N7(27.1.1.2) , N8(28.1.1.2) ," + "Static route next-hop present on R1" + ) + nh_all = {} + for addr_type in ADDR_TYPES: + # Enable static routes + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + } + ] + } + } + 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 + ) + logger.info("Verifying %s routes on r2", addr_type) + nh_all[addr_type] = [ + NEXT_HOP_IP["nh1"][addr_type], + NEXT_HOP_IP["nh2"][addr_type], + NEXT_HOP_IP["nh3"][addr_type], + NEXT_HOP_IP["nh4"][addr_type], + NEXT_HOP_IP["nh5"][addr_type], + NEXT_HOP_IP["nh6"][addr_type], + NEXT_HOP_IP["nh7"][addr_type], + NEXT_HOP_IP["nh8"][addr_type], + ] + + dut = "r2" + protocol = "static" + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh_all[addr_type], + protocol=protocol, + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + step("Configure redistribute static in BGP on R2 router") + for addr_type in ADDR_TYPES: + 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 + ) + + dut = "r3" + protocol = "bgp" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + step( + "Remove the static route configured with nexthop N1 to N8, one" + "by one from running config" + ) + dut = "r2" + protocol = "static" + step( + "After removing the static route with N1 to N8 one by one , " + "verify that entry is removed from RIB and FIB of R3 " + ) + for addr_type in ADDR_TYPES: + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "delete": True, + } + ] + } + } + 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( + "After removing the static route with N1 to N8 one by one , " + "verify that entry is removed from RIB and FIB of R3 " + ) + nh = NEXT_HOP_IP["nh" + str(nhp)][addr_type] + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed\nError: Routes is" + " still present in RIB".format(tc_name) + + step("Configure the static route with nexthop N1 to N8, one by one") + for addr_type in ADDR_TYPES: + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + } + ] + } + } + 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 + ) + + nh = NEXT_HOP_IP["nh" + str(nhp)][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed\nError: Routes are" + " missing in RIB".format(tc_name) + + dut = "r2" + protocol = "static" + step("Shut nexthop interfaces N1 to N3 one by one") + for intfr in range(0, 3): + intf = topo["routers"]["r2"]["links"]["r1-link{}".format(intfr)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + for addr_type in ADDR_TYPES: + nhp = intfr + 1 + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + } + ] + } + } + nh = NEXT_HOP_IP["nh" + str(nhp)][addr_type] + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {}: Failed\nError: Routes are" + " still present in RIB".format(tc_name) + + step("No shut the nexthop interfaces N1 to N3 one by one .") + for intfr in range(0, 3): + intf = topo["routers"]["r2"]["links"]["r1-link{}".format(intfr)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, True) + for addr_type in ADDR_TYPES: + nhp = intfr + 1 + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + } + ] + } + } + nh = NEXT_HOP_IP["nh" + str(nhp)][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + step("Random shut of the nexthop interfaces") + randnum = random.randint(0, 7) + # Shutdown interface + dut = "r2" + step( + " interface which is about to be shut no shut between r1 and r2 is " "%s", + topo["routers"]["r2"]["links"]["r1-link{}".format(randnum)]["interface"], + ) + intf = topo["routers"]["r2"]["links"]["r1-link{}".format(randnum)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + + sleep(5) + + step("Random no shut of the nexthop interfaces") + # Bringup interface + shutdown_bringup_interface(tgen, dut, intf, True) + + step( + "After random shut/no shut of nexthop , only that " + "nexthop deleted/added from all the routes , other nexthop remain " + "unchanged" + ) + dut = "r2" + protocol = "static" + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + } + ] + } + } + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh_all[addr_type], + protocol=protocol, + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + step("Remove random static route with all the nexthop") + dut = "r2" + randnum = random.randint(1, 7) + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(randnum)][addr_type], + "delete": True, + } + ] + } + } + 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( + "After delete of random route , that route only got deleted from" + " RIB/FIB other route are showing properly" + ) + nh = NEXT_HOP_IP["nh{}".format(randnum)][addr_type] + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(randnum)][addr_type], + } + ] + } + } + 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("Reload the FRR router") + # stop/start -> restart FRR router and verify + stop_router(tgen, "r2") + sleep(5) + start_router(tgen, "r2") + + step( + "After reload of FRR router , static route " + "installed in RIB and FIB properly ." + ) + for addr_type in ADDR_TYPES: + # Enable static routes + nhp = 1 + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + } + ] + } + } + logger.info("Verifying %s routes on r2", addr_type) + dut = "r2" + protocol = "static" + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh_all[addr_type], + protocol=protocol, + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + step( + "Remove and add the IBGP nbrs using interface shut and" + "deactivate/activate from address family" + ) + + for intfr in range(0, 8): + intf = topo["routers"]["r2"]["links"]["r3-link{}".format(intfr)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + + sleep(200) + + step("verify bgp convergence as all interface are shut") + + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is not True, "Testcase {} : Failed" + " \n Error: {}".format(tc_name, bgp_convergence) + + dut = "r3" + protocol = "static" + for addr_type in ADDR_TYPES: + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + } + ] + } + } + nh = NEXT_HOP_IP["nh" + str(nhp)][addr_type] + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " still present in RIB".format(tc_name) + dut = "r2" + for intfr in range(0, 8): + intf = topo["routers"]["r2"]["links"]["r3-link{}".format(intfr)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, True) + + step("verify bgp convergence as all interface are un shut") + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is True, "Testcase {} :" + " Failed \n Error: {}".format(tc_name, bgp_convergence) + + step("Remove the redistribute static knob") + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "redistribute": [ + {"redist_type": "static", "delete": True} + ] + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "After removing the BGP neighbor or redistribute static knob , " + "verify route got clear from RIB and FIB of R3 routes " + ) + dut = "r3" + protocol = "bgp" + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " still present in RIB".format(tc_name) + + write_test_footer(tc_name) + + +def test_static_route_8nh_diff_AD_bgp_ecmp_p1_tc6_ebgp(request): + """ + Verify static route functionality with 8 next hop different AD + value and BGP ECMP + + """ + 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) + + step("Configure 8 interfaces / links between R1 and R2 ,") + step("Configure 8 interlaces/links between R2 and R3") + step( + "Configure IBGP IPv4 peering over loopback interface between" + "R2 and R3 router." + ) + step("Configure redistribute static in BGP on R2 router") + reset_config_on_routers(tgen) + NEXT_HOP_IP = populate_nh() + nh_all = {} + for addr_type in ADDR_TYPES: + nh_all[addr_type] = [] + for nhp in range(1, 9): + nh_all[addr_type].append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + step( + "Configure IPv4 static route in R2 with 8 next hop" + "N1(21.1.1.2) AD 10, N2(22.1.1.2) AD 20, N3(23.1.1.2) AD 30," + "N4(24.1.1.2) AD 40, N5(25.1.1.2) AD 50, N6(26.1.1.2) AD 60," + "N7(27.1.1.2) AD 70, N8(28.1.1.2) AD 80, Static route next-hop" + "present on R1" + ) + for addr_type in ADDR_TYPES: + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + } + ] + } + } + 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 + ) + logger.info("Verifying %s routes on r2", addr_type) + + step( + "On R2, static route installed in RIB using " + "show ip route with 8 next hop , lowest AD nexthop is active" + ) + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + nh = [] + for nhp in range(2, 9): + nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + wait=2, + attempts=3, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " are missing in RIB".format(tc_name) + + step( + "Remove the static route configured with nexthop N1 to N8, one" + "by one from running config" + ) + + for addr_type in ADDR_TYPES: + # delete static routes + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + "delete": True, + } + ] + } + } + + 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( + "After removing the static route with N1 to N8 one by one , " + "route become active with next preferred nexthop and nexthop which " + "got removed is not shown in RIB and FIB" + ) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh_all[addr_type], + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " still present in RIB".format(tc_name) + + step("Configure the static route with nexthop N1 to N8, one by one") + + for addr_type in ADDR_TYPES: + # add static routes + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + } + ] + } + } + 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( + " After configuring them, route is always active with lowest AD" + " value and all the nexthop populated in RIB and FIB again" + ) + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + nh = [] + for nhp in range(2, 9): + nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + wait=2, + attempts=3, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " are missing in RIB".format(tc_name) + + step("Shut nexthop interfaces N1 to N8 one by one") + for addr_type in ADDR_TYPES: + for nhp in range(0, 8): + intf = topo["routers"]["r2"]["links"]["r1-link" + str(nhp)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh_all[addr_type], + protocol=protocol, + fib=True, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " are still present in RIB".format(tc_name) + + step("No shut the nexthop interfaces N1 to N3 one by one .") + for addr_type in ADDR_TYPES: + for nhp in range(0, 3): + intf = topo["routers"]["r2"]["links"]["r1-link" + str(nhp)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, True) + + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + nh = [] + for nhp in range(2, 9): + nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + wait=2, + attempts=3, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " are missing in RIB".format(tc_name) + + step("Random shut of the nexthop interfaces") + randnum = random.randint(0, 7) + for addr_type in ADDR_TYPES: + intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type] + input_dict_5 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type], + } + ] + } + } + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_5, + next_hop=nhip, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + + step("Random no shut of the nexthop interfaces") + for addr_type in ADDR_TYPES: + intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, True) + nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_5, next_hop=nhip, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \n" + "Error: Routes are missing in RIB".format(tc_name) + + dut = "r2" + step("Shut the interfaces connected between R2 and R3 one by one") + for nhp in range(0, 3): + intf = topo["routers"]["r2"]["links"]["r3-link" + str(nhp)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + + protocol = "bgp" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + + step("No shut the interfaces between R2 and R3 one by one") + dut = "r2" + for nhp in range(0, 3): + intf = topo["routers"]["r2"]["links"]["r3-link" + str(nhp)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, True) + step( + "After each interface shut and no shut between R2 -R3 ,verify static" + "route is present in the RIB & FIB of R3 & R2 RIB/FIB is remain" + " unchanged" + ) + protocol = "static" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, "Testcase {} : Failed \n" + "Error: Routes are missing in RIB".format(tc_name) + + protocol = "static" + dut = "r2" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert ( + result is True + ), "Testcase {}: Failed \n " "Error: Routes are missing in RIB".format(tc_name) + + protocol = "bgp" + dut = "r3" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert ( + result is True + ), "Testcase {}: Failed \n " "Error: Routes are missing in RIB".format(tc_name) + + step("Reload the FRR router") + # stop/start -> restart FRR router and verify + stop_router(tgen, "r2") + sleep(5) + start_router(tgen, "r2") + + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, ( + "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + ) + + step("BGP neighbor remove and add") + for rtr in ["r2", "r3"]: + if "bgp" in topo["routers"][rtr].keys(): + delete_bgp = {rtr: {"bgp": {"delete": True}}} + result = create_router_bgp(tgen, topo, delete_bgp) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + create_router_bgp(tgen, topo["routers"]) + + NEXT_HOP_IP = populate_nh() + step("Verify routes are still present after delete and add bgp") + dut = "r2" + protocol = "static" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, ( + "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + ) + + dut = "r3" + protocol = "bgp" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, ( + "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + ) + + step("Remove the redistribute static knob") + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "redistribute": [ + {"redist_type": "static", "delete": True} + ] + } + } + } + } + } + } + + logger.info("Remove redistribute static") + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + step("verify that routes are deleted from R3 routing table") + + dut = "r3" + protocol = "bgp" + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " strill present in RIB of R3".format(tc_name) + + write_test_footer(tc_name) + + +def test_static_route_8nh_diff_AD_ebgp_ecmp_p1_tc8_ebgp(request): + """ + Verify static route with 8 next hop with different AD value and 8 + EBGP neighbors + """ + 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) + + step("Configure 8 interfaces / links between R1 and R2") + step("Configure 8 interlaces/links between R2 and R3") + step("Configure 8 EBGP IPv4 peering between R2 and R3") + + reset_config_on_routers(tgen) + NEXT_HOP_IP = populate_nh() + + step("Configure redistribute static in BGP on R2 router") + for addr_type in ADDR_TYPES: + 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( + "Configure IPv4 static route in R2 with 8 next hop" + "N1(21.1.1.2) AD 10, N2(22.1.1.2) AD 20, N3(23.1.1.2) AD 30," + "N4(24.1.1.2) AD 40, N5(25.1.1.2) AD 50, N6(26.1.1.2) AD 60," + "N7(27.1.1.2) AD 70, N8(28.1.1.2) AD 80, Static route next-hop" + "present on R1" + ) + nh_all = {} + for addr_type in ADDR_TYPES: + nh_all[addr_type] = [] + for nhp in range(1, 9): + nh_all[addr_type].append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + for addr_type in ADDR_TYPES: + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + } + ] + } + } + 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 + ) + logger.info("Verifying %s routes on r2", addr_type) + + step( + "On R2, static route installed in RIB using " + "show ip route with 8 next hop , lowest AD nexthop is active" + ) + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + nh = [] + for nhp in range(2, 9): + nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " are missing in RIB".format(tc_name) + + step( + "Remove the static route configured with nexthop N1 to N8, one" + "by one from running config" + ) + + for addr_type in ADDR_TYPES: + # delete static routes + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + "delete": True, + } + ] + } + } + + 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( + "After removing the static route with N1 to N8 one by one , " + "route become active with next preferred nexthop and nexthop which " + "got removed is not shown in RIB and FIB" + ) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh_all[addr_type], + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " still present in RIB".format(tc_name) + + step("Configure the static route with nexthop N1 to N8, one by one") + + for addr_type in ADDR_TYPES: + # add static routes + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + } + ] + } + } + 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( + " After configuring them, route is always active with lowest AD" + " value and all the nexthop populated in RIB and FIB again" + ) + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + nh = [] + for nhp in range(2, 9): + nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " are missing in RIB".format(tc_name) + + step("Shut nexthop interfaces N1 to N8 one by one") + for addr_type in ADDR_TYPES: + for nhp in range(0, 8): + intf = topo["routers"]["r2"]["links"]["r1-link" + str(nhp)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh_all[addr_type], + protocol=protocol, + fib=True, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " are still present in RIB".format(tc_name) + + step("No shut the nexthop interfaces N1 to N8 one by one .") + for addr_type in ADDR_TYPES: + for nhp in range(0, 8): + intf = topo["routers"]["r2"]["links"]["r1-link" + str(nhp)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, True) + + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + nh = [] + for nhp in range(2, 9): + nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " are missing in RIB".format(tc_name) + + step("Random shut of the nexthop interfaces") + randnum = random.randint(0, 7) + for addr_type in ADDR_TYPES: + intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type] + input_dict_5 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type], + } + ] + } + } + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_5, + next_hop=nhip, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + + step("Random no shut of the nexthop interfaces") + for addr_type in ADDR_TYPES: + intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, True) + nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_5, next_hop=nhip, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \n" + "Error: Routes are missing in RIB".format(tc_name) + + dut = "r2" + step("Shut the interfaces connected between R2 and R3 one by one") + for nhp in range(0, 3): + intf = topo["routers"]["r2"]["links"]["r3-link" + str(nhp)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + + protocol = "bgp" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + + step("No shut the interfaces between R2 and R3 one by one") + dut = "r2" + for nhp in range(0, 3): + intf = topo["routers"]["r2"]["links"]["r3-link" + str(nhp)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, True) + + step( + "After each interface shut and no shut between R2 -R3 ,verify static" + "route is present in the RIB & FIB of R3 & R2 RIB/FIB is remain" + " unchanged" + ) + protocol = "static" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, "Testcase {} : Failed \n" + "Error: Routes are missing in RIB".format(tc_name) + + protocol = "static" + dut = "r2" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert ( + result is True + ), "Testcase {}: Failed \n " "Error: Routes are missing in RIB".format(tc_name) + + protocol = "bgp" + dut = "r3" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert ( + result is True + ), "Testcase {}: Failed \n " "Error: Routes are missing in RIB".format(tc_name) + + step("Reload the FRR router") + # stop/start -> restart FRR router and verify + stop_router(tgen, "r2") + sleep(5) + start_router(tgen, "r2") + + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, ( + "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + ) + + step("BGP neighbor remove and add") + for rtr in ["r2", "r3"]: + if "bgp" in topo["routers"][rtr].keys(): + delete_bgp = {rtr: {"bgp": {"delete": True}}} + result = create_router_bgp(tgen, topo, delete_bgp) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + create_router_bgp(tgen, topo["routers"]) + + NEXT_HOP_IP = populate_nh() + step("Verify routes are still present after delete and add bgp") + dut = "r2" + protocol = "static" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, ( + "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + ) + + dut = "r3" + protocol = "bgp" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, ( + "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + ) + + step("Remove the redistribute static knob") + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "redistribute": [ + {"redist_type": "static", "delete": True} + ] + } + } + } + } + } + } + + logger.info("Remove redistribute static") + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + step("verify that routes are deleted from R3 routing table") + + dut = "r3" + protocol = "bgp" + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " still present in RIB of R3".format(tc_name) + + write_test_footer(tc_name) + + +def test_static_route_8nh_diff_AD_bgp_ecmp_p1_tc10_ebgp(request): + """ + Verify 8 static route functionality with 8 next hop different AD' + + """ + 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) + NEXT_HOP_IP = populate_nh() + + step("Configure 8 interfaces / links between R1 and R2 ") + step("Configure 8 IBGP IPv4 peering between R2 and R3 router.") + reset_config_on_routers(tgen) + + step( + "Configure IPv4 static route in R2 with 8 next hop" + "N1(21.1.1.2) AD 10, N2(22.1.1.2) AD 20, N3(23.1.1.2) AD 30," + "N4(24.1.1.2) AD 40, N5(25.1.1.2) AD 50, N6(26.1.1.2) AD 60," + "N7(27.1.1.2) AD 70, N8(28.1.1.2) AD 80" + ) + step( + "Configure nexthop AD in such way for static route S1 , N1 is" + "preferred and for S2 , N2 is preferred and so on .." + ) + nh_all = {} + for addr_type in ADDR_TYPES: + nh_all[addr_type] = [] + for nhp in range(1, 9): + nh_all[addr_type].append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + + for addr_type in ADDR_TYPES: + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + } + ] + } + } + 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 + ) + second_rte = { + "r2": { + "static_routes": [ + { + "network": PREFIX2[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + } + ] + } + } + logger.info("Configure static routes") + result = create_static_routes(tgen, second_rte) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + logger.info("Verifying %s routes on r2", addr_type) + + step( + "On R2, static route installed in RIB using " + "show ip route with 8 next hop , lowest AD nexthop is active" + ) + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + step("Verify that highest AD nexthop are inactive") + nh = [] + for nhp in range(2, 9): + nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + wait=2, + attempts=3, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " are missing in RIB".format(tc_name) + + step("Configure redistribute static in BGP on R2 router") + for addr_type in ADDR_TYPES: + 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 to N8, one" + "by one from running config" + ) + + for addr_type in ADDR_TYPES: + # delete static routes + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + "delete": True, + } + ] + } + } + + 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( + "After removing the static route with N1 to N8 one by one , " + "route become active with next preferred nexthop and nexthop which" + "got removed is not shown in RIB and FIB" + ) + + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " still present in RIB".format(tc_name) + + step("Configure the static route with nexthop N1 to N8, one by one") + for addr_type in ADDR_TYPES: + # add static routes + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + } + ] + } + } + + 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( + " After configuring them, route is always active with lowest AD" + " value and all the nexthop populated in RIB and FIB again" + ) + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type],}]}} + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Route with " + "lowest AD is missing in RIB".format(tc_name) + + step("Shut nexthop interfaces N1 to N3 one by one") + for addr_type in ADDR_TYPES: + for nhp in range(0, 3): + intf = topo["routers"]["r2"]["links"]["r1-link" + str(nhp)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type],}]}} + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + + step("No shut the nexthop interfaces N1 to N3 one by one .") + + for addr_type in ADDR_TYPES: + for nhp in range(0, 3): + intf = topo["routers"]["r2"]["links"]["r1-link" + str(nhp)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, True) + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type],}]}} + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \n" + "Error: Routes are missing in RIB".format(tc_name) + + step("Random shut of the nexthop interfaces") + randnum = random.randint(0, 7) + for addr_type in ADDR_TYPES: + intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type] + input_dict_5 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type], + } + ] + } + } + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_5, + next_hop=nhip, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + + step("Random no shut of the nexthop interfaces") + for addr_type in ADDR_TYPES: + intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, True) + nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_5, next_hop=nhip, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \n" + "Error: Routes are missing in RIB".format(tc_name) + + step("Remove random static route with all the nexthop") + for addr_type in ADDR_TYPES: + # delete static routes + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + "delete": True, + } + ] + } + } + 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( + "After removing the static route with N1 to N8 one by one , " + "route become active with next preferred nexthop and nexthop " + "which got removed is not shown in RIB and FIB" + ) + nh = NEXT_HOP_IP["nh" + str(nhp)][addr_type] + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Route " + " is still present in RIB".format(tc_name) + + step("Reconfigure the deleted routes and verify they are installed") + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + } + ] + } + } + 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 + ) + + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, "Testcase {} : Failed \nError: Route " + " is still present in RIB".format(tc_name) + + step("Reload the FRR router") + # stop/start -> restart FRR router and verify + stop_router(tgen, "r2") + sleep(5) + start_router(tgen, "r2") + + step("After reloading, verify that routes are still present in R2.") + result = verify_rib( + tgen, + addr_type, + dut, + second_rte, + next_hop=nh, + protocol=protocol, + fib=True, + ) + assert result is True, ( + "Testcase {} : Failed \nError: Route " + " is missing in RIB".format(tc_name) + ) + + dut = "r2" + for intfr in range(0, 8): + intf = topo["routers"]["r2"]["links"]["r3-link{}".format(intfr)][ + "interface" + ] + shutdown_bringup_interface(tgen, dut, intf, False) + + dut = "r3" + for intfr in range(0, 8): + intf = topo["routers"]["r3"]["links"]["r2-link{}".format(intfr)][ + "interface" + ] + shutdown_bringup_interface(tgen, dut, intf, False) + sleep(180) + step("verify bgp convergence as all interface are shut") + + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is not True, "Testcase {} : Failed \n" + "Error: {}".format(tc_name, bgp_convergence) + + dut = "r2" + protocol = "static" + for addr_type in ADDR_TYPES: + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + } + ] + } + } + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing present in RIB".format(tc_name) + + dut = "r3" + protocol = "bgp" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type],}]}} + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " are still present in RIB after BGP nbr is down".format(tc_name) + + sleep(5) + dut = "r2" + for intfr in range(0, 8): + intf = topo["routers"]["r2"]["links"]["r3-link{}".format(intfr)][ + "interface" + ] + shutdown_bringup_interface(tgen, dut, intf, True) + + sleep(5) + dut = "r3" + for intfr in range(0, 8): + intf = topo["routers"]["r3"]["links"]["r2-link{}".format(intfr)][ + "interface" + ] + shutdown_bringup_interface(tgen, dut, intf, True) + + step("verify bgp convergence as all interface are un shut") + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is True, "Testcase {} : Failed \n" + "Error: {}".format(tc_name, bgp_convergence) + + step("Remove the redistribute static knob") + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "redistribute": [ + {"redist_type": "static", "delete": True} + ] + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "After removing the BGP neighbor or redistribute static knob , " + "verify route got clear from RIB and FIB of R3 routes " + ) + dut = "r3" + protocol = "bgp" + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + } + ] + } + } + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " still present in RIB".format(tc_name) + + write_test_footer(tc_name) + + +def test_static_route_delete_p0_tc11_ebgp(request): + """ + Delete the static route and verify the RIB and FIB state + """ + 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) + NEXT_HOP_IP = populate_nh() + + step("Configure 8 interfaces / links between R1 and R2 ") + step("Configure 8 IBGP IPv4 peering between R2 and R3 router.") + reset_config_on_routers(tgen) + + step( + "Configure IPv4 static route in R2 with 8 next hop" + "N1(21.1.1.2) AD 10, N2(22.1.1.2) AD 20, N3(23.1.1.2) AD 30," + "N4(24.1.1.2) AD 40, N5(25.1.1.2) AD 50, N6(26.1.1.2) AD 60," + "N7(27.1.1.2) AD 70, N8(28.1.1.2) AD 80" + ) + step( + "Configure nexthop AD in such way for static route S1 , N1 is" + "preferred and for S2 , N2 is preferred and so on .." + ) + nh_all = {} + for addr_type in ADDR_TYPES: + nh_all[addr_type] = [] + for nhp in range(1, 9): + nh_all[addr_type].append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + + for addr_type in ADDR_TYPES: + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + } + ] + } + } + 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 + ) + second_rte = { + "r2": { + "static_routes": [ + { + "network": PREFIX2[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + } + ] + } + } + logger.info("Configure static routes") + result = create_static_routes(tgen, second_rte) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + logger.info("Verifying %s routes on r2", addr_type) + + step( + "On R2, static route installed in RIB using " + "show ip route with 8 next hop , lowest AD nexthop is active" + ) + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + step("Verify that highest AD nexthop are inactive") + nh = [] + for nhp in range(2, 9): + nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " are missing in RIB".format(tc_name) + + step("Configure redistribute static in BGP on R2 router") + for addr_type in ADDR_TYPES: + 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 redistribute static knob") + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "redistribute": [ + {"redist_type": "static", "delete": True} + ] + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "Verify after removing the redistribute static from BGP all the" + "routes got delete from RIB and FIB of R3 " + ) + + dut = "r3" + protocol = "bgp" + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " still present in RIB".format(tc_name) + + for addr_type in ADDR_TYPES: + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + "delete": True, + } + ] + } + } + 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 + ) + second_rte = { + "r2": { + "static_routes": [ + { + "network": PREFIX2[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + } + ] + } + } + logger.info("Configure static routes") + result = create_static_routes(tgen, second_rte) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + logger.info("Verifying %s routes on r2", addr_type) + + step( + " After removing all the routes and nexthop from R2 , " + " verify R2 RIB and FIB is cleared" + ) + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " still active in RIB".format(tc_name) + write_test_footer(tc_name) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo3_ebgp.py b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo3_ebgp.py new file mode 100644 index 0000000000..e055a161c2 --- /dev/null +++ b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo3_ebgp.py @@ -0,0 +1,990 @@ +#!/usr/bin/python + +# +# Copyright (c) 2020 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. +# +""" + -Verify static route ECMP functionality with 8 next hop + + -Verify static route functionality with 8 next hop different AD value + + -Verify static route with tag option + + -Verify BGP did not install the static route when it receive route + with local next hop + +""" +import sys +import json +import time +import os +import pytest +import ipaddr +from time import sleep +from copy import deepcopy +import random +from re import search as re_search + + +# 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/")) +# pylint: disable=C0413 +# Import topogen and topotest helpers +from mininet.topo import Topo +from lib.topogen import Topogen, get_topogen + +from lib.common_config import ( + start_topology, + write_test_header, + write_test_footer, + reset_config_on_routers, + verify_rib, + create_static_routes, + check_address_types, + step, + create_interfaces_cfg, + shutdown_bringup_interface, + stop_router, + start_router, +) +from lib.topolog import logger +from lib.bgp import verify_bgp_convergence, create_router_bgp, 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 = "{}/static_routes_topo3_ebgp.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 variables +BGP_CONVERGENCE = False +ADDR_TYPES = check_address_types() +NETWORK = { + "ipv4": [ + "11.0.20.1/32", + "11.0.20.2/32", + "11.0.20.3/32", + "11.0.20.4/32", + "11.0.20.5/32", + "11.0.20.6/32", + "11.0.20.7/32", + "11.0.20.8/32", + ], + "ipv6": [ + "2::1/128", + "2::2/128", + "2::3/128", + "2::4/128", + "2::5/128", + "2::6/128", + "2::7/128", + "2::8/128", + ], +} +PREFIX1 = {"ipv4": "110.0.20.1/32", "ipv6": "20::1/128"} +NETWORK2 = {"ipv4": ["11.0.20.1/32"], "ipv6": ["2::1/128"]} +NEXT_HOP_IP = [] + + +class CreateTopo(Topo): + """ + Test CreateTopo - 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): + """ + + Set up the pytest environment. + + * `mod`: module name + """ + global topo + 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) + + # Checking BGP convergence + global BGP_CONVERGENCE + global ADDR_TYPES + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + # Api call verify whether BGP is converged + 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(mod): + """ + Teardown the pytest environment + + * `mod`: module name + """ + + 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) + + +def populate_nh(): + NEXT_HOP_IP = { + "nh1": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link0"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link0"]["ipv6"].split("/")[0], + }, + "nh2": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link1"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link1"]["ipv6"].split("/")[0], + }, + "nh3": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link2"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link2"]["ipv6"].split("/")[0], + }, + "nh4": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link3"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link3"]["ipv6"].split("/")[0], + }, + "nh5": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link4"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link4"]["ipv6"].split("/")[0], + }, + "nh6": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link5"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link5"]["ipv6"].split("/")[0], + }, + "nh7": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link6"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link6"]["ipv6"].split("/")[0], + }, + "nh8": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link7"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link7"]["ipv6"].split("/")[0], + }, + } + return NEXT_HOP_IP + + +##################################################### +# +# Tests starting +# +##################################################### + + +def test_staticroute_with_ecmp_p0_tc3_ebgp(request): + """ + Verify static route ECMP functionality with 8 next hop' + + """ + 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 8 interfaces / links between R1 and R2,") + step( + "Configure IPv4 static route in R2 with 8 next hop" + "N1(21.1.1.2), N2(22.1.1.2), N3(23.1.1.2), N4(24.1.1.2)," + "N5(25.1.1.2), N6(26.1.1.2), N7(27.1.1.2),N8(28.1.1.2), Static" + "route next-hop present on R1" + ) + + step("Configure IBGP IPv4 peering between R2 and R3 router.") + + for addr_type in ADDR_TYPES: + # Enable static routes + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + } + ] + } + } + 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 + ) + logger.info("Verifying %s routes on r2", addr_type) + nh = [ + NEXT_HOP_IP["nh1"][addr_type], + NEXT_HOP_IP["nh2"][addr_type], + NEXT_HOP_IP["nh3"][addr_type], + NEXT_HOP_IP["nh4"][addr_type], + NEXT_HOP_IP["nh5"][addr_type], + NEXT_HOP_IP["nh6"][addr_type], + NEXT_HOP_IP["nh7"][addr_type], + NEXT_HOP_IP["nh8"][addr_type], + ] + + dut = "r2" + protocol = "static" + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + step("Configure redistribute static in BGP on R2 router") + for addr_type in ADDR_TYPES: + 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 to N8, one" + "by one from running config" + ) + for addr_type in ADDR_TYPES: + # delete static routes + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "delete": True, + } + ] + } + } + + 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 + ) + + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " still present in RIB".format(tc_name) + + step("Configure the static route with nexthop N1 to N8, one by" "one") + + for addr_type in ADDR_TYPES: + # add static routes + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + } + ] + } + } + + 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 + ) + + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + step("Shut nexthop interfaces N1 to N8 one by one") + for addr_type in ADDR_TYPES: + for nhp in range(0, 8): + intf = topo["routers"]["r2"]["links"]["r1-link" + str(nhp)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + + step("No shut the nexthop interfaces N1 to N8 one by one .") + + for addr_type in ADDR_TYPES: + for nhp in range(0, 8): + intf = topo["routers"]["r2"]["links"]["r1-link" + str(nhp)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, True) + + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \n" + "Error: Routes are missing in RIB".format(tc_name) + + step("Random shut of the nexthop interfaces") + randnum = random.randint(0, 7) + for addr_type in ADDR_TYPES: + intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type] + input_dict_5 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type], + } + ] + } + } + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_5, + next_hop=nhip, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + + step("Random no shut of the nexthop interfaces") + for addr_type in ADDR_TYPES: + intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, True) + nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_5, next_hop=nhip, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \n" + "Error: Routes are missing in RIB".format(tc_name) + + step("Reload the FRR router") + # stop/start -> restart FRR router and verify + stop_router(tgen, "r2") + sleep(5) + start_router(tgen, "r2") + + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + write_test_footer(tc_name) + + +def test_staticroute_with_ecmp_with_diff_AD_p0_tc4_ebgp(request): + """ + Verify static route ECMP functionality with 8 next hop + + """ + 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 8 interfaces / links between R1 and R2,") + step("Configure IBGP IPv4 peering between R2 and R3 router.") + reset_config_on_routers(tgen) + NEXT_HOP_IP = populate_nh() + nh_all = {} + for addr_type in ADDR_TYPES: + nh_all[addr_type] = [] + for nhp in range(1, 9): + nh_all[addr_type].append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + step( + "Configure IPv4 static route in R2 with 8 next hop" + "N1(21.1.1.2) AD 10, N2(22.1.1.2) AD 20, N3(23.1.1.2) AD 30," + "N4(24.1.1.2) AD 40, N5(25.1.1.2) AD 50, N6(26.1.1.2) AD 60," + "N7(27.1.1.2) AD 70, N8(28.1.1.2) AD 80, Static route next-hop" + "present on R1" + ) + for addr_type in ADDR_TYPES: + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + } + ] + } + } + 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 + ) + logger.info("Verifying %s routes on r2", addr_type) + + step( + "On R2, static route installed in RIB using " + "show ip route with 8 next hop, lowest AD nexthop is active" + ) + step("On R2, static route with lowest AD nexthop installed in FIB") + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Route with " + " lowest AD is missing in RIB".format(tc_name) + + nh = [] + for nhp in range(2, 9): + nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " with high AD are active in RIB".format(tc_name) + + step("Configure redistribute static in BGP on R2 router") + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": {"redistribute": [{"redist_type": "static"}]} + } + } + } + } + } + + logger.info("Configuring redistribute static") + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "After configuring them, route is always active with lowest AD" + "value and all the nexthop populated in RIB and FIB again " + ) + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Route with " + " lowest AD is missing in RIB".format(tc_name) + + step( + "Remove the static route configured with nexthop N1 to N8, one" + "by one from running config" + ) + + for addr_type in ADDR_TYPES: + # delete static routes + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + "delete": True, + } + ] + } + } + + 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( + "After removing the static route with N1 to N8 one by one, " + "route become active with next preferred nexthop and nexthop which " + "got removed is not shown in RIB and FIB" + ) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh_all[addr_type], + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " still present in RIB".format(tc_name) + + step("Configure the static route with nexthop N1 to N8, one by" "one") + for addr_type in ADDR_TYPES: + # add static routes + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + } + ] + } + } + 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 with lowest AD nexthop installed in FIB") + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Route with " + " lowest AD is missing in RIB".format(tc_name) + + nh = [] + for nhp in range(2, 9): + nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " with high AD are active in RIB".format(tc_name) + + step("Shut nexthop interfaces N1 to N8 one by one") + for addr_type in ADDR_TYPES: + for nhp in range(0, 8): + intf = topo["routers"]["r2"]["links"]["r1-link" + str(nhp)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh_all[addr_type], + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " are still present in RIB".format(tc_name) + + step("No shut the nexthop interfaces N1 to N8 one by one .") + for addr_type in ADDR_TYPES: + for nhp in range(0, 8): + intf = topo["routers"]["r2"]["links"]["r1-link" + str(nhp)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, True) + + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + nh = [] + for nhp in range(2, 9): + nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " are missing in RIB".format(tc_name) + + step("Random shut of the nexthop interfaces") + randnum = random.randint(0, 7) + for addr_type in ADDR_TYPES: + intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type] + input_dict_5 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type], + } + ] + } + } + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_5, + next_hop=nhip, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + + step("Random no shut of the nexthop interfaces") + for addr_type in ADDR_TYPES: + intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, True) + nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_5, next_hop=nhip, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \n" + "Error: Routes are missing in RIB".format(tc_name) + + step("Reload the FRR router") + # stop/start -> restart FRR router and verify + stop_router(tgen, "r2") + sleep(5) + start_router(tgen, "r2") + + step( + "After reload of FRR router, static route installed " + "in RIB and FIB properly ." + ) + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Route with " + " lowest AD is missing in RIB".format(tc_name) + + nh = [] + for nhp in range(2, 9): + nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " with high AD are active in RIB".format(tc_name) + + step("BGP neighbor remove and add") + for rtr in ["r2", "r3"]: + if "bgp" in topo["routers"][rtr].keys(): + delete_bgp = {rtr: {"bgp": {"delete": True}}} + result = create_router_bgp(tgen, topo, delete_bgp) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + reset_config_on_routers(tgen) + NEXT_HOP_IP = populate_nh() + step("Verify routes are still present after delete and add bgp") + dut = "r3" + protocol = "bgp" + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \n" + "Error: Routes still present in RIB".format(tc_name) + + step("Remove the redistribute static knob") + + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "redistribute": [ + {"redist_type": "static", "delete": True} + ] + } + } + } + } + } + } + + logger.info("Remove redistribute static") + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + step("verify that routes are deleted from R3 routing table") + dut = "r3" + protocol = "bgp" + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " strill present in RIB of R3".format(tc_name) + + write_test_footer(tc_name) + + +def test_bgp_local_nexthop_p1_tc14_ebgp(request): + """ + Verify BGP did not install the static route when it receive route + with local next hop + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + step("Configure BGP IPv4 session between R2 and R3") + step("Configure IPv4 static route on R2") + reset_config_on_routers(tgen) + + for addr_type in ADDR_TYPES: + # Enable static routes + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": topo["routers"]["r3"]["links"]["r2-link0"][ + addr_type + ].split("/")[0], + } + ] + } + } + + 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("Configure redistribute static in the BGP") + + 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("Verify R2 BGP table has IPv4 route") + dut = "r2" + result = verify_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Routes is" + " missing in RIB of R2".format(tc_name) + + step(" Verify route did not install in the R3 BGP table, RIB/FIB") + dut = "r3" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4, expected=False) + assert result is not True, "Testcase {} : Failed \nError: Routes is" + " still present in BGP RIB of R2".format(tc_name) + + result = verify_rib(tgen, addr_type, dut, input_dict_4, expected=False) + assert result is not True, "Testcase {} : Failed \nError: Routes is" + " still present in RIB of R2".format(tc_name) + + write_test_footer(tc_name) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py new file mode 100644 index 0000000000..a0894074c2 --- /dev/null +++ b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py @@ -0,0 +1,989 @@ +#!/usr/bin/python + +# +# Copyright (c) 2020 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 in the script. + +- Verify static route are blocked from route-map and prefix-list + applied in BGP nbrs +- Verify Static route when FRR connected to 2 TOR +""" + +import sys +import json +import time +import os +import pytest +import ipaddr +import ipaddress +from time import sleep +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/")) +# pylint: disable=C0413 +# Import topogen and topotest helpers +from mininet.topo import Topo +from lib.topogen import Topogen, get_topogen + +# Import topoJson from lib, to create topology and initial configuration +from lib.common_config import ( + start_topology, + write_test_header, + write_test_footer, + reset_config_on_routers, + verify_rib, + check_address_types, + step, + create_prefix_lists, + create_route_maps, + create_interfaces_cfg, + verify_prefix_lists, + verify_route_maps, +) +from lib.topolog import logger +from lib.bgp import ( + verify_bgp_convergence, + create_router_bgp, + clear_bgp_and_verify, + clear_bgp, +) +from lib.topojson import build_topo_from_json, build_config_from_json + +# Reading the data from JSON File for topology creation +jsonFile = "{}/static_routes_topo4_ebgp.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 variables +BGP_CONVERGENCE = False +ADDR_TYPES = check_address_types() +NETWORK = {"ipv4": "2.2.2.2/32", "ipv6": "22:22::2/128"} +NEXT_HOP_IP = {} + + +class CreateTopo(Topo): + """ + Test CreateTopo - 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): + """ + Set up the pytest environment. + * `mod`: module name + """ + global topo + 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) + + # Checking BGP convergence + global BGP_CONVERGENCE + global ADDR_TYPES + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + # Api call verify whether BGP is converged + 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(mod): + """ + Teardown the pytest environment. + + * `mod`: module name + """ + 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) + + +##################################################### +# +# Tests starting +# +##################################################### +def test_static_routes_rmap_pfxlist_p0_tc7_ebgp(request): + """ + Verify static route are blocked from route-map & prefix-list applied in BGP + nbrs + + """ + 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) + step("Configure holddown timer = 1 keep alive = 3 in all the neighbors") + step("verify bgp convergence before starting test case") + + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, bgp_convergence + ) + + step( + "Configure 4 IPv4 and 4 IPv6 nbrs with password with mismatch " + " authentication between FRR routers " + ) + + for addr_type in ADDR_TYPES: + # Api call to modfiy BGP timerse + input_dict = { + "r2": { + "bgp": { + "local_as": "200", + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link0": {"password": "r2"}, + "r2-link1": {"password": "r2"}, + "r2-link2": {"password": "r2"}, + "r2-link3": {"password": "r2"}, + } + }, + "r3": { + "dest_link": { + "r2-link0": {"password": "r2"}, + "r2-link1": {"password": "r2"}, + "r2-link2": {"password": "r2"}, + "r2-link3": {"password": "r2"}, + } + }, + } + } + } + }, + } + } + } + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} :Failed \n Error: {}".format( + tc_name, result + ) + clear_bgp(tgen, addr_type, "r2") + + step(" All BGP nbrs are down as authentication is mismatch on both" " the sides") + + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is not True, "Testcase {} : " + "Failed \n BGP nbrs must be down. Error: {}".format(tc_name, bgp_convergence) + + step( + "Configure 4 IPv4 and 4 IPv6 nbrs with macthing password " + " authentication between FRR routers " + ) + for addr_type in ADDR_TYPES: + input_dict = { + "r2": { + "bgp": { + "local_as": "200", + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link0": {"password": "r1"}, + "r2-link1": {"password": "r1"}, + "r2-link2": {"password": "r1"}, + "r2-link3": {"password": "r1"}, + } + }, + "r3": { + "dest_link": { + "r2-link0": {"password": "r1"}, + "r2-link1": {"password": "r1"}, + "r2-link2": {"password": "r1"}, + "r2-link3": {"password": "r1"}, + } + }, + } + } + } + }, + } + } + } + result = create_router_bgp(tgen, topo, deepcopy(input_dict)) + assert result is True, "Testcase {} :Failed \n Error: {}".format( + tc_name, result + ) + + step("All BGP nbrs are up as authentication is matched now") + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is True, "Testcase {} : Failed \n " "Error: {}".format( + tc_name, bgp_convergence + ) + + step("Create prefix list P1 to permit VM3 & deny VM1 v4 & v6 routes") + step("Create prefix list P2 to permit VM6 IPv4 and IPv6 routes") + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r2": { + "prefix_lists": { + addr_type: { + "pf_list_1_{}".format(addr_type): [ + { + "seqid": 10, + "network": topo["routers"]["r2"]["links"]["vm3"][ + addr_type + ], + "action": "permit", + }, + { + "seqid": 20, + "network": topo["routers"]["r2"]["links"]["vm1"][ + addr_type + ], + "action": "deny", + }, + ], + "pf_list_2_{}".format(addr_type): [ + { + "seqid": 10, + "network": topo["routers"]["r2"]["links"]["vm6"][ + addr_type + ], + "action": "permit", + } + ], + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "Prefix list created with matching networks deny or permit " + "show ip prefix list" + ) + result = verify_prefix_lists(tgen, input_dict_2) + assert result is not True, "Testcase {} : Failed \n" + " Error: {}".format(tc_name, result) + + step("Redistribute all the routes (connected, static)") + input_dict_2_r1 = { + "r1": { + "bgp": { + "address_family": { + addr_type: { + "unicast": {"redistribute": [{"redist_type": "static"}]} + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2_r1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + input_dict_2_r2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": {"redistribute": [{"redist_type": "static"}]} + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2_r2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + input_dict_2_r3 = { + "r3": { + "bgp": { + "address_family": { + addr_type: { + "unicast": {"redistribute": [{"redist_type": "static"}]} + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2_r3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("configure redistribute connected in Router BGP") + + input_dict_2_r1 = { + "r1": { + "bgp": { + "address_family": { + addr_type: { + "unicast": {"redistribute": [{"redist_type": "connected"}]} + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2_r1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + input_dict_2_r3 = { + "r3": { + "bgp": { + "address_family": { + addr_type: { + "unicast": {"redistribute": [{"redist_type": "connected"}]} + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2_r3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + input_dict_2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": {"redistribute": [{"redist_type": "connected"}]} + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Apply prefix list P1 on BGP neighbors 1 2 3 4 connected from " "frr r1") + # Configure prefix list to bgp neighbor + input_dict_4 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link0": { + "prefix_lists": [ + { + "name": "pf_list_1_{}".format( + addr_type + ), + "direction": "out", + } + ] + }, + "r2-link1": { + "prefix_lists": [ + { + "name": "pf_list_1_{}".format( + addr_type + ), + "direction": "out", + } + ] + }, + "r2-link2": { + "prefix_lists": [ + { + "name": "pf_list_1_{}".format( + addr_type + ), + "direction": "out", + } + ] + }, + "r2-link3": { + "prefix_lists": [ + { + "name": "pf_list_1_{}".format( + addr_type + ), + "direction": "out", + } + ] + }, + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Apply prefix list P2 on BGP nbrs 5 & 6 connected from FRR-2") + # Configure prefix list to bgp neighbor + input_dict_4 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link0": { + "prefix_lists": [ + { + "name": "pf_list_2_{}".format( + addr_type + ), + "direction": "out", + } + ] + }, + "r2-link1": { + "prefix_lists": [ + { + "name": "pf_list_2_{}".format( + addr_type + ), + "direction": "out", + } + ] + }, + "r2-link2": { + "prefix_lists": [ + { + "name": "pf_list_2_{}".format( + addr_type + ), + "direction": "out", + } + ] + }, + "r2-link3": { + "prefix_lists": [ + { + "name": "pf_list_2_{}".format( + addr_type + ), + "direction": "out", + } + ] + }, + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + clear_bgp_and_verify(tgen, topo, "r2") + + step( + "VM1 IPv4 and IPv6 Route which is denied using prefix list is " + "not present on FRR1 side routing table , also not able to " + "ping the routes show ip route" + ) + + dut = "r1" + protocol = "bgp" + ntwk_r2_vm1 = str( + ipaddress.ip_interface( + u"{}".format(topo["routers"]["r2"]["links"]["vm1"][addr_type]) + ).network + ) + input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}} + result4 = verify_rib( + tgen, addr_type, dut, input_dict, protocol=protocol, expected=False + ) + assert result4 is not True, "Testcase {} : Failed , VM1 route is " + "not filtered out via prefix list. \n Error: {}".format(tc_name, result4) + + step( + "VM4 and VM6 IPV4 and IPv6 address are present in local and " + "FRR2 routing table show ip bgp show ip route" + ) + + dut = "r2" + ntwk_r2_vm6 = str( + ipaddress.ip_interface( + u"{}".format(topo["routers"]["r2"]["links"]["vm6"][addr_type]) + ).network + ) + input_dict = {"r3": {"static_routes": [{"network": ntwk_r2_vm6}]}} + result4 = verify_rib(tgen, addr_type, dut, input_dict) + assert result4 is True, "Testcase {} : Failed.\n Error: {}".format( + tc_name, result4 + ) + + step("Remove prefix list from all the neighbors") + input_dict_4 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link0": { + "prefix_lists": [ + { + "name": "pf_list_1_{}".format( + addr_type + ), + "direction": "out", + "delete": True, + } + ] + }, + "r2-link1": { + "prefix_lists": [ + { + "name": "pf_list_1_{}".format( + addr_type + ), + "direction": "out", + "delete": True, + } + ] + }, + "r2-link2": { + "prefix_lists": [ + { + "name": "pf_list_1_{}".format( + addr_type + ), + "direction": "out", + "delete": True, + } + ] + }, + "r2-link3": { + "prefix_lists": [ + { + "name": "pf_list_1_{}".format( + addr_type + ), + "direction": "out", + "delete": True, + } + ] + }, + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + input_dict_4 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link0": { + "prefix_lists": [ + { + "name": "pf_list_2_{}".format( + addr_type + ), + "direction": "out", + "delete": True, + } + ] + }, + "r2-link1": { + "prefix_lists": [ + { + "name": "pf_list_2_{}".format( + addr_type + ), + "direction": "out", + "delete": True, + } + ] + }, + "r2-link2": { + "prefix_lists": [ + { + "name": "pf_list_2_{}".format( + addr_type + ), + "direction": "out", + "delete": True, + } + ] + }, + "r2-link3": { + "prefix_lists": [ + { + "name": "pf_list_2_{}".format( + addr_type + ), + "direction": "out", + "delete": True, + } + ] + }, + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + clear_bgp_and_verify(tgen, topo, "r2") + + step("Create RouteMap_1 with prefix list P1 and weight 50") + # Create route map + rmap_dict = { + "r2": { + "route_maps": { + "rmap_pf_list_1_{}".format(addr_type): [ + { + "action": "permit", + "set": {"weight": 50}, + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + } + ] + } + } + } + result = create_route_maps(tgen, rmap_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Create RouteMap_2 with prefix list P2 and weight 50") + # Create route map + rmap_dict = { + "r2": { + "route_maps": { + "rmap_pf_list_2_{}".format(addr_type): [ + { + "action": "permit", + "set": {"weight": 50}, + "match": { + addr_type: { + "prefix_lists": "pf_list_2_{}".format(addr_type) + } + }, + } + ] + } + } + } + result = create_route_maps(tgen, rmap_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Verify Route-map created verify using show route-map") + # verify rmap_pf_list_1 and rmap_pf_list_2 are present in router r2 + input_dict = { + "r2": { + "route_maps": [ + "rmap_pf_list_1_{}".format(addr_type), + "rmap_pf_list_2_{}".format(addr_type), + ] + } + } + result = verify_route_maps(tgen, input_dict) + assert result is not True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Apply policy RouteMap_1 nbrs 1 2 3 4 to FRR 1") + # Configure prefix list to bgp neighbor + input_dict_4 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link0": { + "route_maps": [ + { + "name": "rmap_pf_list_1_" + "{}".format(addr_type), + "direction": "out", + } + ] + }, + "r2-link1": { + "route_maps": [ + { + "name": "rmap_pf_list_1_" + "{}".format(addr_type), + "direction": "out", + } + ] + }, + "r2-link2": { + "route_maps": [ + { + "name": "rmap_pf_list_1_" + "{}".format(addr_type), + "direction": "out", + } + ] + }, + "r2-link3": { + "route_maps": [ + { + "name": "rmap_pf_list_1_" + "{}".format(addr_type), + "direction": "out", + } + ] + }, + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Apply policy RouteMap_2 nbrs 5 and 6 to FRR2") + # Configure prefix list to bgp neighbor + input_dict_4 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link0": { + "route_maps": [ + { + "name": "rmap_pf_list_2_" + "{}".format(addr_type), + "direction": "out", + } + ] + }, + "r2-link1": { + "route_maps": [ + { + "name": "rmap_pf_list_2_" + "{}".format(addr_type), + "direction": "out", + } + ] + }, + "r2-link2": { + "route_maps": [ + { + "name": "rmap_pf_list_2_" + "{}".format(addr_type), + "direction": "out", + } + ] + }, + "r2-link3": { + "route_maps": [ + { + "name": "rmap_pf_list_2_" + "{}".format(addr_type), + "direction": "out", + } + ] + }, + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "After applying to BGP neighbors verify VM1 IPv4 and IPv6 Route" + " which is denied using prefix list is not present on FRR side" + " routing table , also not able to ping the routes show ip route" + " and VM4 and VM6 IPV4 and IPv6 address are present in local and" + " FRR routing table show ip bgp show ip route" + ) + + dut = "r1" + protocol = "bgp" + ntwk_r2_vm1 = str( + ipaddress.ip_interface( + u"{}".format(topo["routers"]["r2"]["links"]["vm1"][addr_type]) + ).network + ) + input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}} + result4 = verify_rib( + tgen, addr_type, dut, input_dict, protocol=protocol, expected=False + ) + assert result4 is not True, "Testcase {} : Failed \n" "Error: {}".format( + tc_name, result4 + ) + + step("vm4 should be present in FRR1") + dut = "r1" + ntwk_r2_vm1 = str( + ipaddress.ip_interface( + u"{}".format(topo["routers"]["r1"]["links"]["vm4"][addr_type]) + ).network + ) + input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}} + result4 = verify_rib(tgen, addr_type, dut, input_dict) + assert result4 is True, "Testcase {} : Failed , VM1 route is " + "not filtered out via prefix list. \n Error: {}".format(tc_name, result4) + + step("vm4 should be present in FRR2") + dut = "r2" + ntwk_r2_vm1 = str( + ipaddress.ip_interface( + u"{}".format(topo["routers"]["r1"]["links"]["vm4"][addr_type]) + ).network + ) + input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}} + result4 = verify_rib(tgen, addr_type, dut, input_dict) + assert result4 is True, "Testcase {} : Failed , VM1 route is " + "not filtered out via prefix list. \n Error: {}".format(tc_name, result4) + + dut = "r3" + protocol = "bgp" + ntwk_r2_vm6 = str( + ipaddress.ip_interface( + u"{}".format(topo["routers"]["r2"]["links"]["vm6"][addr_type]) + ).network + ) + input_dict = {"r3": {"static_routes": [{"network": ntwk_r2_vm6}]}} + result4 = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) + assert result4 is True, "Testcase {} : Failed.\n Error: {}".format( + tc_name, result4 + ) + + write_test_footer(tc_name) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/static_routing_with_ibgp/static_routes_topo1_ibgp.json b/tests/topotests/static_routing_with_ibgp/static_routes_topo1_ibgp.json new file mode 100644 index 0000000000..5f263072ab --- /dev/null +++ b/tests/topotests/static_routing_with_ibgp/static_routes_topo1_ibgp.json @@ -0,0 +1,145 @@ +{ + "address_types": [ + "ipv4", + "ipv6" + ], + "ipv4base": "10.0.0.0", + "ipv4mask": 30, + "ipv6base": "fd00::", + "ipv6mask": 64, + "link_ip_start": { + "ipv4": "10.0.0.0", + "v4mask": 30, + "ipv6": "fd00::", + "v6mask": 64 + }, + "lo_prefix": { + "ipv4": "1.0.", + "v4mask": 32, + "ipv6": "2001:db8:f::", + "v6mask": 128 + }, + "routers": { + "r1": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link1": { + "ipv4": "auto", + "ipv6": "auto" + } + } + }, + "r2": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r1-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2": {} + } + } + } + } + } + } + } + }, + "r3": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link1": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3": {} + } + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/tests/topotests/static_routing_with_ibgp/static_routes_topo2_ibgp.json b/tests/topotests/static_routing_with_ibgp/static_routes_topo2_ibgp.json new file mode 100644 index 0000000000..7537e5cf98 --- /dev/null +++ b/tests/topotests/static_routing_with_ibgp/static_routes_topo2_ibgp.json @@ -0,0 +1,267 @@ +{ + "address_types": [ + "ipv4", + "ipv6" + ], + "ipv4base": "10.0.0.0", + "ipv4mask": 30, + "ipv6base": "fd00::", + "ipv6mask": 64, + "link_ip_start": { + "ipv4": "10.0.0.0", + "v4mask": 30, + "ipv6": "fd00::", + "v6mask": 64 + }, + "lo_prefix": { + "ipv4": "1.0.", + "v4mask": 32, + "ipv6": "2001:db8:f::", + "v6mask": 128 + }, + "routers": { + "r1": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link4": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link5": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link6": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link7": { + "ipv4": "auto", + "ipv6": "auto" + } + } + }, + "r2": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r1-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link4": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link5": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link6": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link7": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link4": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link5": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link6": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link7": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link0": {}, + "r2-link1": {}, + "r2-link2": {}, + "r2-link3": {}, + "r2-link4": {}, + "r2-link5": {}, + "r2-link6": {}, + "r2-link7": {} + } + } + }, + "redistribute": [{ + "redist_type": "static" + }] + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link0": {}, + "r2-link1": {}, + "r2-link2": {}, + "r2-link3": {}, + "r2-link4": {}, + "r2-link5": {}, + "r2-link6": {}, + "r2-link7": {} + } + } + }, + "redistribute": [{ + "redist_type": "static" + }] + } + } + } + } + }, + "r3": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link4": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link5": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link6": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link7": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3-link0": {}, + "r3-link1": {}, + "r3-link2": {}, + "r3-link3": {}, + "r3-link4": {}, + "r3-link5": {}, + "r3-link6": {}, + "r3-link7": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3-link0": {}, + "r3-link1": {}, + "r3-link2": {}, + "r3-link3": {}, + "r3-link4": {}, + "r3-link5": {}, + "r3-link6": {}, + "r3-link7": {} + } + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/tests/topotests/static_routing_with_ibgp/static_routes_topo3_ibgp.json b/tests/topotests/static_routing_with_ibgp/static_routes_topo3_ibgp.json new file mode 100644 index 0000000000..3346609c58 --- /dev/null +++ b/tests/topotests/static_routing_with_ibgp/static_routes_topo3_ibgp.json @@ -0,0 +1,177 @@ +{ + "address_types": [ + "ipv4", + "ipv6" + ], + "ipv4base": "10.0.0.0", + "ipv4mask": 30, + "ipv6base": "fd00::", + "ipv6mask": 64, + "link_ip_start": { + "ipv4": "10.0.0.0", + "v4mask": 29, + "ipv6": "fd00::", + "v6mask": 64 + }, + "lo_prefix": { + "ipv4": "1.0.", + "v4mask": 32, + "ipv6": "2001:db8:f::", + "v6mask": 128 + }, + "routers": { + "r1": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link4": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link5": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link6": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link7": { + "ipv4": "auto", + "ipv6": "auto" + } + } + }, + "r2": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r1-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link4": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link5": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link6": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link7": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link0": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link0": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link0": {} + } + } + } + } + } + } + } + }, + "r3": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2-link0": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3-link0": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3-link0": {} + } + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/tests/topotests/static_routing_with_ibgp/static_routes_topo4_ibgp.json b/tests/topotests/static_routing_with_ibgp/static_routes_topo4_ibgp.json new file mode 100644 index 0000000000..bb72578ff3 --- /dev/null +++ b/tests/topotests/static_routing_with_ibgp/static_routes_topo4_ibgp.json @@ -0,0 +1,428 @@ +{ + "address_types": [ + "ipv4", + "ipv6" + ], + "ipv4base": "10.0.0.0", + "ipv4mask": 30, + "ipv6base": "fd00::", + "ipv6mask": 64, + "link_ip_start": { + "ipv4": "10.0.0.0", + "v4mask": 30, + "ipv6": "fd00::", + "v6mask": 64 + }, + "lo_prefix": { + "ipv4": "1.0.", + "v4mask": 32, + "ipv6": "2001:db8:f::", + "v6mask": 128 + }, + "routers": { + "r1": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "vm4": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link0": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r1-link1": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r1-link2": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r1-link3": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link0": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r1-link1": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r1-link2": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r1-link3": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + } + } + } + } + } + } + } + } + }, + "r2": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r1-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r1-link3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "vm1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "vm2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "vm3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "vm6": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link3": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "200", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link0": { + "password": "r1" + }, + "r2-link1": { + "password": "r1" + }, + "r2-link2": { + "password": "r1" + }, + "r2-link3": { + "password": "r1" + } + } + }, + "r3": { + "dest_link": { + "r2-link0": { + "password": "r1" + }, + "r2-link1": { + "password": "r1" + }, + "r2-link2": { + "password": "r1" + }, + "r2-link3": { + "password": "r1" + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link0": { + "password": "r1" + }, + "r2-link1": { + "password": "r1" + }, + "r2-link2": { + "password": "r1" + }, + "r2-link3": { + "password": "r1" + } + } + }, + "r3": { + "dest_link": { + "r2-link0": { + "password": "r1" + }, + "r2-link1": { + "password": "r1" + }, + "r2-link2": { + "password": "r1" + }, + "r2-link3": { + "password": "r1" + } + } + } + } + } + } + } + } + }, + "r3": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2-link0": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r2-link3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "vm5": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "300", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3-link0": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r3-link1": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r3-link2": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r3-link3": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3-link0": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r3-link1": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r3-link2": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + }, + "r3-link3": { + "password": "r1", + "holddowntimer": 3, + "keepalivetimer": 1 + } + } + } + } + } + } + } + } + }, + "vm1": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + } + } + }, + "vm2": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + } + } + }, + "vm3": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + } + } + }, + "vm4": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r1": { + "ipv4": "auto", + "ipv6": "auto" + } + } + }, + "vm5": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r3": { + "ipv4": "auto", + "ipv6": "auto" + } + } + }, + "vm6": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + } + } + } + } +} \ No newline at end of file diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py new file mode 100644 index 0000000000..dc68f16ac4 --- /dev/null +++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py @@ -0,0 +1,1313 @@ +#!/usr/bin/python + +# +# Copyright (c) 2020 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. +# +""" + + -Verify static route ECMP functionality with 2 next hop + + -Verify static route functionality with 2 next hop and different AD + value + + -Verify RIB status when same route advertise via BGP and static route + +""" +import sys +import json +import time +import os +import pytest +import ipaddr +from time import sleep +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/")) +# pylint: disable=C0413 +# Import topogen and topotest helpers +from mininet.topo import Topo +from lib.topogen import Topogen, get_topogen + +# Import topoJson from lib, to create topology and initial configuration +from lib.common_config import ( + start_topology, + write_test_header, + write_test_footer, + reset_config_on_routers, + verify_rib, + create_static_routes, + check_address_types, + step, + create_interfaces_cfg, + shutdown_bringup_interface, + stop_router, + start_router, +) +from lib.topolog import logger +from lib.bgp import verify_bgp_convergence, create_router_bgp, 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 = "{}/static_routes_topo1_ibgp.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 variables +BGP_CONVERGENCE = False +ADDR_TYPES = check_address_types() +NETWORK = {"ipv4": ["11.0.20.1/32", "11.0.20.2/32"], "ipv6": ["2::1/128", "2::2/128"]} +NETWORK2 = {"ipv4": "11.0.20.1/32", "ipv6": "2::1/128"} + +PREFIX1 = {"ipv4": "110.0.20.1/32", "ipv6": "20::1/128"} + + +class CreateTopo(Topo): + """ + Test CreateTopo - 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): + """ + + Set up the pytest environment. + + * `mod`: module name + """ + global topo + 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) + + # Checking BGP convergence + global BGP_CONVERGENCE + global ADDR_TYPES + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + # Api call verify whether BGP is converged + 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(mod): + """ + Teardown the pytest environment + + * `mod`: module name + """ + + 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) + + +def populate_nh(): + NEXT_HOP_IP = { + "nh1": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link0"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link0"]["ipv6"].split("/")[0], + }, + "nh2": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link1"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link1"]["ipv6"].split("/")[0], + }, + } + return NEXT_HOP_IP + + +##################################################### +# +# Tests starting +# +##################################################### + + +def test_static_route_2nh_p0_tc_1_ibgp(request): + """ + Verify static route ECMP functionality with 2 next hop + + """ + 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 ) and N2 (29.1.1.2) , Static route next-hop present on" + "R1" + ) + step("ex :- ip route 10.1.1.1/24 28.1.1.2 & ip route 10.1.1.1/24 29.1.1.1") + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + }, + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh2"][addr_type], + }, + ] + } + } + + 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 ECMP next hop " + ) + nh = [NEXT_HOP_IP["nh1"][addr_type], NEXT_HOP_IP["nh2"][addr_type]] + dut = "r2" + protocol = "static" + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \nError: Routes is" + " missing in RIB".format(tc_name) + + step("Configure IBGP IPv4 peering between R2 and R3 router.") + 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") + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "delete": True, + } + ] + } + } + 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, after removing the static route with N1 , " + "route become active with nexthop N2 and vice versa." + ) + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + 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, input_dict_4, 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 N1") + + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + } + ] + } + } + + 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("Remove the static route configured with nexthop N2 from" "running config") + + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh2"][addr_type], + "delete": True, + } + ] + } + } + + 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, 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, + input_dict_4, + 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, input_dict_4, 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") + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP["nh2"][addr_type], + } + ] + } + } + + 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("Shut nexthop interface N1") + intf = topo["routers"]["r2"]["links"]["r1-link0"]["interface"] + + shutdown_bringup_interface(tgen, dut, intf, False) + + step("Only one the nexthops should be active in RIB.") + + nh = NEXT_HOP_IP["nh2"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \nError: Routes is" + " missing in RIB".format(tc_name) + + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes is" + " still present in RIB".format(tc_name) + + dut = "r3" + result = verify_bgp_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + protocol=protocol, + next_hop=nh, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + dut = "r2" + nh = [NEXT_HOP_IP["nh2"][addr_type]] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \nError: Routes is" + " missing in RIB".format(tc_name) + + dut = "r3" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Route is" + " missing in RIB".format(tc_name) + + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + dut = "r2" + 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], NEXT_HOP_IP["nh2"][addr_type]] + + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol + ) + 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"] + dut = "r2" + 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, + input_dict_4, + 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]] + dut = "r2" + protocol = "static" + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \nError: Routes is" + " missing in RIB".format(tc_name) + + dut = "r3" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Route is" + " missing in RIB".format(tc_name) + + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + step("No shut nexthop interface N2") + dut = "r2" + 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], NEXT_HOP_IP["nh2"][addr_type]] + + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \nError: Routes is" + " missing in RIB".format(tc_name) + + dut = "r3" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Route is" + " missing in RIB".format(tc_name) + + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + step("Reload the FRR router") + # stop/start -> restart FRR router and verify + stop_router(tgen, "r2") + sleep(5) + start_router(tgen, "r2") + + dut = "r2" + step( + "After reload of FRR router , static route installed" + " in RIB and FIB properly ." + ) + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \nError: Routes is" + " missing in RIB".format(tc_name) + + dut = "r3" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + write_test_footer(tc_name) + + +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], + "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], + "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") + sleep(5) + 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) + + +""" +def test_same_rte_from_bgp_static_P0_tc5(request): + + #Verify RIB status when same route advertise via BGP and static + #route + + + 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) + + NEXT_HOP_IP = populate_nh() + step('Configure iBGP IPv4 peering between R2 and R3 router.') + reset_config_on_routers(tgen) + step( + 'Configure IPv4 static route (10.1.1.1/24) in R2 with next hop' + 'N1 (28.1.1.2 ) and N2 (29.1.1.2) , Static route next-hop present' + 'on R1') + + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP['nh1'][addr_type] + }, + { + "network": NETWORK[addr_type], + "next_hop": NEXT_HOP_IP['nh2'][addr_type] + } + ] + } + } + 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('Configure redistribute static in BGP.') + for addr_type in ADDR_TYPES: + 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("Verify on R3 , route receive on R3 BGP table ") + dut = 'r3' + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + step("Verify route installed in the RIB and FIB of R3") + protocol = 'bgp' + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + step( + 'Configure 2 links/interfaces between R1 and R3 , keep one' + 'interface in shut (active) state and other interface in no shut' + '(inactive) state') + dut = 'r3' + intf = topo['routers']['r3']['links']['r1-link0']['interface'] + shutdown_bringup_interface(tgen, dut, intf, False) + + step( + 'Configure same static route (10.1.1.1/24) in R3 with inactive' + 'nexthop interface') + + step( + 'Configure same static route 10.1.1.1/24) again in R3 with' + 'active nexthop interface') + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r3": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": topo['routers']['r1']['links']['r3-link0'][ + addr_type] + }, + { + "network": NETWORK[addr_type], + "next_hop": topo['routers']['r1']['links']['r3-link1'][ + addr_type] + } + ] + } + } + 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( + "Verify when static route configure with inactive nexthop , " + "verify BGP received route is active in the RIB and FIB") + dut = 'r3' + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Route is" + " missing in BGP RIB".format(tc_name) + + protocol = 'bgp' + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, fib=True) + assert result is True, "Testcase {} : Failed \nError: Route is" + " missing in RIB".format(tc_name) + + step('Remove the redistribute static knob from R2 router') + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "redistribute": [{ + "redist_type": "static", + "delete": True + }] + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + step( + "After removing /adding the redistribute static knob , " + "BGP received route is deleted and added in RIB of R3 ") + dut = 'r3' + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is not True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + protocol = 'bgp' + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, fib=True) + assert result is not True, "Testcase {} : Failed \nError: Route is" + " still present in RIB".format(tc_name) + + step('Configure the redistribute static knob again on R2 router') + for addr_type in ADDR_TYPES: + 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) + dut = 'r3' + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Route is" + " missing in BGP RIB".format(tc_name) + + protocol = 'bgp' + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, fib=True) + assert result is True, "Testcase {} : Failed \nError: Route is" + " missing in RIB".format(tc_name) + + step( + 'Remove the static route on R3 configured with active' + 'interface') + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r3": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": topo['routers']['r1']['links']['r3-link0'][ + addr_type], + "delete": True + }, + { + "network": NETWORK[addr_type], + "next_hop": topo['routers']['r1']['links']['r3-link1'][ + addr_type], + "delete": True + } + ] + } + } + 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( + "After removing the static route with active nexthop verify " + "BGP received route is became active in RIB and FIB") + dut = 'r3' + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Route is" + " missing in BGP RIB".format(tc_name) + + protocol = 'bgp' + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, fib=True) + assert result is True, "Testcase {} : Failed \nError: Route is" + " missing in RIB".format(tc_name) + + write_test_footer(tc_name) +""" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py new file mode 100644 index 0000000000..0e051d6910 --- /dev/null +++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py @@ -0,0 +1,2357 @@ +#!/usr/bin/python + +# +# Copyright (c) 2020 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. +# + + +""" + -Verify static route functionality with 8 next hop different AD value + and BGP ECMP + + -Verify 8 static route functionality with 8 next hop different AD + + -Verify static route with 8 next hop with different AD value and 8 + EBGP neighbors + + -Verify static route with 8 next hop with different AD value and 8 + IBGP neighbors + + -Delete the static route and verify the RIB and FIB state + + -Verify 8 static route functionality with 8 ECMP next hop +""" +import sys +import json +import time +import os +import pytest +import ipaddr +from time import sleep +from copy import deepcopy +import random + +# 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/")) +# pylint: disable=C0413 +# Import topogen and topotest helpers +from mininet.topo import Topo +from lib.topogen import Topogen, get_topogen + +# Import topoJson from lib, to create topology and initial configuration +from lib.common_config import ( + start_topology, + write_test_header, + write_test_footer, + reset_config_on_routers, + verify_rib, + create_static_routes, + check_address_types, + step, + create_interfaces_cfg, + shutdown_bringup_interface, + stop_router, + start_router, +) +from lib.topolog import logger +from lib.bgp import verify_bgp_convergence, create_router_bgp, 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 = "{}/static_routes_topo2_ibgp.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 variables +BGP_CONVERGENCE = False +ADDR_TYPES = check_address_types() +NETWORK = { + "ipv4": [ + "11.0.20.1/32", + "11.0.20.2/32", + "11.0.20.3/32", + "11.0.20.4/32", + "11.0.20.5/32", + "11.0.20.6/32", + "11.0.20.7/32", + "11.0.20.8/32", + ], + "ipv6": [ + "2::1/128", + "2::2/128", + "2::3/128", + "2::4/128", + "2::5/128", + "2::6/128", + "2::7/128", + "2::8/128", + ], +} +PREFIX1 = {"ipv4": "110.0.20.1/32", "ipv6": "20::1/128"} +PREFIX2 = {"ipv4": "110.0.20.2/32", "ipv6": "20::2/128"} +NEXT_HOP_IP = [] +topo_diag = """ + Please view in a fixed-width font such as Courier. + +------+ +------+ +------+ + | +--------------+ +--------------+ | + | | | | | | + | R1 +---8 links----+ R2 +---8 links----+ R3 | + | | | | | | + | +--------------+ +--------------+ | + +------+ +------+ +------+ + +""" + + +class CreateTopo(Topo): + """ + Test CreateTopo - 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): + """ + + Set up the pytest environment. + + * `mod`: module name + """ + global topo + 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) + + # Checking BGP convergence + global BGP_CONVERGENCE + global ADDR_TYPES + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Api call verify whether BGP is converged + 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(mod): + """ + Teardown the pytest environment + + * `mod`: module name + """ + + 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) + + +def populate_nh(): + NEXT_HOP_IP = { + "nh1": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link0"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link0"]["ipv6"].split("/")[0], + }, + "nh2": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link1"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link1"]["ipv6"].split("/")[0], + }, + "nh3": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link2"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link2"]["ipv6"].split("/")[0], + }, + "nh4": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link3"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link3"]["ipv6"].split("/")[0], + }, + "nh5": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link4"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link4"]["ipv6"].split("/")[0], + }, + "nh6": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link5"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link5"]["ipv6"].split("/")[0], + }, + "nh7": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link6"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link6"]["ipv6"].split("/")[0], + }, + "nh8": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link7"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link7"]["ipv6"].split("/")[0], + }, + } + return NEXT_HOP_IP + + +##################################################### +# +# Tests starting +# +##################################################### + + +def test_static_rte_with_8ecmp_nh_p1_tc9_ibgp(request): + """ + Verify 8 static route functionality with 8 ECMP next hop + + """ + 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) + NEXT_HOP_IP = populate_nh() + step("Configure 8 interfaces / links between R1 and R2") + step("Configure 8 interfaces / links between R2 and R3") + step("Configure 8 IBGP IPv4 peering between R2 and R3 router.") + reset_config_on_routers(tgen) + + step( + "Configure 8 IPv4 static route in R2 with 8 next hop" + "N1(21.1.1.2) , N2(22.1.1.2) , N3(23.1.1.2) , N4(24.1.1.2) ," + "N5(25.1.1.2) , N6(26.1.1.2) , N7(27.1.1.2) , N8(28.1.1.2) ," + "Static route next-hop present on R1" + ) + nh_all = {} + for addr_type in ADDR_TYPES: + # Enable static routes + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + } + ] + } + } + 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 + ) + logger.info("Verifying %s routes on r2", addr_type) + nh_all[addr_type] = [ + NEXT_HOP_IP["nh1"][addr_type], + NEXT_HOP_IP["nh2"][addr_type], + NEXT_HOP_IP["nh3"][addr_type], + NEXT_HOP_IP["nh4"][addr_type], + NEXT_HOP_IP["nh5"][addr_type], + NEXT_HOP_IP["nh6"][addr_type], + NEXT_HOP_IP["nh7"][addr_type], + NEXT_HOP_IP["nh8"][addr_type], + ] + + dut = "r2" + protocol = "static" + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh_all[addr_type], + protocol=protocol, + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + step("Configure redistribute static in BGP on R2 router") + for addr_type in ADDR_TYPES: + 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 + ) + + dut = "r3" + protocol = "bgp" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + step( + "Remove the static route configured with nexthop N1 to N8, one" + "by one from running config" + ) + dut = "r2" + protocol = "static" + step( + "After removing the static route with N1 to N8 one by one , " + "verify that entry is removed from RIB and FIB of R3 " + ) + for addr_type in ADDR_TYPES: + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "delete": True, + } + ] + } + } + 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( + "After removing the static route with N1 to N8 one by one , " + "verify that entry is removed from RIB and FIB of R3 " + ) + nh = NEXT_HOP_IP["nh" + str(nhp)][addr_type] + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed\nError: Routes is" + " still present in RIB".format(tc_name) + + step("Configure the static route with nexthop N1 to N8, one by one") + for addr_type in ADDR_TYPES: + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + } + ] + } + } + 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 + ) + + nh = NEXT_HOP_IP["nh" + str(nhp)][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed\nError: Routes are" + " missing in RIB".format(tc_name) + + dut = "r2" + protocol = "static" + step("Shut nexthop interfaces N1 to N8 one by one") + for intfr in range(0, 3): + intf = topo["routers"]["r2"]["links"]["r1-link{}".format(intfr)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + for addr_type in ADDR_TYPES: + nhp = intfr + 1 + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + } + ] + } + } + nh = NEXT_HOP_IP["nh" + str(nhp)][addr_type] + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {}: Failed\nError: Routes are" + " still present in RIB".format(tc_name) + + step("No shut the nexthop interfaces N1 to N8 one by one .") + for intfr in range(0, 3): + intf = topo["routers"]["r2"]["links"]["r1-link{}".format(intfr)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, True) + for addr_type in ADDR_TYPES: + nhp = intfr + 1 + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + } + ] + } + } + nh = NEXT_HOP_IP["nh" + str(nhp)][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + step("Random shut of the nexthop interfaces") + randnum = random.randint(0, 7) + # Shutdown interface + dut = "r2" + step( + " interface which is about to be shut no shut between r1 and r2 is " "%s", + topo["routers"]["r2"]["links"]["r1-link{}".format(randnum)]["interface"], + ) + intf = topo["routers"]["r2"]["links"]["r1-link{}".format(randnum)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + + sleep(5) + + step("Random no shut of the nexthop interfaces") + # Bringup interface + shutdown_bringup_interface(tgen, dut, intf, True) + + step( + "After random shut/no shut of nexthop , only that " + "nexthop deleted/added from all the routes , other nexthop remain " + "unchanged" + ) + dut = "r2" + protocol = "static" + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + } + ] + } + } + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh_all[addr_type], + protocol=protocol, + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + step("Remove random static route with all the nexthop") + dut = "r2" + randnum = random.randint(1, 7) + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(randnum)][addr_type], + "delete": True, + } + ] + } + } + 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( + "After delete of random route , that route only got deleted from" + " RIB/FIB other route are showing properly" + ) + nh = NEXT_HOP_IP["nh{}".format(randnum)][addr_type] + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(randnum)][addr_type], + } + ] + } + } + 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("Reload the FRR router") + # stop/start -> restart FRR router and verify + stop_router(tgen, "r2") + sleep(5) + start_router(tgen, "r2") + + step( + "After reload of FRR router , static route " + "installed in RIB and FIB properly ." + ) + for addr_type in ADDR_TYPES: + # Enable static routes + nhp = 1 + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + } + ] + } + } + logger.info("Verifying %s routes on r2", addr_type) + dut = "r2" + protocol = "static" + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh_all[addr_type], + protocol=protocol, + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + step( + "Remove and add the IBGP nbrs using interface shut and" + "deactivate/activate from address family" + ) + + for intfr in range(0, 8): + intf = topo["routers"]["r2"]["links"]["r3-link{}".format(intfr)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + + sleep(200) + + step("verify bgp convergence as all interface are shut") + + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is not True, "Testcase {} : Failed" + " \n Error: {}".format(tc_name, bgp_convergence) + + dut = "r3" + protocol = "static" + for addr_type in ADDR_TYPES: + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + } + ] + } + } + nh = NEXT_HOP_IP["nh" + str(nhp)][addr_type] + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " still present in RIB".format(tc_name) + dut = "r2" + for intfr in range(0, 8): + intf = topo["routers"]["r2"]["links"]["r3-link{}".format(intfr)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, True) + + step("verify bgp convergence as all interface are un shut") + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is True, "Testcase {} :" + " Failed \n Error: {}".format(tc_name, bgp_convergence) + + step("Remove the redistribute static knob") + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "redistribute": [ + {"redist_type": "static", "delete": True} + ] + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "After removing the BGP neighbor or redistribute static knob , " + "verify route got clear from RIB and FIB of R3 routes " + ) + dut = "r3" + protocol = "bgp" + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " still present in RIB".format(tc_name) + + write_test_footer(tc_name) + + +def test_static_route_8nh_diff_AD_bgp_ecmp_p1_tc6_ibgp(request): + """ + Verify static route functionality with 8 next hop different AD + value and BGP ECMP + + """ + 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) + + step("Configure 8 interfaces / links between R1 and R2 ,") + step("Configure 8 interlaces/links between R2 and R3") + step( + "Configure IBGP IPv4 peering over loopback interface between" + "R2 and R3 router." + ) + step("Configure redistribute static in BGP on R2 router") + reset_config_on_routers(tgen) + NEXT_HOP_IP = populate_nh() + nh_all = {} + for addr_type in ADDR_TYPES: + nh_all[addr_type] = [] + for nhp in range(1, 9): + nh_all[addr_type].append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + step( + "Configure IPv4 static route in R2 with 8 next hop" + "N1(21.1.1.2) AD 10, N2(22.1.1.2) AD 20, N3(23.1.1.2) AD 30," + "N4(24.1.1.2) AD 40, N5(25.1.1.2) AD 50, N6(26.1.1.2) AD 60," + "N7(27.1.1.2) AD 70, N8(28.1.1.2) AD 80, Static route next-hop" + "present on R1" + ) + for addr_type in ADDR_TYPES: + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + } + ] + } + } + 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 + ) + logger.info("Verifying %s routes on r2", addr_type) + + step( + "On R2, static route installed in RIB using " + "show ip route with 8 next hop , lowest AD nexthop is active" + ) + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + nh = [] + for nhp in range(2, 9): + nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + wait=2, + attempts=3, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " are missing in RIB".format(tc_name) + + step( + "Remove the static route configured with nexthop N1 to N8, one" + "by one from running config" + ) + + for addr_type in ADDR_TYPES: + # delete static routes + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + "delete": True, + } + ] + } + } + + 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( + "After removing the static route with N1 to N8 one by one , " + "route become active with next preferred nexthop and nexthop which " + "got removed is not shown in RIB and FIB" + ) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh_all[addr_type], + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " still present in RIB".format(tc_name) + + step("Configure the static route with nexthop N1 to N8, one by one") + + for addr_type in ADDR_TYPES: + # add static routes + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + } + ] + } + } + 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( + " After configuring them, route is always active with lowest AD" + " value and all the nexthop populated in RIB and FIB again" + ) + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + nh = [] + for nhp in range(2, 9): + nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + wait=2, + attempts=3, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " are missing in RIB".format(tc_name) + + step("Shut nexthop interfaces N1 to N8 one by one") + for addr_type in ADDR_TYPES: + for nhp in range(0, 8): + intf = topo["routers"]["r2"]["links"]["r1-link" + str(nhp)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh_all[addr_type], + protocol=protocol, + fib=True, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " are still present in RIB".format(tc_name) + + step("No shut the nexthop interfaces N1 to N3 one by one .") + for addr_type in ADDR_TYPES: + for nhp in range(0, 3): + intf = topo["routers"]["r2"]["links"]["r1-link" + str(nhp)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, True) + + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + nh = [] + for nhp in range(2, 9): + nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + wait=2, + attempts=3, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " are missing in RIB".format(tc_name) + + step("Random shut of the nexthop interfaces") + randnum = random.randint(0, 7) + for addr_type in ADDR_TYPES: + intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type] + input_dict_5 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type], + } + ] + } + } + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_5, + next_hop=nhip, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + + step("Random no shut of the nexthop interfaces") + for addr_type in ADDR_TYPES: + intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, True) + nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_5, next_hop=nhip, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \n" + "Error: Routes are missing in RIB".format(tc_name) + + dut = "r2" + step("Shut the interfaces connected between R2 and R3 one by one") + for nhp in range(0, 3): + intf = topo["routers"]["r2"]["links"]["r3-link" + str(nhp)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + + protocol = "bgp" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + + step("No shut the interfaces between R2 and R3 one by one") + dut = "r2" + for nhp in range(0, 3): + intf = topo["routers"]["r2"]["links"]["r3-link" + str(nhp)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, True) + + # this is next hop reachability route in r3 as we are using ibgp + dut = "r3" + for addr_type in ADDR_TYPES: + nh_as_rte = NEXT_HOP_IP["nh1"][addr_type] + "/32" + # add static routes + nh_static_rte = { + "r3": {"static_routes": [{"network": nh_as_rte, "next_hop": "Null0"}]} + } + logger.info("Configure static routes") + result = create_static_routes(tgen, nh_static_rte) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "After each interface shut and no shut between R2 -R3 ,verify static" + "route is present in the RIB & FIB of R3 & R2 RIB/FIB is remain" + " unchanged" + ) + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, "Testcase {} : Failed \n" + "Error: Routes are missing in RIB".format(tc_name) + + protocol = "static" + dut = "r2" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert ( + result is True + ), "Testcase {}: Failed \n " "Error: Routes are missing in RIB".format(tc_name) + + protocol = "bgp" + dut = "r3" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert ( + result is True + ), "Testcase {}: Failed \n " "Error: Routes are missing in RIB".format(tc_name) + + step("Reload the FRR router") + # stop/start -> restart FRR router and verify + stop_router(tgen, "r2") + sleep(5) + start_router(tgen, "r2") + + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, ( + "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + ) + + step("BGP neighbor remove and add") + for rtr in ["r2", "r3"]: + if "bgp" in topo["routers"][rtr].keys(): + delete_bgp = {rtr: {"bgp": {"delete": True}}} + result = create_router_bgp(tgen, topo, delete_bgp) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + create_router_bgp(tgen, topo["routers"]) + + NEXT_HOP_IP = populate_nh() + step("Verify routes are still present after delete and add bgp") + dut = "r2" + protocol = "static" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, ( + "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + ) + + dut = "r3" + protocol = "bgp" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, ( + "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + ) + + step("Remove the redistribute static knob") + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "redistribute": [ + {"redist_type": "static", "delete": True} + ] + } + } + } + } + } + } + + logger.info("Remove redistribute static") + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + step("verify that routes are deleted from R3 routing table") + + dut = "r3" + protocol = "bgp" + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " strill present in RIB of R3".format(tc_name) + + write_test_footer(tc_name) + + +def test_static_route_8nh_diff_AD_ibgp_ecmp_p1_tc7_ibgp(request): + """ + Verify static route with 8 next hop with different AD value and 8 + IBGP neighbors + """ + 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) + + step("Configure 8 interfaces / links between R1 and R2") + step("Configure 8 interlaces/links between R2 and R3") + step("Configure 8 IBGP IPv4 peering between R2 and R3") + + reset_config_on_routers(tgen) + NEXT_HOP_IP = populate_nh() + + step("Configure redistribute static in BGP on R2 router") + for addr_type in ADDR_TYPES: + 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( + "Configure IPv4 static route in R2 with 8 next hop" + "N1(21.1.1.2) AD 10, N2(22.1.1.2) AD 20, N3(23.1.1.2) AD 30," + "N4(24.1.1.2) AD 40, N5(25.1.1.2) AD 50, N6(26.1.1.2) AD 60," + "N7(27.1.1.2) AD 70, N8(28.1.1.2) AD 80, Static route next-hop" + "present on R1" + ) + nh_all = {} + for addr_type in ADDR_TYPES: + nh_all[addr_type] = [] + for nhp in range(1, 9): + nh_all[addr_type].append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + for addr_type in ADDR_TYPES: + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + } + ] + } + } + 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 + ) + logger.info("Verifying %s routes on r2", addr_type) + + step( + "On R2, static route installed in RIB using " + "show ip route with 8 next hop , lowest AD nexthop is active" + ) + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + nh = [] + for nhp in range(2, 9): + nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " are missing in RIB".format(tc_name) + + step( + "Remove the static route configured with nexthop N1 to N8, one" + "by one from running config" + ) + + for addr_type in ADDR_TYPES: + # delete static routes + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + "delete": True, + } + ] + } + } + + 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( + "After removing the static route with N1 to N8 one by one , " + "route become active with next preferred nexthop and nexthop which " + "got removed is not shown in RIB and FIB" + ) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh_all[addr_type], + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " still present in RIB".format(tc_name) + + step("Configure the static route with nexthop N1 to N8, one by one") + + for addr_type in ADDR_TYPES: + # add static routes + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + } + ] + } + } + 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( + " After configuring them, route is always active with lowest AD" + " value and all the nexthop populated in RIB and FIB again" + ) + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + nh = [] + for nhp in range(2, 9): + nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " are missing in RIB".format(tc_name) + + step("Shut nexthop interfaces N1 to N8 one by one") + for addr_type in ADDR_TYPES: + for nhp in range(0, 8): + intf = topo["routers"]["r2"]["links"]["r1-link" + str(nhp)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh_all[addr_type], + protocol=protocol, + fib=True, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " are still present in RIB".format(tc_name) + + step("No shut the nexthop interfaces N1 to N8 one by one .") + for addr_type in ADDR_TYPES: + for nhp in range(0, 8): + intf = topo["routers"]["r2"]["links"]["r1-link" + str(nhp)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, True) + + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + nh = [] + for nhp in range(2, 9): + nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " are missing in RIB".format(tc_name) + + step("Random shut of the nexthop interfaces") + randnum = random.randint(0, 7) + for addr_type in ADDR_TYPES: + intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type] + input_dict_5 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type], + } + ] + } + } + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_5, + next_hop=nhip, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + + step("Random no shut of the nexthop interfaces") + for addr_type in ADDR_TYPES: + intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, True) + nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_5, next_hop=nhip, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \n" + "Error: Routes are missing in RIB".format(tc_name) + + dut = "r2" + step("Shut the interfaces connected between R2 and R3 one by one") + for nhp in range(0, 3): + intf = topo["routers"]["r2"]["links"]["r3-link" + str(nhp)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + + protocol = "bgp" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + + step("No shut the interfaces between R2 and R3 one by one") + dut = "r2" + for nhp in range(0, 3): + intf = topo["routers"]["r2"]["links"]["r3-link" + str(nhp)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, True) + + # this is next hop reachability route in r3 as we are using ibgp + dut = "r3" + for addr_type in ADDR_TYPES: + nh_as_rte = NEXT_HOP_IP["nh1"][addr_type] + "/32" + # add static routes + nh_static_rte = { + "r3": {"static_routes": [{"network": nh_as_rte, "next_hop": "Null0"}]} + } + logger.info("Configure static routes") + result = create_static_routes(tgen, nh_static_rte) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "After each interface shut and no shut between R2 -R3 ,verify static" + "route is present in the RIB & FIB of R3 & R2 RIB/FIB is remain" + " unchanged" + ) + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, "Testcase {} : Failed \n" + "Error: Routes are missing in RIB".format(tc_name) + + protocol = "static" + dut = "r2" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert ( + result is True + ), "Testcase {}: Failed \n " "Error: Routes are missing in RIB".format(tc_name) + + protocol = "bgp" + dut = "r3" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert ( + result is True + ), "Testcase {}: Failed \n " "Error: Routes are missing in RIB".format(tc_name) + + step("Reload the FRR router") + # stop/start -> restart FRR router and verify + stop_router(tgen, "r2") + sleep(5) + start_router(tgen, "r2") + + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, ( + "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + ) + + step("BGP neighbor remove and add") + for rtr in ["r2", "r3"]: + if "bgp" in topo["routers"][rtr].keys(): + delete_bgp = {rtr: {"bgp": {"delete": True}}} + result = create_router_bgp(tgen, topo, delete_bgp) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + create_router_bgp(tgen, topo["routers"]) + + NEXT_HOP_IP = populate_nh() + step("Verify routes are still present after delete and add bgp") + dut = "r2" + protocol = "static" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, ( + "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + ) + + dut = "r3" + protocol = "bgp" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, ( + "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + ) + + step("Remove the redistribute static knob") + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "redistribute": [ + {"redist_type": "static", "delete": True} + ] + } + } + } + } + } + } + + logger.info("Remove redistribute static") + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + step("verify that routes are deleted from R3 routing table") + + dut = "r3" + protocol = "bgp" + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}} + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " still present in RIB of R3".format(tc_name) + + write_test_footer(tc_name) + + +def test_static_route_8nh_diff_AD_bgp_ecmp_p1_tc10_ibgp(request): + """ + Verify 8 static route functionality with 8 next hop different AD' + + """ + 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) + NEXT_HOP_IP = populate_nh() + + step("Configure 8 interfaces / links between R1 and R2 ") + step("Configure 8 IBGP IPv4 peering between R2 and R3 router.") + reset_config_on_routers(tgen) + + step( + "Configure IPv4 static route in R2 with 8 next hop" + "N1(21.1.1.2) AD 10, N2(22.1.1.2) AD 20, N3(23.1.1.2) AD 30," + "N4(24.1.1.2) AD 40, N5(25.1.1.2) AD 50, N6(26.1.1.2) AD 60," + "N7(27.1.1.2) AD 70, N8(28.1.1.2) AD 80" + ) + step( + "Configure nexthop AD in such way for static route S1 , N1 is" + "preferred and for S2 , N2 is preferred and so on .." + ) + nh_all = {} + for addr_type in ADDR_TYPES: + nh_all[addr_type] = [] + for nhp in range(1, 9): + nh_all[addr_type].append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + + for addr_type in ADDR_TYPES: + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + } + ] + } + } + 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 + ) + second_rte = { + "r2": { + "static_routes": [ + { + "network": PREFIX2[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + } + ] + } + } + logger.info("Configure static routes") + result = create_static_routes(tgen, second_rte) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + logger.info("Verifying %s routes on r2", addr_type) + + step( + "On R2, static route installed in RIB using " + "show ip route with 8 next hop , lowest AD nexthop is active" + ) + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + step("Verify that highest AD nexthop are inactive") + nh = [] + for nhp in range(2, 9): + nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + wait=2, + attempts=3, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " are missing in RIB".format(tc_name) + + step("Configure redistribute static in BGP on R2 router") + for addr_type in ADDR_TYPES: + 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 to N8, one" + "by one from running config" + ) + + for addr_type in ADDR_TYPES: + # delete static routes + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + "delete": True, + } + ] + } + } + + 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( + "After removing the static route with N1 to N8 one by one , " + "route become active with next preferred nexthop and nexthop which" + "got removed is not shown in RIB and FIB" + ) + + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " still present in RIB".format(tc_name) + + step("Configure the static route with nexthop N1 to N8, one by one") + for addr_type in ADDR_TYPES: + # add static routes + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + } + ] + } + } + + 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( + " After configuring them, route is always active with lowest AD" + " value and all the nexthop populated in RIB and FIB again" + ) + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type],}]}} + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Route with " + "lowest AD is missing in RIB".format(tc_name) + + step("Shut nexthop interfaces N1 to N3 one by one") + for addr_type in ADDR_TYPES: + for nhp in range(0, 3): + intf = topo["routers"]["r2"]["links"]["r1-link" + str(nhp)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type],}]}} + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + + step("No shut the nexthop interfaces N1 to N3 one by one .") + + for addr_type in ADDR_TYPES: + for nhp in range(0, 3): + intf = topo["routers"]["r2"]["links"]["r1-link" + str(nhp)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, True) + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type],}]}} + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \n" + "Error: Routes are missing in RIB".format(tc_name) + + step("Random shut of the nexthop interfaces") + randnum = random.randint(0, 7) + for addr_type in ADDR_TYPES: + intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type] + input_dict_5 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type], + } + ] + } + } + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_5, + next_hop=nhip, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + + step("Random no shut of the nexthop interfaces") + for addr_type in ADDR_TYPES: + intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, True) + nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_5, next_hop=nhip, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \n" + "Error: Routes are missing in RIB".format(tc_name) + + step("Remove random static route with all the nexthop") + for addr_type in ADDR_TYPES: + # delete static routes + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + "delete": True, + } + ] + } + } + 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( + "After removing the static route with N1 to N8 one by one , " + "route become active with next preferred nexthop and nexthop " + "which got removed is not shown in RIB and FIB" + ) + nh = NEXT_HOP_IP["nh" + str(nhp)][addr_type] + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Route " + " is still present in RIB".format(tc_name) + + step("Reconfigure the deleted routes and verify they are installed") + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + } + ] + } + } + 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 + ) + + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol) + assert result is True, "Testcase {} : Failed \nError: Route " + " is still present in RIB".format(tc_name) + + step("Reload the FRR router") + # stop/start -> restart FRR router and verify + stop_router(tgen, "r2") + sleep(5) + start_router(tgen, "r2") + + step("After reloading, verify that routes are still present in R2.") + result = verify_rib( + tgen, + addr_type, + dut, + second_rte, + next_hop=nh, + protocol=protocol, + fib=True, + ) + assert result is True, ( + "Testcase {} : Failed \nError: Route " + " is missing in RIB".format(tc_name) + ) + + dut = "r2" + for intfr in range(0, 8): + intf = topo["routers"]["r2"]["links"]["r3-link{}".format(intfr)][ + "interface" + ] + shutdown_bringup_interface(tgen, dut, intf, False) + + dut = "r3" + for intfr in range(0, 8): + intf = topo["routers"]["r3"]["links"]["r2-link{}".format(intfr)][ + "interface" + ] + shutdown_bringup_interface(tgen, dut, intf, False) + sleep(180) + step("verify bgp convergence as all interface are shut") + + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is not True, "Testcase {} : Failed \n" + "Error: {}".format(tc_name, bgp_convergence) + + dut = "r2" + protocol = "static" + for addr_type in ADDR_TYPES: + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + } + ] + } + } + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing present in RIB".format(tc_name) + + dut = "r3" + protocol = "bgp" + for addr_type in ADDR_TYPES: + input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type],}]}} + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " are still present in RIB after BGP nbr is down".format(tc_name) + + sleep(5) + dut = "r2" + for intfr in range(0, 8): + intf = topo["routers"]["r2"]["links"]["r3-link{}".format(intfr)][ + "interface" + ] + shutdown_bringup_interface(tgen, dut, intf, True) + + sleep(5) + dut = "r3" + for intfr in range(0, 8): + intf = topo["routers"]["r3"]["links"]["r2-link{}".format(intfr)][ + "interface" + ] + shutdown_bringup_interface(tgen, dut, intf, True) + + step("verify bgp convergence as all interface are un shut") + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is True, "Testcase {} : Failed \n" + "Error: {}".format(tc_name, bgp_convergence) + + step("Remove the redistribute static knob") + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "redistribute": [ + {"redist_type": "static", "delete": True} + ] + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "After removing the BGP neighbor or redistribute static knob , " + "verify route got clear from RIB and FIB of R3 routes " + ) + dut = "r3" + protocol = "bgp" + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + } + ] + } + } + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " still present in RIB".format(tc_name) + + write_test_footer(tc_name) + + +def test_static_route_delete_p0_tc11_ibgp(request): + """ + Delete the static route and verify the RIB and FIB state + """ + 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) + NEXT_HOP_IP = populate_nh() + + step("Configure 8 interfaces / links between R1 and R2 ") + step("Configure 8 IBGP IPv4 peering between R2 and R3 router.") + reset_config_on_routers(tgen) + + step( + "Configure IPv4 static route in R2 with 8 next hop" + "N1(21.1.1.2) AD 10, N2(22.1.1.2) AD 20, N3(23.1.1.2) AD 30," + "N4(24.1.1.2) AD 40, N5(25.1.1.2) AD 50, N6(26.1.1.2) AD 60," + "N7(27.1.1.2) AD 70, N8(28.1.1.2) AD 80" + ) + step( + "Configure nexthop AD in such way for static route S1 , N1 is" + "preferred and for S2 , N2 is preferred and so on .." + ) + nh_all = {} + for addr_type in ADDR_TYPES: + nh_all[addr_type] = [] + for nhp in range(1, 9): + nh_all[addr_type].append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + + for addr_type in ADDR_TYPES: + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + } + ] + } + } + 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 + ) + second_rte = { + "r2": { + "static_routes": [ + { + "network": PREFIX2[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + } + ] + } + } + logger.info("Configure static routes") + result = create_static_routes(tgen, second_rte) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + logger.info("Verifying %s routes on r2", addr_type) + + step( + "On R2, static route installed in RIB using " + "show ip route with 8 next hop , lowest AD nexthop is active" + ) + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + step("Verify that highest AD nexthop are inactive") + nh = [] + for nhp in range(2, 9): + nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " are missing in RIB".format(tc_name) + + step("Configure redistribute static in BGP on R2 router") + for addr_type in ADDR_TYPES: + 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 redistribute static knob") + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "redistribute": [ + {"redist_type": "static", "delete": True} + ] + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "Verify after removing the redistribute static from BGP all the" + "routes got delete from RIB and FIB of R3 " + ) + + dut = "r3" + protocol = "bgp" + result = verify_rib( + tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " still present in RIB".format(tc_name) + + for addr_type in ADDR_TYPES: + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + "delete": True, + } + ] + } + } + 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 + ) + second_rte = { + "r2": { + "static_routes": [ + { + "network": PREFIX2[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + } + ] + } + } + logger.info("Configure static routes") + result = create_static_routes(tgen, second_rte) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + logger.info("Verifying %s routes on r2", addr_type) + + step( + " After removing all the routes and nexthop from R2 , " + " verify R2 RIB and FIB is cleared" + ) + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " still active in RIB".format(tc_name) + write_test_footer(tc_name) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py new file mode 100644 index 0000000000..3458893f69 --- /dev/null +++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py @@ -0,0 +1,992 @@ +#!/usr/bin/python + +# +# Copyright (c) 2020 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. +# +""" + -Verify static route ECMP functionality with 8 next hop + + -Verify static route functionality with 8 next hop different AD value + + -Verify static route with tag option + + -Verify BGP did not install the static route when it receive route + with local next hop + +""" +import sys +import json +import time +import os +import pytest +import ipaddr +from time import sleep +from copy import deepcopy +import random +from re import search as re_search + + +# 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/")) +# pylint: disable=C0413 +# Import topogen and topotest helpers +from mininet.topo import Topo +from lib.topogen import Topogen, get_topogen + +from lib.common_config import ( + start_topology, + write_test_header, + write_test_footer, + reset_config_on_routers, + verify_rib, + create_static_routes, + check_address_types, + step, + create_interfaces_cfg, + shutdown_bringup_interface, + stop_router, + start_router, +) +from lib.topolog import logger +from lib.bgp import verify_bgp_convergence, create_router_bgp, 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 = "{}/static_routes_topo3_ibgp.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 variables +BGP_CONVERGENCE = False +ADDR_TYPES = check_address_types() +NETWORK = { + "ipv4": [ + "11.0.20.1/32", + "11.0.20.2/32", + "11.0.20.3/32", + "11.0.20.4/32", + "11.0.20.5/32", + "11.0.20.6/32", + "11.0.20.7/32", + "11.0.20.8/32", + ], + "ipv6": [ + "2::1/128", + "2::2/128", + "2::3/128", + "2::4/128", + "2::5/128", + "2::6/128", + "2::7/128", + "2::8/128", + ], +} +PREFIX1 = {"ipv4": "110.0.20.1/32", "ipv6": "20::1/128"} +NETWORK2 = {"ipv4": ["11.0.20.1/32"], "ipv6": ["2::1/128"]} +NEXT_HOP_IP = [] + + +class CreateTopo(Topo): + """ + Test CreateTopo - 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): + """ + + Set up the pytest environment. + + * `mod`: module name + """ + global topo + 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) + + # Checking BGP convergence + global BGP_CONVERGENCE + global ADDR_TYPES + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + # Api call verify whether BGP is converged + 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(mod): + """ + Teardown the pytest environment + + * `mod`: module name + """ + + 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) + + +def populate_nh(): + NEXT_HOP_IP = { + "nh1": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link0"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link0"]["ipv6"].split("/")[0], + }, + "nh2": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link1"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link1"]["ipv6"].split("/")[0], + }, + "nh3": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link2"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link2"]["ipv6"].split("/")[0], + }, + "nh4": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link3"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link3"]["ipv6"].split("/")[0], + }, + "nh5": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link4"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link4"]["ipv6"].split("/")[0], + }, + "nh6": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link5"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link5"]["ipv6"].split("/")[0], + }, + "nh7": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link6"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link6"]["ipv6"].split("/")[0], + }, + "nh8": { + "ipv4": topo["routers"]["r1"]["links"]["r2-link7"]["ipv4"].split("/")[0], + "ipv6": topo["routers"]["r1"]["links"]["r2-link7"]["ipv6"].split("/")[0], + }, + } + return NEXT_HOP_IP + + +##################################################### +# +# Tests starting +# +##################################################### + + +def test_staticroute_with_ecmp_p0_tc3_ibgp(request): + """ + Verify static route ECMP functionality with 8 next hop' + + """ + 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 8 interfaces / links between R1 and R2,") + step( + "Configure IPv4 static route in R2 with 8 next hop" + "N1(21.1.1.2), N2(22.1.1.2), N3(23.1.1.2), N4(24.1.1.2)," + "N5(25.1.1.2), N6(26.1.1.2), N7(27.1.1.2),N8(28.1.1.2), Static" + "route next-hop present on R1" + ) + + step("Configure IBGP IPv4 peering between R2 and R3 router.") + + for addr_type in ADDR_TYPES: + # Enable static routes + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + } + ] + } + } + 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 + ) + logger.info("Verifying %s routes on r2", addr_type) + nh = [ + NEXT_HOP_IP["nh1"][addr_type], + NEXT_HOP_IP["nh2"][addr_type], + NEXT_HOP_IP["nh3"][addr_type], + NEXT_HOP_IP["nh4"][addr_type], + NEXT_HOP_IP["nh5"][addr_type], + NEXT_HOP_IP["nh6"][addr_type], + NEXT_HOP_IP["nh7"][addr_type], + NEXT_HOP_IP["nh8"][addr_type], + ] + + dut = "r2" + protocol = "static" + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + step("Configure redistribute static in BGP on R2 router") + for addr_type in ADDR_TYPES: + 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 to N8, one" + "by one from running config" + ) + for addr_type in ADDR_TYPES: + # delete static routes + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "delete": True, + } + ] + } + } + + 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 + ) + + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " still present in RIB".format(tc_name) + + step("Configure the static route with nexthop N1 to N8, one by" "one") + + for addr_type in ADDR_TYPES: + # add static routes + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + } + ] + } + } + + 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 + ) + + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + step("Shut nexthop interfaces N1 to N8 one by one") + for addr_type in ADDR_TYPES: + for nhp in range(0, 8): + intf = topo["routers"]["r2"]["links"]["r1-link" + str(nhp)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + + step("No shut the nexthop interfaces N1 to N8 one by one .") + + for addr_type in ADDR_TYPES: + for nhp in range(0, 8): + intf = topo["routers"]["r2"]["links"]["r1-link" + str(nhp)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, True) + + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \n" + "Error: Routes are missing in RIB".format(tc_name) + + step("Random shut of the nexthop interfaces") + randnum = random.randint(0, 7) + for addr_type in ADDR_TYPES: + intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type] + input_dict_5 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type], + } + ] + } + } + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_5, + next_hop=nhip, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + + step("Random no shut of the nexthop interfaces") + for addr_type in ADDR_TYPES: + intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, True) + nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_5, next_hop=nhip, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \n" + "Error: Routes are missing in RIB".format(tc_name) + + step("Reload the FRR router") + # stop/start -> restart FRR router and verify + stop_router(tgen, "r2") + sleep(5) + start_router(tgen, "r2") + + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + write_test_footer(tc_name) + + +def test_staticroute_with_ecmp_with_diff_AD_p0_tc4_ibgp(request): + """ + Verify static route ECMP functionality with 8 next hop + + """ + 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 8 interfaces / links between R1 and R2,") + step("Configure IBGP IPv4 peering between R2 and R3 router.") + reset_config_on_routers(tgen) + NEXT_HOP_IP = populate_nh() + nh_all = {} + for addr_type in ADDR_TYPES: + nh_all[addr_type] = [] + for nhp in range(1, 9): + nh_all[addr_type].append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + step( + "Configure IPv4 static route in R2 with 8 next hop" + "N1(21.1.1.2) AD 10, N2(22.1.1.2) AD 20, N3(23.1.1.2) AD 30," + "N4(24.1.1.2) AD 40, N5(25.1.1.2) AD 50, N6(26.1.1.2) AD 60," + "N7(27.1.1.2) AD 70, N8(28.1.1.2) AD 80, Static route next-hop" + "present on R1" + ) + for addr_type in ADDR_TYPES: + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + } + ] + } + } + 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 + ) + logger.info("Verifying %s routes on r2", addr_type) + + step( + "On R2, static route installed in RIB using " + "show ip route with 8 next hop, lowest AD nexthop is active" + ) + step("On R2, static route with lowest AD nexthop installed in FIB") + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Route with " + " lowest AD is missing in RIB".format(tc_name) + + nh = [] + for nhp in range(2, 9): + nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " with high AD are active in RIB".format(tc_name) + + step("Configure redistribute static in BGP on R2 router") + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": {"redistribute": [{"redist_type": "static"}]} + } + } + } + } + } + + logger.info("Configuring redistribute static") + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "After configuring them, route is always active with lowest AD" + "value and all the nexthop populated in RIB and FIB again " + ) + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Route with " + " lowest AD is missing in RIB".format(tc_name) + + step( + "Remove the static route configured with nexthop N1 to N8, one" + "by one from running config" + ) + + for addr_type in ADDR_TYPES: + # delete static routes + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + "delete": True, + } + ] + } + } + + 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( + "After removing the static route with N1 to N8 one by one, " + "route become active with next preferred nexthop and nexthop which " + "got removed is not shown in RIB and FIB" + ) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh_all[addr_type], + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " still present in RIB".format(tc_name) + + step("Configure the static route with nexthop N1 to N8, one by" "one") + for addr_type in ADDR_TYPES: + # add static routes + for nhp in range(1, 9): + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type], + "admin_distance": 10 * nhp, + } + ] + } + } + 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 with lowest AD nexthop installed in FIB") + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Route with " + " lowest AD is missing in RIB".format(tc_name) + + nh = [] + for nhp in range(2, 9): + nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " with high AD are active in RIB".format(tc_name) + + step("Shut nexthop interfaces N1 to N8 one by one") + for addr_type in ADDR_TYPES: + for nhp in range(0, 8): + intf = topo["routers"]["r2"]["links"]["r1-link" + str(nhp)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh_all[addr_type], + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " are still present in RIB".format(tc_name) + + step("No shut the nexthop interfaces N1 to N8 one by one .") + for addr_type in ADDR_TYPES: + for nhp in range(0, 8): + intf = topo["routers"]["r2"]["links"]["r1-link" + str(nhp)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, True) + + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Routes are" + " missing in RIB".format(tc_name) + + nh = [] + for nhp in range(2, 9): + nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " are missing in RIB".format(tc_name) + + step("Random shut of the nexthop interfaces") + randnum = random.randint(0, 7) + for addr_type in ADDR_TYPES: + intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, False) + nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type] + input_dict_5 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type], + } + ] + } + } + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_5, + next_hop=nhip, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \n" + "Error: Routes are still present in RIB".format(tc_name) + + step("Random no shut of the nexthop interfaces") + for addr_type in ADDR_TYPES: + intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"] + shutdown_bringup_interface(tgen, dut, intf, True) + nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_5, next_hop=nhip, protocol=protocol + ) + assert result is True, "Testcase {} : Failed \n" + "Error: Routes are missing in RIB".format(tc_name) + + step("Reload the FRR router") + # stop/start -> restart FRR router and verify + stop_router(tgen, "r2") + sleep(5) + start_router(tgen, "r2") + + step( + "After reload of FRR router, static route installed " + "in RIB and FIB properly ." + ) + for addr_type in ADDR_TYPES: + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": PREFIX1[addr_type], + "next_hop": NEXT_HOP_IP["nh1"][addr_type], + "admin_distance": 10, + } + ] + } + } + dut = "r2" + protocol = "static" + nh = NEXT_HOP_IP["nh1"][addr_type] + result = verify_rib( + tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True + ) + assert result is True, "Testcase {} : Failed \nError: Route with " + " lowest AD is missing in RIB".format(tc_name) + + nh = [] + for nhp in range(2, 9): + nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type]) + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + fib=True, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes " + " with high AD are active in RIB".format(tc_name) + + step("BGP neighbor remove and add") + for rtr in ["r2", "r3"]: + if "bgp" in topo["routers"][rtr].keys(): + delete_bgp = {rtr: {"bgp": {"delete": True}}} + result = create_router_bgp(tgen, topo, delete_bgp) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + reset_config_on_routers(tgen) + NEXT_HOP_IP = populate_nh() + step("Verify routes are still present after delete and add bgp") + dut = "r3" + protocol = "bgp" + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \n" + "Error: Routes still present in RIB".format(tc_name) + + step("Remove the redistribute static knob") + + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "redistribute": [ + {"redist_type": "static", "delete": True} + ] + } + } + } + } + } + } + + logger.info("Remove redistribute static") + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + step("verify that routes are deleted from R3 routing table") + dut = "r3" + protocol = "bgp" + result = verify_rib( + tgen, + addr_type, + dut, + input_dict_4, + next_hop=nh, + protocol=protocol, + expected=False, + ) + assert result is not True, "Testcase {} : Failed \nError: Routes are" + " strill present in RIB of R3".format(tc_name) + + step("Repeat above steps when EBGP IPv4 session is configure" "between R2 and R3") + + write_test_footer(tc_name) + + +def test_bgp_local_nexthop_p1_tc14_ibgp(request): + """ + Verify BGP did not install the static route when it receive route + with local next hop + + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + step("Configure BGP IPv4 session between R2 and R3") + step("Configure IPv4 static route on R2") + reset_config_on_routers(tgen) + + for addr_type in ADDR_TYPES: + # Enable static routes + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": NETWORK[addr_type], + "next_hop": topo["routers"]["r3"]["links"]["r2-link0"][ + addr_type + ].split("/")[0], + } + ] + } + } + + 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("Configure redistribute static in the BGP") + + 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("Verify R2 BGP table has IPv4 route") + dut = "r2" + result = verify_rib(tgen, addr_type, dut, input_dict_4) + assert result is True, "Testcase {} : Failed \nError: Routes is" + " missing in RIB of R2".format(tc_name) + + step(" Verify route did not install in the R3 BGP table, RIB/FIB") + dut = "r3" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4, expected=False) + assert result is not True, "Testcase {} : Failed \nError: Routes is" + " still present in BGP RIB of R2".format(tc_name) + + result = verify_rib(tgen, addr_type, dut, input_dict_4, expected=False) + assert result is not True, "Testcase {} : Failed \nError: Routes is" + " still present in RIB of R2".format(tc_name) + + write_test_footer(tc_name) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py new file mode 100644 index 0000000000..abc89b90ee --- /dev/null +++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py @@ -0,0 +1,1213 @@ +#!/usr/bin/python + +# +# Copyright (c) 2020 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 in the script. + +- Verify static route are blocked from route-map and prefix-list + applied in BGP nbrs +- Verify Static route when FRR connected to 2 TOR +""" + +import sys +import json +import time +import os +import pytest +import ipaddr +import ipaddress +from time import sleep +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/")) +# pylint: disable=C0413 +# Import topogen and topotest helpers +from mininet.topo import Topo +from lib.topogen import Topogen, get_topogen +from time import sleep + +from lib.common_config import ( + start_topology, + write_test_header, + write_test_footer, + reset_config_on_routers, + verify_kernel_ping, + verify_rib, + create_static_routes, + check_address_types, + step, + create_prefix_lists, + create_route_maps, + create_interfaces_cfg, + verify_prefix_lists, + verify_route_maps, +) +from lib.topolog import logger +from lib.bgp import ( + verify_bgp_convergence, + create_router_bgp, + clear_bgp_and_verify, + clear_bgp, +) +from lib.topojson import build_topo_from_json, build_config_from_json + +# Reading the data from JSON File for topology creation +jsonFile = "{}/static_routes_topo4_ibgp.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 variables +BGP_CONVERGENCE = False +ADDR_TYPES = check_address_types() +NETWORK = {"ipv4": "2.2.2.2/32", "ipv6": "22:22::2/128"} +NEXT_HOP_IP = {} + + +class CreateTopo(Topo): + """ + Test CreateTopo - 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): + """ + + Set up the pytest environment. + + * `mod`: module name + """ + global topo + 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) + + # Checking BGP convergence + global BGP_CONVERGENCE + global ADDR_TYPES + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + # Api call verify whether BGP is converged + 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(mod): + """ + Teardown the pytest environment. + + * `mod`: module name + """ + 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) + + +##################################################### +# +# Tests starting +# +##################################################### +def test_static_routes_rmap_pfxlist_p0_tc7_ibgp(request): + """ + Verify static route are blocked from route-map & prefix-list applied in BGP + nbrs + + """ + 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) + step("Configure holddown timer = 1 keep alive = 3 in all the neighbors") + step("verify bgp convergence before starting test case") + + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, bgp_convergence + ) + + step( + "Configure 4 IPv4 and 4 IPv6 nbrs with password with mismatch " + " authentication between FRR routers " + ) + + for addr_type in ADDR_TYPES: + # Api call to modfiy BGP timerse + input_dict = { + "r2": { + "bgp": { + "local_as": "200", + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link0": {"password": "r2"}, + "r2-link1": {"password": "r2"}, + "r2-link2": {"password": "r2"}, + "r2-link3": {"password": "r2"}, + } + }, + "r3": { + "dest_link": { + "r2-link0": {"password": "r2"}, + "r2-link1": {"password": "r2"}, + "r2-link2": {"password": "r2"}, + "r2-link3": {"password": "r2"}, + } + }, + } + } + } + }, + } + } + } + result = create_router_bgp(tgen, topo, deepcopy(input_dict)) + assert result is True, "Testcase {} :Failed \n Error: {}".format( + tc_name, result + ) + clear_bgp(tgen, addr_type, "r2") + + step(" All BGP nbrs are down as authentication is mismatch on both" " the sides") + + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is not True, "Testcase {} : " + "Failed \n BGP nbrs must be down. Error: {}".format(tc_name, bgp_convergence) + + step( + "Configure 4 IPv4 and 4 IPv6 nbrs with macthing password " + " authentication between FRR routers " + ) + for addr_type in ADDR_TYPES: + input_dict = { + "r2": { + "bgp": { + "local_as": "200", + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link0": {"password": "r1"}, + "r2-link1": {"password": "r1"}, + "r2-link2": {"password": "r1"}, + "r2-link3": {"password": "r1"}, + } + }, + "r3": { + "dest_link": { + "r2-link0": {"password": "r1"}, + "r2-link1": {"password": "r1"}, + "r2-link2": {"password": "r1"}, + "r2-link3": {"password": "r1"}, + } + }, + } + } + } + }, + } + } + } + result = create_router_bgp(tgen, topo, deepcopy(input_dict)) + assert result is True, "Testcase {} :Failed \n Error: {}".format( + tc_name, result + ) + + step("All BGP nbrs are up as authentication is matched now") + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is True, "Testcase {} : Failed \n " "Error: {}".format( + tc_name, bgp_convergence + ) + + step("Create prefix list P1 to permit VM3 & deny VM1 v4 & v6 routes") + step("Create prefix list P2 to permit VM6 IPv4 and IPv6 routes") + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r2": { + "prefix_lists": { + addr_type: { + "pf_list_1_{}".format(addr_type): [ + { + "seqid": 10, + "network": topo["routers"]["r2"]["links"]["vm3"][ + addr_type + ], + "action": "permit", + }, + { + "seqid": 20, + "network": topo["routers"]["r2"]["links"]["vm1"][ + addr_type + ], + "action": "deny", + }, + ], + "pf_list_2_{}".format(addr_type): [ + { + "seqid": 10, + "network": topo["routers"]["r2"]["links"]["vm6"][ + addr_type + ], + "action": "permit", + } + ], + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "Prefix list created with matching networks deny or permit " + "show ip prefix list" + ) + result = verify_prefix_lists(tgen, input_dict_2) + assert result is not True, "Testcase {} : Failed \n" + " Error: {}".format(tc_name, result) + + step("Redistribute all the routes (connected, static)") + input_dict_2_r1 = { + "r1": { + "bgp": { + "address_family": { + addr_type: { + "unicast": {"redistribute": [{"redist_type": "static"}]} + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2_r1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + input_dict_2_r2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": {"redistribute": [{"redist_type": "static"}]} + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2_r2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + input_dict_2_r3 = { + "r3": { + "bgp": { + "address_family": { + addr_type: { + "unicast": {"redistribute": [{"redist_type": "static"}]} + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2_r3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("configure redistribute connected in Router BGP") + + input_dict_2_r1 = { + "r1": { + "bgp": { + "address_family": { + addr_type: { + "unicast": {"redistribute": [{"redist_type": "connected"}]} + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2_r1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + input_dict_2_r3 = { + "r3": { + "bgp": { + "address_family": { + addr_type: { + "unicast": {"redistribute": [{"redist_type": "connected"}]} + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2_r3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + input_dict_2 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": {"redistribute": [{"redist_type": "connected"}]} + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Apply prefix list P1 on BGP neighbors 1 2 3 4 connected from " "frr r1") + # Configure prefix list to bgp neighbor + input_dict_4 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link0": { + "prefix_lists": [ + { + "name": "pf_list_1_{}".format( + addr_type + ), + "direction": "out", + } + ] + }, + "r2-link1": { + "prefix_lists": [ + { + "name": "pf_list_1_{}".format( + addr_type + ), + "direction": "out", + } + ] + }, + "r2-link2": { + "prefix_lists": [ + { + "name": "pf_list_1_{}".format( + addr_type + ), + "direction": "out", + } + ] + }, + "r2-link3": { + "prefix_lists": [ + { + "name": "pf_list_1_{}".format( + addr_type + ), + "direction": "out", + } + ] + }, + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Apply prefix list P2 on BGP nbrs 5 & 6 connected from FRR-2") + # Configure prefix list to bgp neighbor + input_dict_4 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link0": { + "prefix_lists": [ + { + "name": "pf_list_2_{}".format( + addr_type + ), + "direction": "out", + } + ] + }, + "r2-link1": { + "prefix_lists": [ + { + "name": "pf_list_2_{}".format( + addr_type + ), + "direction": "out", + } + ] + }, + "r2-link2": { + "prefix_lists": [ + { + "name": "pf_list_2_{}".format( + addr_type + ), + "direction": "out", + } + ] + }, + "r2-link3": { + "prefix_lists": [ + { + "name": "pf_list_2_{}".format( + addr_type + ), + "direction": "out", + } + ] + }, + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + clear_bgp_and_verify(tgen, topo, "r2") + + step( + "VM1 IPv4 and IPv6 Route which is denied using prefix list is " + "not present on FRR1 side routing table , also not able to " + "ping the routes show ip route" + ) + + dut = "r1" + protocol = "bgp" + ntwk_r2_vm1 = str( + ipaddress.ip_interface( + u"{}".format(topo["routers"]["r2"]["links"]["vm1"][addr_type]) + ).network + ) + input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}} + result4 = verify_rib( + tgen, addr_type, dut, input_dict, protocol=protocol, expected=False + ) + assert result4 is not True, "Testcase {} : Failed , VM1 route is " + "not filtered out via prefix list. \n Error: {}".format(tc_name, result4) + + step( + "VM4 and VM6 IPV4 and IPv6 address are present in local and " + "FRR2 routing table show ip bgp show ip route" + ) + + dut = "r2" + ntwk_r2_vm6 = str( + ipaddress.ip_interface( + u"{}".format(topo["routers"]["r2"]["links"]["vm6"][addr_type]) + ).network + ) + input_dict = {"r3": {"static_routes": [{"network": ntwk_r2_vm6}]}} + result4 = verify_rib(tgen, addr_type, dut, input_dict) + assert result4 is True, "Testcase {} : Failed.\n Error: {}".format( + tc_name, result4 + ) + + step("Remove prefix list from all the neighbors") + input_dict_4 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link0": { + "prefix_lists": [ + { + "name": "pf_list_1_{}".format( + addr_type + ), + "direction": "out", + "delete": True, + } + ] + }, + "r2-link1": { + "prefix_lists": [ + { + "name": "pf_list_1_{}".format( + addr_type + ), + "direction": "out", + "delete": True, + } + ] + }, + "r2-link2": { + "prefix_lists": [ + { + "name": "pf_list_1_{}".format( + addr_type + ), + "direction": "out", + "delete": True, + } + ] + }, + "r2-link3": { + "prefix_lists": [ + { + "name": "pf_list_1_{}".format( + addr_type + ), + "direction": "out", + "delete": True, + } + ] + }, + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + input_dict_4 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link0": { + "prefix_lists": [ + { + "name": "pf_list_2_{}".format( + addr_type + ), + "direction": "out", + "delete": True, + } + ] + }, + "r2-link1": { + "prefix_lists": [ + { + "name": "pf_list_2_{}".format( + addr_type + ), + "direction": "out", + "delete": True, + } + ] + }, + "r2-link2": { + "prefix_lists": [ + { + "name": "pf_list_2_{}".format( + addr_type + ), + "direction": "out", + "delete": True, + } + ] + }, + "r2-link3": { + "prefix_lists": [ + { + "name": "pf_list_2_{}".format( + addr_type + ), + "direction": "out", + "delete": True, + } + ] + }, + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + clear_bgp_and_verify(tgen, topo, "r2") + + step("Create RouteMap_1 with prefix list P1 and weight 50") + # Create route map + rmap_dict = { + "r2": { + "route_maps": { + "rmap_pf_list_1_{}".format(addr_type): [ + { + "action": "permit", + "set": {"weight": 50}, + "match": { + addr_type: { + "prefix_lists": "pf_list_1_{}".format(addr_type) + } + }, + } + ] + } + } + } + result = create_route_maps(tgen, rmap_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Create RouteMap_2 with prefix list P2 and weight 50") + # Create route map + rmap_dict = { + "r2": { + "route_maps": { + "rmap_pf_list_2_{}".format(addr_type): [ + { + "action": "permit", + "set": {"weight": 50}, + "match": { + addr_type: { + "prefix_lists": "pf_list_2_{}".format(addr_type) + } + }, + } + ] + } + } + } + result = create_route_maps(tgen, rmap_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Verify Route-map created verify using show route-map") + # verify rmap_pf_list_1 and rmap_pf_list_2 are present in router r2 + input_dict = { + "r2": { + "route_maps": [ + "rmap_pf_list_1_{}".format(addr_type), + "rmap_pf_list_2_{}".format(addr_type), + ] + } + } + result = verify_route_maps(tgen, input_dict) + assert result is not True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Apply policy RouteMap_1 nbrs 1 2 3 4 to FRR 1") + # Configure prefix list to bgp neighbor + input_dict_4 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link0": { + "route_maps": [ + { + "name": "rmap_pf_list_1_" + "{}".format(addr_type), + "direction": "out", + } + ] + }, + "r2-link1": { + "route_maps": [ + { + "name": "rmap_pf_list_1_" + "{}".format(addr_type), + "direction": "out", + } + ] + }, + "r2-link2": { + "route_maps": [ + { + "name": "rmap_pf_list_1_" + "{}".format(addr_type), + "direction": "out", + } + ] + }, + "r2-link3": { + "route_maps": [ + { + "name": "rmap_pf_list_1_" + "{}".format(addr_type), + "direction": "out", + } + ] + }, + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Apply policy RouteMap_2 nbrs 5 and 6 to FRR2") + # Configure prefix list to bgp neighbor + input_dict_4 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link0": { + "route_maps": [ + { + "name": "rmap_pf_list_2_" + "{}".format(addr_type), + "direction": "out", + } + ] + }, + "r2-link1": { + "route_maps": [ + { + "name": "rmap_pf_list_2_" + "{}".format(addr_type), + "direction": "out", + } + ] + }, + "r2-link2": { + "route_maps": [ + { + "name": "rmap_pf_list_2_" + "{}".format(addr_type), + "direction": "out", + } + ] + }, + "r2-link3": { + "route_maps": [ + { + "name": "rmap_pf_list_2_" + "{}".format(addr_type), + "direction": "out", + } + ] + }, + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "After applying to BGP neighbors verify VM1 IPv4 and IPv6 Route" + " which is denied using prefix list is not present on FRR side" + " routing table , also not able to ping the routes show ip route" + " and VM4 and VM6 IPV4 and IPv6 address are present in local and" + " FRR routing table show ip bgp show ip route" + ) + + dut = "r1" + protocol = "bgp" + ntwk_r2_vm1 = str( + ipaddress.ip_interface( + u"{}".format(topo["routers"]["r2"]["links"]["vm1"][addr_type]) + ).network + ) + input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}} + result4 = verify_rib( + tgen, addr_type, dut, input_dict, protocol=protocol, expected=False + ) + assert result4 is not True, "Testcase {} : Failed \n" "Error: {}".format( + tc_name, result4 + ) + + step("vm4 should be present in FRR1") + dut = "r1" + ntwk_r2_vm1 = str( + ipaddress.ip_interface( + u"{}".format(topo["routers"]["r1"]["links"]["vm4"][addr_type]) + ).network + ) + input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}} + result4 = verify_rib(tgen, addr_type, dut, input_dict) + assert result4 is True, "Testcase {} : Failed , VM1 route is " + "not filtered out via prefix list. \n Error: {}".format(tc_name, result4) + + step("vm4 should be present in FRR2") + dut = "r2" + ntwk_r2_vm1 = str( + ipaddress.ip_interface( + u"{}".format(topo["routers"]["r1"]["links"]["vm4"][addr_type]) + ).network + ) + input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}} + result4 = verify_rib(tgen, addr_type, dut, input_dict) + assert result4 is True, "Testcase {} : Failed , VM1 route is " + "not filtered out via prefix list. \n Error: {}".format(tc_name, result4) + + dut = "r3" + protocol = "bgp" + ntwk_r2_vm6 = str( + ipaddress.ip_interface( + u"{}".format(topo["routers"]["r2"]["links"]["vm6"][addr_type]) + ).network + ) + input_dict = {"r3": {"static_routes": [{"network": ntwk_r2_vm6}]}} + result4 = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) + assert result4 is True, "Testcase {} : Failed.\n Error: {}".format( + tc_name, result4 + ) + + write_test_footer(tc_name) + + +def test_static_routes_tor_p0_tc5_ibgp(request): + """Verify Static route when FRR connected to 2 TOR.""" + 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) + step("Configure link between FRR to FRR1 & FRR2 as shown in the topology.") + step("Attach 2 VMs (vm1 & vm2) to FRR, vm3 to FRR1 ,vm4 to FRR2.") + step("Configure Ipv4 and ipv6 addresses on all the interfaces.") + + reset_config_on_routers(tgen) + + def_nw = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"} + step( + "Configure the static route (ipv4 & ipv6) on FRR to vm3 and vm4 " + "with next hop as FRR1 and FRR2 respectively." + ) + for addr_type in ADDR_TYPES: + # Enable static routes + for vm in ["vm1", "vm2", "vm3", "vm6"]: + input_dict_4 = { + vm: { + "static_routes": [ + { + "network": def_nw[addr_type], + "next_hop": topo["routers"]["r2"]["links"][vm][ + addr_type + ].split("/")[0], + } + ] + } + } + 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 + ) + + input_dict_4 = { + "vm4": { + "static_routes": [ + { + "network": def_nw[addr_type], + "next_hop": topo["routers"]["r1"]["links"]["vm4"][ + addr_type + ].split("/")[0], + } + ] + } + } + 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 + ) + + input_dict_4 = { + "vm5": { + "static_routes": [ + { + "network": def_nw[addr_type], + "next_hop": topo["routers"]["r3"]["links"]["vm5"][ + addr_type + ].split("/")[0], + } + ] + } + } + 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 + ) + + input_dict_4 = { + "r1": { + "static_routes": [ + { + "network": topo["routers"]["vm1"]["links"]["r2"][ + addr_type + ].split("/")[0] + + "/16", + "next_hop": topo["routers"]["r2"]["links"]["r1-link0"][ + addr_type + ].split("/")[0], + }, + { + "network": topo["routers"]["vm2"]["links"]["r2"][ + addr_type + ].split("/")[0] + + "/16", + "next_hop": topo["routers"]["r2"]["links"]["r1-link0"][ + addr_type + ].split("/")[0], + }, + ] + } + } + + 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 + ) + + # Enable static routes + input_dict_4 = { + "r3": { + "static_routes": [ + { + "network": topo["routers"]["vm3"]["links"]["r2"][ + addr_type + ].split("/")[0] + + "/16", + "next_hop": topo["routers"]["r2"]["links"]["r3-link0"][ + addr_type + ].split("/")[0], + }, + { + "network": topo["routers"]["vm6"]["links"]["r2"][ + addr_type + ].split("/")[0] + + "/16", + "next_hop": topo["routers"]["r2"]["links"]["r3-link0"][ + addr_type + ].split("/")[0], + }, + ] + } + } + + 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 + ) + + # Enable static routes + input_dict_4 = { + "r2": { + "static_routes": [ + { + "network": topo["routers"]["vm4"]["links"]["r1"][ + addr_type + ].split("/")[0] + + "/16", + "next_hop": topo["routers"]["r1"]["links"]["r2-link0"][ + addr_type + ].split("/")[0], + }, + { + "network": topo["routers"]["vm5"]["links"]["r3"][ + addr_type + ].split("/")[0] + + "/16", + "next_hop": topo["routers"]["r3"]["links"]["r2-link0"][ + addr_type + ].split("/")[0], + }, + { + "network": topo["routers"]["vm4"]["links"]["r1"][addr_type], + "next_hop": topo["routers"]["r1"]["links"]["r2-link0"][ + addr_type + ].split("/")[0], + }, + { + "network": topo["routers"]["vm5"]["links"]["r3"][addr_type], + "next_hop": topo["routers"]["r3"]["links"]["r2-link0"][ + addr_type + ].split("/")[0], + }, + { + "network": topo["routers"]["r1"]["links"]["vm4"][addr_type], + "next_hop": topo["routers"]["r1"]["links"]["r2-link0"][ + addr_type + ].split("/")[0], + }, + { + "network": topo["routers"]["r3"]["links"]["vm5"][addr_type], + "next_hop": topo["routers"]["r3"]["links"]["r2-link0"][ + addr_type + ].split("/")[0], + }, + ] + } + } + + 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 + ) + sleep(10) + step( + "Ping from all the vms for both ipv4 and ipv6 address. " + "All the ping should pass." + ) + + step("ping from vm4 to vm1 vm2") + vm4tovm1 = topo["routers"]["vm1"]["links"]["r2"][addr_type].split("/")[0] + result = verify_kernel_ping(tgen, "vm4", vm4tovm1, count=1, addrtype=addr_type) + assert result is True, "Testcase {}:Failed \n Error: {}".format(tc_name, result) + + vm4tovm2 = topo["routers"]["vm2"]["links"]["r2"][addr_type].split("/")[0] + result = verify_kernel_ping(tgen, "vm4", vm4tovm2, count=1, addrtype=addr_type) + assert result is True, "Testcase {}:Failed \n Error: {}".format(tc_name, result) + + step("ping from vm5 to vm3 vm6") + vm5tovm3 = topo["routers"]["vm3"]["links"]["r2"][addr_type].split("/")[0] + result = verify_kernel_ping(tgen, "vm5", vm5tovm3, count=1, addrtype=addr_type) + assert result is True, "Testcase {}:Failed \n Error: {}".format(tc_name, result) + + vm5tovm6 = topo["routers"]["vm6"]["links"]["r2"][addr_type].split("/")[0] + result = verify_kernel_ping(tgen, "vm5", vm5tovm6, count=1, addrtype=addr_type) + assert result is True, "Testcase {}:Failed \n Error: {}".format(tc_name, result) + + write_test_footer(tc_name) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args))