diff options
Diffstat (limited to 'tests')
17 files changed, 1195 insertions, 117 deletions
diff --git a/tests/topotests/bgp-path-attributes-topo1/bgp_path_attributes.json b/tests/topotests/bgp-path-attributes-topo1/bgp_path_attributes.json index 15b7ec13be..de2bffa33d 100644 --- a/tests/topotests/bgp-path-attributes-topo1/bgp_path_attributes.json +++ b/tests/topotests/bgp-path-attributes-topo1/bgp_path_attributes.json @@ -12,6 +12,17 @@ "r2":{"ipv4":"auto", "ipv6":"auto"}, "r3":{"ipv4":"auto", "ipv6":"auto"} }, + "route_maps": { + "rmap_global": [{ + "action": "permit", + "set": { + "ipv6": { + "nexthop": "prefer-global" + } + } + } + ] + }, "bgp":{ "local_as":"555", "address_family": { @@ -20,8 +31,34 @@ "neighbor": { "r2": { "dest_link": { + "r1": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + }, + "r3": { + "dest_link": { "r1": {} } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } }, "r3": { "dest_link": { @@ -65,6 +102,27 @@ } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {} + } + }, + "r3": { + "dest_link": { + "r2": {} + } + }, + "r4": { + "dest_link": { + "r2-link1": {} + } + } + } + } } } } @@ -99,6 +157,27 @@ } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {} + } + }, + "r2": { + "dest_link": { + "r3": {} + } + }, + "r5": { + "dest_link": { + "r3": {} + } + } + } + } } } } @@ -128,6 +207,22 @@ } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4-link1": {} + } + }, + "r6": { + "dest_link": { + "r4": {} + } + } + } + } } } } @@ -156,6 +251,22 @@ } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r5": {} + } + }, + "r7": { + "dest_link": { + "r5": {} + } + } + } + } } } } @@ -184,6 +295,22 @@ } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r6": {} + } + }, + "r7": { + "dest_link": { + "r6": {} + } + } + } + } } } } @@ -212,6 +339,22 @@ } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r5": { + "dest_link": { + "r7": {} + } + }, + "r6": { + "dest_link": { + "r7": {} + } + } + } + } } } } diff --git a/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py b/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py index 9f92b4b290..3b2d9c25d7 100755 --- a/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py +++ b/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py @@ -76,13 +76,14 @@ from lib.common_config import ( write_test_footer, reset_config_on_routers, verify_rib, create_static_routes, create_prefix_lists, verify_prefix_lists, - create_route_maps + create_route_maps, check_address_types ) from lib.topolog import logger from lib.bgp import ( verify_bgp_convergence, create_router_bgp, clear_bgp_and_verify, verify_best_path_as_per_bgp_attribute, - verify_best_path_as_per_admin_distance + verify_best_path_as_per_admin_distance, modify_as_number, + verify_as_numbers ) from lib.topojson import build_topo_from_json, build_config_from_json @@ -95,6 +96,8 @@ try: except IOError: assert False, "Could not read file {}".format(jsonFile) +# Address read from env variables +ADDR_TYPES = check_address_types() #### class CreateTopo(Topo): @@ -119,6 +122,8 @@ def setup_module(mod): * `mod`: module name """ + global ADDR_TYPES + testsuite_run_time = time.asctime(time.localtime(time.time())) logger.info("Testsuite start time: %s", testsuite_run_time) logger.info("=" * 40) @@ -170,6 +175,7 @@ def teardown_module(): ## Testcases ## ##################################################### + def test_next_hop_attribute(request): """ Verifying route are not getting installed in, as next_hop is @@ -193,7 +199,7 @@ def test_next_hop_attribute(request): # Api call to advertise networks input_dict = { "r7": { - "bgp":{ + "bgp": { "address_family": { "ipv4": { "unicast": { @@ -206,6 +212,18 @@ def test_next_hop_attribute(request): } ] } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + { + "network": "200:50:2::/128" + }, + { + "network": "200:60:2::/128" + } + ] + } } } } @@ -218,9 +236,12 @@ def test_next_hop_attribute(request): # Verifying RIB routes dut = "r1" protocol = "bgp" - result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False) - assert result is not True, "Testcase {} : Failed \n Error: Routes still" \ - " present in RIB".format(tc_name) + # Verification should fail as nexthop-self is not enabled + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol, expected=False) + assert result is not True, "Testcase {} : Failed \n Error: "\ + "{} routes are not present in RIB".format(addr_type, tc_name) # Configure next-hop-self to bgp neighbor input_dict_1 = { @@ -237,6 +258,17 @@ def test_next_hop_attribute(request): } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {"next_hop_self": True} + } + } + } + } } } } @@ -254,11 +286,23 @@ def test_next_hop_attribute(request): } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"next_hop_self": True} + } + } + } + } } } } } } + result = create_router_bgp(tgen, topo, input_dict_1) assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) @@ -266,9 +310,11 @@ def test_next_hop_attribute(request): # Verifying RIB routes dut = "r1" protocol = "bgp" - result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) write_test_footer(tc_name) @@ -305,6 +351,18 @@ def test_aspath_attribute(request): } ] } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + { + "network": "200:50:2::/128" + }, + { + "network": "200:60:2::/128" + } + ] + } } } } @@ -322,6 +380,17 @@ def test_aspath_attribute(request): } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {"next_hop_self": True} + } + } + } + } } } } @@ -339,6 +408,17 @@ def test_aspath_attribute(request): } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"next_hop_self": True} + } + } + } + } } } } @@ -351,11 +431,136 @@ def test_aspath_attribute(request): # Verifying best path dut = "r1" attribute = "aspath" - result = verify_best_path_as_per_bgp_attribute(tgen, "ipv4", dut, - input_dict, attribute) + for addr_type in ADDR_TYPES: + result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut, + {"r7": input_dict["r7"]}, + attribute) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Modify AS-Path and verify best path is changed + # Create Prefix list + + input_dict_2 = { + "r3": { + "prefix_lists": { + "ipv4": { + "pf_ls_1_ipv4": [{ + "seqid": 10, + "network": "200.0.0.0/8", + "le": "32", + "action": "permit" + }] + }, + "ipv6": { + "pf_ls_1_ipv6": [{ + "seqid": 10, + "network": "200::/8", + "le": "128", + "action": "permit" + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Create route map + input_dict_3 = { + "r3": { + "route_maps": { + "RMAP_AS_PATH": [{ + "action": "permit", + "match": { + "ipv4": { + "prefix_lists": "pf_ls_1_ipv4" + } + }, + "set": { + "aspath": { + "as_num": "111 222", + "as_action": "prepend" + } + } + }, + { + "action": "permit", + "match": { + "ipv6": { + "prefix_lists": "pf_ls_1_ipv6" + } + }, + "set": { + "aspath": { + "as_num": "111 222", + "as_action": "prepend" + } + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + "r3": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r5": { + "dest_link": { + "r3": { + "route_maps": [ + {"name": "RMAP_AS_PATH", + "direction": "in"} + ] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r5": { + "dest_link": { + "r3": { + "route_maps": [ + {"name": "RMAP_AS_PATH", + "direction": "in"} + ] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) + # Verifying best path + dut = "r1" + attribute = "aspath" + for addr_type in ADDR_TYPES: + result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut, + {"r7": input_dict["r7"]}, + attribute) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + write_test_footer(tc_name) @@ -391,6 +596,18 @@ def test_localpref_attribute(request): } ] } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + { + "network": "200:50:2::/128" + }, + { + "network": "200:60:2::/128" + } + ] + } } } } @@ -408,6 +625,17 @@ def test_localpref_attribute(request): } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {"next_hop_self": True} + } + } + } + } } } } @@ -425,11 +653,23 @@ def test_localpref_attribute(request): } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"next_hop_self": True} + } + } + } + } } } } } } + result = create_router_bgp(tgen, topo, input_dict) assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) @@ -439,12 +679,20 @@ def test_localpref_attribute(request): "r2": { "prefix_lists": { "ipv4": { - "pf_ls_1": [{ + "pf_ls_1_ipv4": [{ "seqid": 10, "network": "200.0.0.0/8", "le": "32", "action": "permit" }] + }, + "ipv6": { + "pf_ls_1_ipv6": [{ + "seqid": 10, + "network": "200::/8", + "le": "128", + "action": "permit" + }] } } } @@ -459,13 +707,26 @@ def test_localpref_attribute(request): "route_maps": { "RMAP_LOCAL_PREF": [{ "action": "permit", + "seq_id": "10", "match": { "ipv4": { - "prefix_lists": "pf_ls_1" + "prefix_lists": "pf_ls_1_ipv4" + } + }, + "set": { + "localpref": 1111 + } + }, + { + "action": "permit", + "seq_id": "20", + "match": { + "ipv6": { + "prefix_lists": "pf_ls_1_ipv6" } }, "set": { - "localpref": 1000 + "localpref": 1111 } }] } @@ -483,9 +744,25 @@ def test_localpref_attribute(request): "ipv4": { "unicast": { "neighbor": { - "r1": { + "r4": { + "dest_link": { + "r2-link1": { + "route_maps": [ + {"name": "RMAP_LOCAL_PREF", + "direction": "in"} + ] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r4": { "dest_link": { - "r2": { + "r2-link1": { "route_maps": [ {"name": "RMAP_LOCAL_PREF", "direction": "in"} @@ -500,7 +777,6 @@ def test_localpref_attribute(request): } } } - result = create_router_bgp(tgen, topo, input_dict_4) assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) @@ -508,16 +784,66 @@ def test_localpref_attribute(request): # Verifying best path dut = "r1" attribute = "localpref" - result = verify_best_path_as_per_bgp_attribute(tgen, "ipv4", dut, - input_dict, attribute) + for addr_type in ADDR_TYPES: + result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut, + {"r7": input_dict["r7"]}, + attribute) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Modify route map + input_dict_3 = { + "r2": { + "route_maps": { + "RMAP_LOCAL_PREF": [{ + "action": "permit", + "seq_id": "10", + "match": { + "ipv4": { + "prefix_lists": "pf_ls_1_ipv4" + } + }, + "set": { + "localpref": 50 + } + }, + { + "action": "permit", + "seq_id": "20", + "match": { + "ipv6": { + "prefix_lists": "pf_ls_1_ipv6" + } + }, + "set": { + "localpref": 50 + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) + # Verifying best path + dut = "r1" + attribute = "localpref" + for addr_type in ADDR_TYPES: + result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut, + {"r7": input_dict["r7"]}, + attribute) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + write_test_footer(tc_name) def test_weight_attribute(request): - " Verifying WEIGHT attribute functionality" + """ + Test configure/modify weight attribute and + verify best path is installed as per highest weight + """ tgen = get_topogen() @@ -548,6 +874,18 @@ def test_weight_attribute(request): } ] } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + { + "network": "200:50:2::/128" + }, + { + "network": "200:60:2::/128" + } + ] + } } } } @@ -565,6 +903,17 @@ def test_weight_attribute(request): } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {"next_hop_self": True} + } + } + } + } } } } @@ -582,6 +931,17 @@ def test_weight_attribute(request): } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"next_hop_self": True} + } + } + } + } } } } @@ -596,12 +956,20 @@ def test_weight_attribute(request): "r1": { "prefix_lists": { "ipv4": { - "pf_ls_1": [{ + "pf_ls_1_ipv4": [{ "seqid": 10, "network": "200.0.0.0/8", "le": "32", "action": "permit" }] + }, + "ipv6": { + "pf_ls_1_ipv6": [{ + "seqid": 10, + "network": "200::/8", + "le": "128", + "action": "permit" + }] } } } @@ -616,9 +984,22 @@ def test_weight_attribute(request): "route_maps": { "RMAP_WEIGHT": [{ "action": "permit", + "seq_id": "5", "match": { "ipv4": { - "prefix_lists": "pf_ls_1" + "prefix_lists": "pf_ls_1_ipv4" + } + }, + "set": { + "weight": 500 + } + }, + { + "action": "permit", + "seq_id": "10", + "match": { + "ipv6": { + "prefix_lists": "pf_ls_1_ipv6" } }, "set": { @@ -652,6 +1033,22 @@ def test_weight_attribute(request): } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1": { + "route_maps": [ + {"name": "RMAP_WEIGHT", + "direction": "in"} + ] + } + } + } + } + } } } } @@ -664,16 +1061,66 @@ def test_weight_attribute(request): # Verifying best path dut = "r1" attribute = "weight" - result = verify_best_path_as_per_bgp_attribute(tgen, "ipv4", dut, - input_dict, attribute) + for addr_type in ADDR_TYPES: + result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut, + {"r7": input_dict["r7"]}, + attribute) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Modify route map + input_dict_3 = { + "r1": { + "route_maps": { + "RMAP_WEIGHT": [{ + "action": "permit", + "seq_id": "5", + "match": { + "ipv4": { + "prefix_lists": "pf_ls_1_ipv4" + } + }, + "set": { + "weight": 1000 + } + }, + { + "action": "permit", + "seq_id": "10", + "match": { + "ipv6": { + "prefix_lists": "pf_ls_1_ipv6" + } + }, + "set": { + "weight": 1000 + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) + # Verifying best path + dut = "r1" + attribute = "weight" + for addr_type in ADDR_TYPES: + result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut, + {"r7": input_dict["r7"]}, + attribute) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + write_test_footer(tc_name) def test_origin_attribute(request): - " Verifying ORIGIN attribute functionality" + """ + Test origin attribute and verify best path is + installed as per IGP>EGP>INCOMPLETE rule + """ tgen = get_topogen() @@ -704,6 +1151,18 @@ def test_origin_attribute(request): } ] } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + { + "network": "200:50:2::/128" + }, + { + "network": "200:60:2::/128" + } + ] + } } } } @@ -721,6 +1180,17 @@ def test_origin_attribute(request): } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {"next_hop_self": True} + } + } + } + } } } } @@ -738,6 +1208,17 @@ def test_origin_attribute(request): } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"next_hop_self": True} + } + } + } + } } } } @@ -752,6 +1233,14 @@ def test_origin_attribute(request): {"redist_type": "connected"} ] } + }, + "ipv6": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } } } } @@ -767,11 +1256,19 @@ def test_origin_attribute(request): "static_routes": [ { "network": "200.50.2.0/32", - "next_hop": "10.0.0.26" + "next_hop": "Null0" }, { "network": "200.60.2.0/32", - "next_hop": "10.0.0.26" + "next_hop": "Null0" + }, + { + "network": "200:50:2::/128", + "next_hop": "Null0" + }, + { + "network": "200:60:2::/128", + "next_hop": "Null0" } ] } @@ -780,23 +1277,24 @@ def test_origin_attribute(request): assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) - # Api call to redistribute static routes - - # Configure next-hop-self to bgp neighbor - # Verifying best path dut = "r1" attribute = "origin" - result = verify_best_path_as_per_bgp_attribute(tgen, "ipv4", dut, - input_dict, attribute) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + for addr_type in ADDR_TYPES: + result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut, + {"r4": input_dict["r4"]}, + attribute) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) write_test_footer(tc_name) def test_med_attribute(request): - " Verifying MED attribute functionality" + """ + Test configure/modify MED attribute and verify best path + is installed as per lowest med value + """ tgen = get_topogen() @@ -814,7 +1312,7 @@ def test_med_attribute(request): # Api call to advertise networks input_dict = { "r4": { - "bgp":{ + "bgp": { "address_family": { "ipv4": { "unicast": { @@ -827,49 +1325,102 @@ def test_med_attribute(request): } ] } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + { + "network": "200:50:2::/128" + }, + { + "network": "200:60:2::/128" + } + ] + } + } + } + } + }, + "r5": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "advertise_networks": [ + { + "network": "200.50.2.0/32" + }, + { + "network": "200.60.2.0/32" + } + ] + } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + { + "network": "200:50:2::/128" + }, + { + "network": "200:60:2::/128" + } + ] + } } } } } } + result = create_router_bgp(tgen, topo, input_dict) assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) - # Api call to advertise networks - - - # Configure next-hop-self to bgp neighbor - - # Create Prefix list - input_dict_3 = { + input_dict_2 = { "r2": { "prefix_lists": { "ipv4": { - "pf_ls_r2": [{ + "pf_ls_r2_ipv4": [{ "seqid": 10, "network": "200.0.0.0/8", "le": "32", "action": "permit" }] + }, + "ipv6": { + "pf_ls_r2_ipv6": [{ + "seqid": 20, + "network": "200::/8", + "le": "128", + "action": "permit" + }] } } }, "r3": { "prefix_lists": { "ipv4": { - "pf_ls_r3": [{ + "pf_ls_r3_ipv4": [{ "seqid": 10, "network": "200.0.0.0/8", "le": "32", "action": "permit" }] + }, + "ipv6": { + "pf_ls_r3_ipv6": [{ + "seqid": 20, + "network": "200::/8", + "le": "128", + "action": "permit" + }] } } } } - result = create_prefix_lists(tgen, input_dict_3) + result = create_prefix_lists(tgen, input_dict_2) assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) @@ -879,9 +1430,22 @@ def test_med_attribute(request): "route_maps": { "RMAP_MED_R2": [{ "action": "permit", + "seq_id": "10", "match": { "ipv4": { - "prefix_lists": "pf_ls_r2" + "prefix_lists": "pf_ls_r2_ipv4" + } + }, + "set": { + "med": 100 + } + }, + { + "action": "permit", + "seq_id": "20", + "match": { + "ipv6": { + "prefix_lists": "pf_ls_r2_ipv6" } }, "set": { @@ -894,9 +1458,22 @@ def test_med_attribute(request): "route_maps": { "RMAP_MED_R3": [{ "action": "permit", + "seq_id": "10", "match": { "ipv4": { - "prefix_lists": "pf_ls_r3" + "prefix_lists": "pf_ls_r3_ipv4" + } + }, + "set": { + "med": 10 + } + }, + { + "action": "permit", + "seq_id": "20", + "match": { + "ipv6": { + "prefix_lists": "pf_ls_r3_ipv6" } }, "set": { @@ -912,28 +1489,31 @@ def test_med_attribute(request): # Configure neighbor for route map input_dict_4 = { - "r5": { + "r2": { "bgp": { "address_family": { "ipv4": { "unicast": { - "advertise_networks": [ - { - "network": "200.50.2.0/32" + "neighbor": { + "r4": { + "dest_link": { + "r2-link1": { + "route_maps": [ + {"name": "RMAP_MED_R2", + "direction": "in"} + ] + } + } }, - { - "network": "200.60.2.0/32" + "r1": { + "dest_link": { + "r2": {"next_hop_self": True} + } } - ] + } } - } - } - } - }, - "r2": { - "bgp": { - "address_family": { - "ipv4": { + }, + "ipv6": { "unicast": { "neighbor": { "r4": { @@ -980,11 +1560,33 @@ def test_med_attribute(request): } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"next_hop_self": True} + } + }, + "r5": { + "dest_link": { + "r3": { + "route_maps": [ + {"name": "RMAP_MED_R3", + "direction": "in"} + ] + } + } + } + } + } } } } } } + result = create_router_bgp(tgen, topo, input_dict_4) assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) @@ -992,12 +1594,58 @@ def test_med_attribute(request): # Verifying best path dut = "r1" attribute = "med" - result = verify_best_path_as_per_bgp_attribute(tgen, "ipv4", dut, + for addr_type in ADDR_TYPES: + result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut, input_dict, attribute) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Modify route-map to set med value + input_dict_3 = { + "r3": { + "route_maps": { + "RMAP_MED_R3": [{ + "action": "permit", + "seq_id": "10", + "match": { + "ipv4": { + "prefix_lists": "pf_ls_r3_ipv4" + } + }, + "set": { + "med": 200 + } + }, + { + "action": "permit", + "seq_id": "20", + "match": { + "ipv6": { + "prefix_lists": "pf_ls_r3_ipv6" + } + }, + "set": { + "med": 200 + } + }] + } + } + } + + result = create_route_maps(tgen, input_dict_3) assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) - logger.info("Testcase %s :Passed \n", tc_name) + # Verifying best path + dut = "r1" + attribute = "med" + for addr_type in ADDR_TYPES: + result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut, + input_dict, attribute) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + write_test_footer(tc_name) # Uncomment next line for debugging # tgen.mininet_cli() @@ -1032,6 +1680,16 @@ def test_admin_distance(request): "network": "200.50.2.0/32", "admin_distance": 60, "next_hop": "10.0.0.18" + }, + { + "network": "200:50:2::/128", + "admin_distance": 80, + "next_hop": "fd00::1" + }, + { + "network": "200:50:2::/128", + "admin_distance": 60, + "next_hop": "fd00::1" } ] } @@ -1052,6 +1710,14 @@ def test_admin_distance(request): {"redist_type": "connected"} ] } + }, + "ipv6": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } } } } @@ -1064,10 +1730,45 @@ def test_admin_distance(request): # Verifying best path dut = "r1" attribute = "admin_distance" - result = verify_best_path_as_per_admin_distance(tgen, "ipv4", dut, - input_dict, attribute) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + + input_dict = { + "ipv4": { + "r2": { + "static_routes": [{ + "network": "200.50.2.0/32", + "admin_distance": 80, + "next_hop": "10.0.0.14" + }, + { + "network": "200.50.2.0/32", + "admin_distance": 60, + "next_hop": "10.0.0.18" + } + ] + } + }, + "ipv6": { + "r2": { + "static_routes": [{ + "network": "200:50:2::/128", + "admin_distance": 80, + "next_hop": "fd00::1" + }, + { + "network": "200:50:2::/128", + "admin_distance": 60, + "next_hop": "fd00::1" + }] + } + } + } + + for addr_type in ADDR_TYPES: + result = verify_best_path_as_per_admin_distance(tgen, addr_type, dut, + input_dict[addr_type], + attribute) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) write_test_footer(tc_name) diff --git a/tests/topotests/bgp_sender-as-path-loop-detection/__init__.py b/tests/topotests/bgp_sender-as-path-loop-detection/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_sender-as-path-loop-detection/__init__.py diff --git a/tests/topotests/bgp_sender-as-path-loop-detection/r1/bgpd.conf b/tests/topotests/bgp_sender-as-path-loop-detection/r1/bgpd.conf new file mode 100644 index 0000000000..a91b564bff --- /dev/null +++ b/tests/topotests/bgp_sender-as-path-loop-detection/r1/bgpd.conf @@ -0,0 +1,12 @@ +! exit1 +router bgp 65001 + neighbor 192.168.255.1 remote-as 65002 + address-family ipv4 unicast + neighbor 192.168.255.1 route-map prepend out + redistribute connected + exit-address-family + ! +! +route-map prepend permit 10 + set as-path prepend 65003 +! diff --git a/tests/topotests/bgp_sender-as-path-loop-detection/r1/zebra.conf b/tests/topotests/bgp_sender-as-path-loop-detection/r1/zebra.conf new file mode 100644 index 0000000000..9904bb4e16 --- /dev/null +++ b/tests/topotests/bgp_sender-as-path-loop-detection/r1/zebra.conf @@ -0,0 +1,9 @@ +! exit1 +interface lo + ip address 172.16.255.254/32 +! +interface r1-eth0 + ip address 192.168.255.2/30 +! +ip forwarding +! diff --git a/tests/topotests/bgp_sender-as-path-loop-detection/r2/bgpd.conf b/tests/topotests/bgp_sender-as-path-loop-detection/r2/bgpd.conf new file mode 100644 index 0000000000..6e8e89360f --- /dev/null +++ b/tests/topotests/bgp_sender-as-path-loop-detection/r2/bgpd.conf @@ -0,0 +1,8 @@ +! spine +router bgp 65002 + neighbor 192.168.255.2 remote-as 65001 + neighbor 192.168.255.2 solo + neighbor 192.168.254.2 remote-as 65003 + neighbor 192.168.254.2 solo + neighbor 192.168.254.2 sender-as-path-loop-detection +! diff --git a/tests/topotests/bgp_sender-as-path-loop-detection/r2/zebra.conf b/tests/topotests/bgp_sender-as-path-loop-detection/r2/zebra.conf new file mode 100644 index 0000000000..f0d357c5ff --- /dev/null +++ b/tests/topotests/bgp_sender-as-path-loop-detection/r2/zebra.conf @@ -0,0 +1,9 @@ +! spine +interface r2-eth0 + ip address 192.168.255.1/30 +! +interface r2-eth1 + ip address 192.168.254.1/30 +! +ip forwarding +! diff --git a/tests/topotests/bgp_sender-as-path-loop-detection/r3/bgpd.conf b/tests/topotests/bgp_sender-as-path-loop-detection/r3/bgpd.conf new file mode 100644 index 0000000000..8962befad2 --- /dev/null +++ b/tests/topotests/bgp_sender-as-path-loop-detection/r3/bgpd.conf @@ -0,0 +1,4 @@ +! exit2 +router bgp 65003 + neighbor 192.168.254.1 remote-as 65002 +! diff --git a/tests/topotests/bgp_sender-as-path-loop-detection/r3/zebra.conf b/tests/topotests/bgp_sender-as-path-loop-detection/r3/zebra.conf new file mode 100644 index 0000000000..a10fe3a3c7 --- /dev/null +++ b/tests/topotests/bgp_sender-as-path-loop-detection/r3/zebra.conf @@ -0,0 +1,6 @@ +! exit2 +interface r3-eth0 + ip address 192.168.254.2/30 +! +ip forwarding +! diff --git a/tests/topotests/bgp_sender-as-path-loop-detection/test_bgp_sender-as-path-loop-detection.py b/tests/topotests/bgp_sender-as-path-loop-detection/test_bgp_sender-as-path-loop-detection.py new file mode 100644 index 0000000000..708464864a --- /dev/null +++ b/tests/topotests/bgp_sender-as-path-loop-detection/test_bgp_sender-as-path-loop-detection.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python + +# +# test_bgp_sender-as-path-loop-detection.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2019 by +# Donatas Abraitis <donatas.abraitis@gmail.com> +# +# 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 NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF 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. +# + +""" +Test if neighbor <neighbor> sender-as-path-loop-detection +command works as expeced. +""" + +import os +import sys +import json +import time +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, '../')) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger +from mininet.topo import Topo + +class TemplateTopo(Topo): + def build(self, *_args, **_opts): + tgen = get_topogen(self) + + for routern in range(1, 4): + tgen.add_router('r{}'.format(routern)) + + switch = tgen.add_switch('s1') + switch.add_link(tgen.gears['r1']) + switch.add_link(tgen.gears['r2']) + + switch = tgen.add_switch('s2') + switch.add_link(tgen.gears['r2']) + switch.add_link(tgen.gears['r3']) + +def setup_module(mod): + tgen = Topogen(TemplateTopo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for i, (rname, router) in enumerate(router_list.iteritems(), 1): + router.load_config( + TopoRouter.RD_ZEBRA, + os.path.join(CWD, '{}/zebra.conf'.format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, + os.path.join(CWD, '{}/bgpd.conf'.format(rname)) + ) + + tgen.start_router() + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + +def test_bgp_sender_as_path_loop_detection(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router = tgen.gears['r2'] + + def _bgp_converge(router): + output = json.loads(router.vtysh_cmd("show ip bgp neighbor 192.168.255.2 json")) + expected = { + '192.168.255.2': { + 'bgpState': 'Established', + 'addressFamilyInfo': { + 'ipv4Unicast': { + 'acceptedPrefixCounter': 2 + } + } + } + } + return topotest.json_cmp(output, expected) + + def _bgp_has_route_from_r1(router): + output = json.loads(router.vtysh_cmd("show ip bgp 172.16.255.254/32 json")) + expected = { + 'paths': [ + { + 'aspath': { + 'segments': [ + { + 'type': 'as-sequence', + 'list': [ + 65001, + 65003 + ] + } + ], + 'length': 2 + } + } + ] + } + return topotest.json_cmp(output, expected) + + def _bgp_suppress_route_to_r3(router): + output = json.loads(router.vtysh_cmd("show ip bgp neighbor 192.168.254.2 advertised-routes json")) + expected = { + 'totalPrefixCounter': 0 + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_converge, router) + success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + + assert result is None, 'Failed bgp convergence in "{}"'.format(router) + + test_func = functools.partial(_bgp_has_route_from_r1, router) + success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + + assert result is None, 'Failed to see a route from r1 in "{}"'.format(router) + + test_func = functools.partial(_bgp_suppress_route_to_r3, router) + success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + + assert result is None, 'Route 172.16.255.254/32 should not be sent to r3 "{}"'.format(router) + +if __name__ == '__main__': + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/ldp-vpls-topo1/r1/zebra.conf b/tests/topotests/ldp-vpls-topo1/r1/zebra.conf index edfa1780a9..ea047355ad 100644 --- a/tests/topotests/ldp-vpls-topo1/r1/zebra.conf +++ b/tests/topotests/ldp-vpls-topo1/r1/zebra.conf @@ -14,17 +14,14 @@ interface lo ! interface r1-eth0 description to s1 - no link-detect ! interface r1-eth1 description to s4 ip address 10.0.1.1/24 - no link-detect ! interface r1-eth2 description to s5 ip address 10.0.2.1/24 - no link-detect ! ip forwarding ! diff --git a/tests/topotests/ldp-vpls-topo1/r2/zebra.conf b/tests/topotests/ldp-vpls-topo1/r2/zebra.conf index 6b95efdce8..c244442876 100644 --- a/tests/topotests/ldp-vpls-topo1/r2/zebra.conf +++ b/tests/topotests/ldp-vpls-topo1/r2/zebra.conf @@ -13,17 +13,14 @@ interface lo ! interface r2-eth0 description to s2 - no link-detect ! interface r2-eth1 description to s4 ip address 10.0.1.2/24 - no link-detect ! interface r2-eth2 description to s6 ip address 10.0.3.2/24 - no link-detect ! ip forwarding ! diff --git a/tests/topotests/ldp-vpls-topo1/r3/zebra.conf b/tests/topotests/ldp-vpls-topo1/r3/zebra.conf index 85ec68ff32..6b1eaa2ca0 100644 --- a/tests/topotests/ldp-vpls-topo1/r3/zebra.conf +++ b/tests/topotests/ldp-vpls-topo1/r3/zebra.conf @@ -13,17 +13,14 @@ interface lo ! interface r3-eth0 description to s3 - no link-detect ! interface r3-eth1 description to s5 ip address 10.0.2.3/24 - no link-detect ! interface r3-eth2 description to s6 ip address 10.0.3.3/24 - no link-detect ! ip forwarding ! diff --git a/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py b/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py index ce651c50cd..0fae64402a 100755 --- a/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py +++ b/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py @@ -257,6 +257,7 @@ def test_ldp_pseudowires_after_link_down(): # Shut down r1-r2 link */ tgen = get_topogen() tgen.gears['r1'].peer_link_enable('r1-eth1', False) + topotest.sleep(5, "Waiting for the network to reconverge") # check if the pseudowire is still up (using an alternate path for nexthop resolution) for rname in ['r1', 'r2', 'r3']: diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index 7ec584bf5f..a8354f4c77 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -112,6 +112,8 @@ def create_router_bgp(tgen, topo, input_dict=None, build=False): input_dict = deepcopy(topo) else: topo = topo["routers"] + input_dict = deepcopy(input_dict) + for router in input_dict.keys(): if "bgp" not in input_dict[router]: logger.debug("Router %s: 'bgp' not present in input_dict", router) @@ -220,7 +222,7 @@ def __create_bgp_unicast_neighbor(tgen, topo, input_dict, router, logger.debug("Entering lib API: __create_bgp_unicast_neighbor()") add_neigh = True - if "router bgp "in config_data: + if "router bgp" in config_data: add_neigh = False bgp_data = input_dict[router]["bgp"]["address_family"] @@ -1366,7 +1368,7 @@ def verify_bgp_attributes(tgen, addr_type, dut, static_routes, rmap_name, logger.debug("Exiting lib API: verify_bgp_attributes()") return True -@retry(attempts=3, wait=2, return_is_str=True) +@retry(attempts=4, wait=2, return_is_str=True, initial_wait=2) def verify_best_path_as_per_bgp_attribute(tgen, addr_type, router, input_dict, attribute): """ @@ -1422,16 +1424,14 @@ def verify_best_path_as_per_bgp_attribute(tgen, addr_type, router, input_dict, rnode = tgen.routers()[router] - # TODO get addr_type from address - # Verifying show bgp json command = "show bgp {} json".format(addr_type) - sleep(2) + sleep(5) logger.info("Verifying router %s RIB for best path:", router) sh_ip_bgp_json = run_frr_cmd(rnode, command, isjson=True) for route_val in input_dict.values(): - net_data = route_val["bgp"]["address_family"]["ipv4"]["unicast"] + net_data = route_val["bgp"]["address_family"][addr_type]["unicast"] networks = net_data["advertise_networks"] for network in networks: route = network["network"] @@ -1503,8 +1503,8 @@ def verify_best_path_as_per_bgp_attribute(tgen, addr_type, router, input_dict, if route in rib_routes_json: st_found = True # Verify next_hop in rib_routes_json - if rib_routes_json[route][0]["nexthops"][0]["ip"] == \ - _next_hop: + if rib_routes_json[route][0]["nexthops"][0]["ip"] in \ + attribute_dict: nh_found = True else: errormsg = "Incorrect Nexthop for BGP route {} in " \ @@ -1526,7 +1526,6 @@ def verify_best_path_as_per_bgp_attribute(tgen, addr_type, router, input_dict, return True -@retry(attempts=3, wait=2, return_is_str=True) def verify_best_path_as_per_admin_distance(tgen, addr_type, router, input_dict, attribute): """ @@ -1568,7 +1567,7 @@ def verify_best_path_as_per_admin_distance(tgen, addr_type, router, input_dict, rnode = tgen.routers()[router] - sleep(2) + sleep(5) logger.info("Verifying router %s RIB for best path:", router) # Show ip route cmd diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index 38b97cba2d..9f2fef52ea 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -1202,6 +1202,7 @@ def create_route_maps(tgen, input_dict, build=False): "large_comm_list", {}) set_action = set_data.setdefault("set_action", None) nexthop = set_data.setdefault("nexthop", None) + origin = set_data.setdefault("origin", None) # Local Preference if local_preference: @@ -1212,6 +1213,10 @@ def create_route_maps(tgen, input_dict, build=False): if metric: rmap_data.append("set metric {} \n".format(metric)) + # Origin + if origin: + rmap_data.append("set origin {} \n".format(origin)) + # AS Path Prepend if as_path: as_num = as_path.setdefault("as_num", None) @@ -1628,9 +1633,10 @@ def verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None): static_routes = input_dict[routerInput]["static_routes"] st_found = False nh_found = False - found_routes = [] - missing_routes = [] for static_route in static_routes: + found_routes = [] + missing_routes = [] + network = static_route["network"] if "no_of_ip" in static_route: no_of_ip = static_route["no_of_ip"] @@ -1667,6 +1673,7 @@ def verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None): return errormsg else: missing_routes.append(st_rt) + if nh_found: logger.info("Found next_hop %s for all routes in RIB of" " router %s\n", next_hop, dut) @@ -1679,37 +1686,69 @@ def verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None): logger.info("Verified routes in router %s RIB, found routes" " are: %s\n", dut, found_routes) - advertise_network = input_dict[routerInput].setdefault( - "advertise_networks", {}) - if advertise_network: - found_routes = [] - missing_routes = [] - found = False - for advertise_network_dict in advertise_network: - start_ip = advertise_network_dict["network"] - if "no_of_network" in advertise_network_dict: - no_of_network = advertise_network_dict["no_of_network"] - else: - no_of_network = 0 + continue - # Generating IPs for verification - ip_list = generate_ips(start_ip, no_of_network) - for st_rt in ip_list: - st_rt = str(ipaddr.IPNetwork(unicode(st_rt))) + if "bgp" in input_dict[routerInput]: + if 'advertise_networks' in input_dict[routerInput]["bgp"]\ + ["address_family"][addr_type]["unicast"]: - if st_rt in rib_routes_json: - found = True - found_routes.append(st_rt) + found_routes = [] + missing_routes = [] + advertise_network = input_dict[routerInput]["bgp"]\ + ["address_family"][addr_type]["unicast"]\ + ["advertise_networks"] + + for advertise_network_dict in advertise_network: + start_ip = advertise_network_dict["network"] + if "no_of_network" in advertise_network_dict: + no_of_network = advertise_network_dict["no_of_network"] else: - missing_routes.append(st_rt) + no_of_network = 1 + + # Generating IPs for verification + ip_list = generate_ips(start_ip, no_of_network) + for st_rt in ip_list: + st_rt = str(ipaddr.IPNetwork(unicode(st_rt))) + + found = False + nh_found = False + if st_rt in rib_routes_json: + found = True + found_routes.append(st_rt) + + if next_hop: + if type(next_hop) is not list: + next_hop = [next_hop] + + for index, nh in enumerate(next_hop): + if rib_routes_json[st_rt][0]\ + ['nexthops'][index]['ip'] == nh: + nh_found = True + else: + errormsg=("Nexthop {} is Missing" + " for {} route {} in " + "RIB of router {}\n".\ + format(next_hop, + protocol, + st_rt, dut)) + return errormsg - if not found and len(missing_routes) > 0: - errormsg = "Missing route in RIB of router {}, are: {}" \ - " \n".format(dut, missing_routes) - return errormsg + else: + missing_routes.append(st_rt) - logger.info("Verified routes in router %s RIB, found routes" - " are: %s", dut, found_routes) + if nh_found: + logger.info("Found next_hop {} for all routes in RIB" + " of router {}\n".format(next_hop, dut)) + + if not found and len(missing_routes) > 0: + errormsg = ("Missing {} route in RIB of router {}, " + "routes: {} \n".\ + format(addr_type, dut, missing_routes)) + return errormsg + + logger.info("Verified {} routes in router {} RIB, found" + " routes are: {}\n".\ + format(addr_type, dut, found_routes)) logger.debug("Exiting lib API: verify_rib()") return True diff --git a/tests/topotests/lib/topogen.py b/tests/topotests/lib/topogen.py index d7145c3be0..6859f5a076 100644 --- a/tests/topotests/lib/topogen.py +++ b/tests/topotests/lib/topogen.py @@ -61,6 +61,7 @@ from mininet.cli import CLI from lib import topotest from lib.topolog import logger, logger_config +from lib.topotest import set_sysctl CWD = os.path.dirname(os.path.realpath(__file__)) @@ -676,6 +677,10 @@ class TopoRouter(TopoGear): if result != '': self.tgen.set_error(result) + else: + # Enable MPLS processing on all interfaces. + for interface in self.links.keys(): + set_sysctl(nrouter, 'net.mpls.conf.{}.input'.format(interface), 1) return result |
