diff --git a/ansible/library/exabgp.py b/ansible/library/exabgp.py index e051d6f0259..1c8f938237d 100644 --- a/ansible/library/exabgp.py +++ b/ansible/library/exabgp.py @@ -187,7 +187,7 @@ def setup_exabgp_conf(name, router_id, local_ip, peer_ip, local_asn, peer_asn, p def remove_exabgp_conf(name): try: os.remove("/etc/exabgp/%s.conf" % name) - except e: + except Exception: pass @@ -200,7 +200,7 @@ def setup_exabgp_supervisord_conf(name): def remove_exabgp_supervisord_conf(name): try: os.remove("/etc/supervisor/conf.d/exabgp-%s.conf" % name) - except e: + except Exception: pass def setup_exabgp_processor(): diff --git a/ansible/roles/test/files/ptftests/fib.py b/ansible/roles/test/files/ptftests/fib.py index c600aa2d921..5686bf516c0 100644 --- a/ansible/roles/test/files/ptftests/fib.py +++ b/ansible/roles/test/files/ptftests/fib.py @@ -72,6 +72,13 @@ def __getitem__(self, ip): elif ip.version is 6: return self._ipv6_lpm_dict[str(ip)] + def __contains__(self, ip): + ip_obj = ip_address(unicode(ip)) + if ip_obj.version == 4: + return self._ipv4_lpm_dict.contains(ip) + elif ip_obj.version == 6: + return self._ipv6_lpm_dict.contains(ip) + def ipv4_ranges(self): return self._ipv4_lpm_dict.ranges() diff --git a/ansible/roles/test/files/ptftests/fib_test.py b/ansible/roles/test/files/ptftests/fib_test.py index a51c0c5cfe3..1ed3ba477a4 100644 --- a/ansible/roles/test/files/ptftests/fib_test.py +++ b/ansible/roles/test/files/ptftests/fib_test.py @@ -149,8 +149,9 @@ def check_ip_ranges(self, ipv4=True): ip_ranges = self.fib.ipv6_ranges() for ip_range in ip_ranges: - next_hop = self.fib[ip_range.get_first_ip()] - self.check_ip_range(ip_range, next_hop, ipv4) + if ip_range.get_first_ip() in self.fib: + next_hop = self.fib[ip_range.get_first_ip()] + self.check_ip_range(ip_range, next_hop, ipv4) def check_ip_range(self, ip_range, next_hop, ipv4=True): # Get the expected list of ports that would receive the packets diff --git a/ansible/roles/test/files/ptftests/lpm.py b/ansible/roles/test/files/ptftests/lpm.py index f30fdcef4e9..609613d4eea 100644 --- a/ansible/roles/test/files/ptftests/lpm.py +++ b/ansible/roles/test/files/ptftests/lpm.py @@ -103,3 +103,6 @@ def ranges(self): interval = self.IpInterval(sorted_boundaries[index], ip_address(u'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff')) ranges.append(interval) return ranges + + def contains(self, key): + return key in self._subnet_tree diff --git a/tests/bgp/test_bgp_speaker.py b/tests/bgp/test_bgp_speaker.py index ff2a9dac2cf..ffdcf9a2a1e 100644 --- a/tests/bgp/test_bgp_speaker.py +++ b/tests/bgp/test_bgp_speaker.py @@ -3,6 +3,8 @@ import time import logging import requests +import ipaddress + from tests.common.fixtures.ptfhost_utils import copy_ptftests_directory # lgtm[py/unused-import] from tests.common.fixtures.ptfhost_utils import change_mac_addresses # lgtm[py/unused-import] @@ -10,6 +12,7 @@ from tests.ptf_runner import ptf_runner from tests.common.utilities import wait_tcp_connection + pytestmark = [ pytest.mark.topology('t0'), pytest.mark.device_type('vs') @@ -22,28 +25,30 @@ def generate_ips(num, prefix, exclude_ips): prefix = IPNetwork(prefix) exclude_ips.append(prefix.broadcast) exclude_ips.append(prefix.network) - available_ips = list(prefix) - - if len(available_ips) - len(exclude_ips)< num: - raise Exception("Not enough available IPs") generated_ips = [] - for available_ip in available_ips: + for available_ip in prefix: if available_ip not in exclude_ips: generated_ips.append(IPNetwork(str(available_ip) + '/' + str(prefix.prefixlen))) if len(generated_ips) == num: break + else: + raise Exception("Not enough available IPs") return generated_ips - def announce_route(ptfip, neighbor, route, nexthop, port): + change_route("announce", ptfip, neighbor, route, nexthop, port) + +def withdraw_route(ptfip, neighbor, route, nexthop, port): + change_route("withdraw", ptfip, neighbor, route, nexthop, port) + +def change_route(operation, ptfip, neighbor, route, nexthop, port): url = "http://%s:%d" % (ptfip, port) - data = {"command": "neighbor %s announce route %s next-hop %s" % (neighbor, route, nexthop)} + data = {"command": "neighbor %s %s route %s next-hop %s" % (neighbor, operation, route, nexthop)} r = requests.post(url, data=data) assert r.status_code == 200 - @pytest.fixture(scope="module") def common_setup_teardown(duthost, ptfhost, localhost): @@ -55,7 +60,11 @@ def common_setup_teardown(duthost, ptfhost, localhost): mg_facts = duthost.minigraph_facts(host=duthost.hostname)['ansible_facts'] interface_facts = duthost.interface_facts()['ansible_facts'] - res = duthost.shell("sonic-cfggen -m -d -y /etc/sonic/constants.yml -v \"constants.deployment_id_asn_map[DEVICE_METADATA['localhost']['deployment_id']]\"") + constants_stat = duthost.stat(path="/etc/sonic/constants.yml") + if constants_stat["stat"]["exists"]: + res = duthost.shell("sonic-cfggen -m -d -y /etc/sonic/constants.yml -v \"constants.deployment_id_asn_map[DEVICE_METADATA['localhost']['deployment_id']]\"") + else: + res = duthost.shell("sonic-cfggen -m -d -y /etc/sonic/deployment_id_asn_map.yml -v \"deployment_id_asn_map[DEVICE_METADATA['localhost']['deployment_id']]\"") bgp_speaker_asn = res['stdout'] vlan_ips = generate_ips(3, "%s/%s" % (mg_facts['minigraph_vlan_interfaces'][0]['addr'], @@ -83,6 +92,19 @@ def common_setup_teardown(duthost, ptfhost, localhost): vlan_ports.append(mg_facts['minigraph_port_indices'][mg_facts['minigraph_vlans'][mg_facts['minigraph_vlan_interfaces'][0]['attachto']]['members'][i]]) logging.info("vlan_ports: %s" % str(vlan_ports)) + # Generate ipv6 nexthops + vlan_ipv6_entry = mg_facts['minigraph_vlan_interfaces'][1] + vlan_ipv6_prefix = "%s/%s" % (vlan_ipv6_entry["addr"], vlan_ipv6_entry["prefixlen"]) + vlan_ipv6_address = vlan_ipv6_entry["addr"] + vlan_if_name = vlan_ipv6_entry['attachto'] + nexthops_ipv6 = generate_ips(3, vlan_ipv6_prefix, [IPAddress(vlan_ipv6_address)]) + logging.info("Generated nexthops_ipv6: %s" % str(nexthops_ipv6)) + + # Set ipv6 nexthop addresses on the ptf interfaces + for nh in nexthops_ipv6: + duthost.command("ip -6 route flush %s/64" % nh.ip) + duthost.command("ip -6 route add %s/64 dev %s" % (nh.ip, vlan_if_name)) + logging.info("setup ip/routes in ptf") ptfhost.shell("ifconfig eth%d %s" % (vlan_ports[0], vlan_ips[0])) ptfhost.shell("ifconfig eth%d:0 %s" % (vlan_ports[0], speaker_ips[0])) @@ -94,6 +116,10 @@ def common_setup_teardown(duthost, ptfhost, localhost): ptfhost.shell("ip route flush %s/%d" % (lo_addr, lo_addr_prefixlen)) ptfhost.shell("ip route add %s/%d via %s" % (lo_addr, lo_addr_prefixlen, vlan_addr)) + logging.info("setup ip/routes in ptf") + for i in [0, 1, 2]: + ptfhost.shell("ip -6 addr add %s dev eth%d:%d" % (nexthops_ipv6[i], vlan_ports[0], i)) + logging.info("Start exabgp on ptf") for i in range(0, 3): local_ip = str(speaker_ips[i].ip) @@ -115,12 +141,17 @@ def common_setup_teardown(duthost, ptfhost, localhost): logging.info("########### Done setup for bgp speaker testing ###########") - yield ptfip, mg_facts, interface_facts, vlan_ips, speaker_ips, port_num, http_ready + yield ptfip, mg_facts, interface_facts, vlan_ips, nexthops_ipv6, vlan_if_name, speaker_ips, port_num, http_ready logging.info("########### Teardown for bgp speaker testing ###########") for i in range(0, 3): ptfhost.exabgp(name="bgps%d" % i, state="absent") + logging.info("exabgp stopped") + + for nh in nexthops_ipv6: + duthost.command("ip -6 route flush %s/64" % nh.ip) + logging.info("Flushed ipv6 nexthop routes from dut") for ip in vlan_ips: duthost.command("ip route flush %s/32" % ip.ip, module_ignore_errors=True) @@ -131,7 +162,7 @@ def common_setup_teardown(duthost, ptfhost, localhost): def test_bgp_speaker_bgp_sessions(common_setup_teardown, duthost, ptfhost, collect_techsupport): """Setup bgp speaker on T0 topology and verify bgp sessions are established """ - ptfip, mg_facts, interface_facts, vlan_ips, speaker_ips, port_num, http_ready = common_setup_teardown + ptfip, mg_facts, interface_facts, vlan_ips, _, _, speaker_ips, port_num, http_ready = common_setup_teardown assert http_ready logging.info("Wait some time to verify that bgp sessions are established") @@ -142,21 +173,20 @@ def test_bgp_speaker_bgp_sessions(common_setup_teardown, duthost, ptfhost, colle assert str(speaker_ips[2].ip) in bgp_facts["bgp_neighbors"], "No bgp session with PTF" -@pytest.mark.parametrize("ipv4, ipv6, mtu", [pytest.param(True, False, 1514)]) -def test_bgp_speaker_announce_routes(common_setup_teardown, testbed, duthost, ptfhost, ipv4, ipv6, mtu, collect_techsupport): +def bgp_speaker_announce_routes_common(common_setup_teardown, testbed, duthost, ptfhost, ipv4, ipv6, mtu, family, prefix, nexthop_ips): """Setup bgp speaker on T0 topology and verify routes advertised by bgp speaker is received by T0 TOR """ - ptfip, mg_facts, interface_facts, vlan_ips, speaker_ips, port_num, http_ready = common_setup_teardown + ptfip, mg_facts, interface_facts, vlan_ips, _, vlan_if_name, speaker_ips, port_num, http_ready = common_setup_teardown assert http_ready logging.info("announce route") peer_range = mg_facts['minigraph_bgp_peers_with_range'][0]['ip_range'][0] lo_addr = mg_facts['minigraph_lo_interfaces'][0]['addr'] - lo_addr_prefixlen = int(mg_facts['minigraph_lo_interfaces'][0]['prefixlen']) - prefix = '10.10.10.0/26' - announce_route(ptfip, lo_addr, prefix, vlan_ips[1].ip, port_num[0]) - announce_route(ptfip, lo_addr, prefix, vlan_ips[2].ip, port_num[1]) + + logging.info("Announce ip%s prefixes over ipv4 bgp sessions" % family) + announce_route(ptfip, lo_addr, prefix, nexthop_ips[1].ip, port_num[0]) + announce_route(ptfip, lo_addr, prefix, nexthop_ips[2].ip, port_num[1]) announce_route(ptfip, lo_addr, peer_range, vlan_ips[0].ip, port_num[2]) logging.info("Wait some time to make sure routes announced to dynamic bgp neighbors") @@ -175,15 +205,23 @@ def test_bgp_speaker_announce_routes(common_setup_teardown, testbed, duthost, pt for ip in speaker_ips: assert bgp_facts['bgp_neighbors'][str(ip.ip)]['accepted prefixes'] == 1 + logging.info("Verify nexthops and nexthop interfaces for accepted prefixes of the dynamic neighbors") + rtinfo = duthost.get_ip_route_info(ipaddress.ip_network(unicode(prefix))) + nexthops_ip_set = { str(nexthop.ip) for nexthop in nexthop_ips } + assert len(rtinfo["nexthops"]) == 2 + for i in [0,1]: + assert str(rtinfo["nexthops"][i][0]) in nexthops_ip_set + assert rtinfo["nexthops"][i][1] == unicode(vlan_if_name) + logging.info("Generate route-port map information") - extra_vars = {'announce_prefix': '10.10.10.0/26', + extra_vars = {'announce_prefix': prefix, 'minigraph_portchannels': mg_facts['minigraph_portchannels'], 'minigraph_vlans': mg_facts['minigraph_vlans'], 'minigraph_port_indices': mg_facts['minigraph_port_indices']} ptfhost.host.options['variable_manager'].extra_vars.update(extra_vars) logging.info("extra_vars: %s" % str(ptfhost.host.options['variable_manager'].extra_vars)) - ptfhost.template(src="bgp_speaker/bgp_speaker_route.j2", dest="/root/bgp_speaker_route.txt") + ptfhost.template(src="bgp_speaker/bgp_speaker_route.j2", dest="/root/bgp_speaker_route_%s.txt" % family) logging.info("run ptf test") @@ -193,9 +231,34 @@ def test_bgp_speaker_announce_routes(common_setup_teardown, testbed, duthost, pt platform_dir="ptftests", params={"testbed_type": testbed['topo']['name'], "router_mac": interface_facts['ansible_interface_facts']['Ethernet0']['macaddress'], - "fib_info": "/root/bgp_speaker_route.txt", + "fib_info": "/root/bgp_speaker_route_%s.txt" % family, "ipv4": ipv4, "ipv6": ipv6, "testbed_mtu": mtu }, log_file="/tmp/bgp_speaker_test.FibTest.log", socket_recv_size=16384) + + logging.info("Withdraw routes") + withdraw_route(ptfip, lo_addr, prefix, nexthop_ips[1].ip, port_num[0]) + withdraw_route(ptfip, lo_addr, prefix, nexthop_ips[2].ip, port_num[1]) + withdraw_route(ptfip, lo_addr, peer_range, vlan_ips[0].ip, port_num[2]) + + logging.info("Nexthop ip%s tests are done" % family) + + +@pytest.mark.parametrize("ipv4, ipv6, mtu", [pytest.param(True, False, 1514)]) +def test_bgp_speaker_announce_routes(common_setup_teardown, testbed, duthost, ptfhost, ipv4, ipv6, mtu, collect_techsupport): + """Setup bgp speaker on T0 topology and verify routes advertised by bgp speaker is received by T0 TOR + + """ + nexthops = common_setup_teardown[3] + bgp_speaker_announce_routes_common(common_setup_teardown, testbed, duthost, ptfhost, ipv4, ipv6, mtu, "v4", "10.10.10.0/26", nexthops) + + +@pytest.mark.parametrize("ipv4, ipv6, mtu", [pytest.param(False, True, 1514)]) +def test_bgp_speaker_announce_routes_v6(common_setup_teardown, testbed, duthost, ptfhost, ipv4, ipv6, mtu, collect_techsupport): + """Setup bgp speaker on T0 topology and verify routes advertised by bgp speaker is received by T0 TOR + + """ + nexthops = common_setup_teardown[4] + bgp_speaker_announce_routes_common(common_setup_teardown, testbed, duthost, ptfhost, ipv4, ipv6, mtu, "v6", "fc00:10::/64", nexthops)