diff --git a/ansible/library/minigraph_facts.py b/ansible/library/minigraph_facts.py index 1dfee77a7cf..9dc1eebe849 100644 --- a/ansible/library/minigraph_facts.py +++ b/ansible/library/minigraph_facts.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python import calendar import os import sys @@ -13,6 +12,7 @@ from lxml import etree as ET from lxml.etree import QName +from fractions import gcd DOCUMENTATION = ''' --- @@ -45,6 +45,7 @@ ANSIBLE_LOCAL_MINIGRAPH_PATH = '{}.xml' ANSIBLE_USER_MINIGRAPH_MAX_AGE = 86400 # 24-hours (in seconds) + class minigraph_encoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, @@ -53,7 +54,7 @@ def default(self, obj): return json.JSONEncoder.default(self, obj) -def parse_png(png, hname): +def parse_png(png, hname, dpg_ecmp_content=None): neighbors = {} devices = {} neighbors_namespace = defaultdict(str) @@ -61,6 +62,13 @@ def parse_png(png, hname): console_port = '' mgmt_dev = '' mgmt_port = '' + png_ecmp_content = {} + port_device_map = {} + FG_NHG_MEMBER = {} + FG_NHG_PREFIX = {} + FG_NHG = {} + NEIGH = {} + try: from sonic_py_common import multi_asic namespace_list = multi_asic.get_namespace_list() @@ -73,6 +81,10 @@ def parse_png(png, hname): linktype = link.find(str(QName(ns, "ElementType"))).text if linktype != "DeviceInterfaceLink" and linktype != "UnderlayInterfaceLink": continue + if linktype == "DeviceInterfaceLink": + endport = link.find(str(QName(ns, "EndPort"))).text + startdevice = link.find(str(QName(ns, "StartDevice"))).text + port_device_map[endport] = startdevice enddevice = link.find(str(QName(ns, "EndDevice"))).text endport = link.find(str(QName(ns, "EndPort"))).text @@ -85,14 +97,14 @@ def parse_png(png, hname): if startdevice.lower() in namespace_list: neighbors_namespace[endport] = startdevice.lower() else: - neighbors[endport] = {'name': startdevice, 'port': startport, 'namespace':''} + neighbors[endport] = {'name': startdevice, 'port': startport, 'namespace': ''} elif startdevice == hname: if port_alias_to_name_map.has_key(startport): startport = port_alias_to_name_map[startport] if enddevice.lower() in namespace_list: neighbors_namespace[startport] = enddevice.lower() else: - neighbors[startport] = {'name': enddevice, 'port': endport, 'namespace':''} + neighbors[startport] = {'name': enddevice, 'port': endport, 'namespace': ''} if child.tag == str(QName(ns, "Devices")): for device in child.findall(str(QName(ns, "Device"))): @@ -137,9 +149,21 @@ def parse_png(png, hname): mgmt_dev = node.text for k, v in neighbors.iteritems(): - v['namespace'] = neighbors_namespace[k] + v['namespace'] = neighbors_namespace[k] + + if (len(dpg_ecmp_content)): + for version, content in dpg_ecmp_content.items(): # version is ipv4 or ipv6 + fine_grained_content = formulate_fine_grained_ecmp(version, content, port_device_map, + port_alias_to_name_map) # port_alias_map + FG_NHG_MEMBER.update(fine_grained_content['FG_NHG_MEMBER']) + FG_NHG_PREFIX.update(fine_grained_content['FG_NHG_PREFIX']) + FG_NHG.update(fine_grained_content['FG_NHG']) + NEIGH.update(fine_grained_content['NEIGH']) + + png_ecmp_content = {"FG_NHG_PREFIX": FG_NHG_PREFIX, "FG_NHG_MEMBER": FG_NHG_MEMBER, "FG_NHG": FG_NHG, + "NEIGH": NEIGH} - return (neighbors, devices, console_dev, console_port, mgmt_dev, mgmt_port) + return (neighbors, devices, console_dev, console_port, mgmt_dev, mgmt_port, png_ecmp_content) def parse_dpg(dpg, hname): @@ -148,6 +172,7 @@ def parse_dpg(dpg, hname): if hostname.text != hname: continue + ip_intfs_map = {} ipintfs = child.find(str(QName(ns, "IPInterfaces"))) intfs = [] for ipintf in ipintfs.findall(str(QName(ns, "IPInterface"))): @@ -163,7 +188,7 @@ def parse_dpg(dpg, hname): addr_bits = ipn.max_prefixlen subnet = ipaddress.IPNetwork(str(ipn.network) + '/' + str(prefix_len)) ipmask = ipn.netmask - + ip_intfs_map[ipprefix] = intfalias intf = {'addr': ipaddr, 'subnet': subnet} if isinstance(ipn, ipaddress.IPv4Network): intf['mask'] = ipmask @@ -233,9 +258,51 @@ def parse_dpg(dpg, hname): ports[port_alias_to_name_map[member]] = {'name': port_alias_to_name_map[member], 'alias': member} pcs[pcintfname] = {'name': pcintfname, 'members': pcmbr_list} fallback_node = pcintf.find(str(QName(ns, "Fallback"))) - if fallback_node is not None: + if fallback_node is not None: pcs[pcintfname]['fallback'] = fallback_node.text ports.pop(pcintfname) + nhip_port_map = {} + port_nhipv4_map = {} + port_nhipv6_map = {} + nhgaddr = ["", ""] + nhg_int = "" + nhportlist = [] + dpg_ecmp_content = {} + ipnhs = child.find(str(QName(ns, "IPNextHops"))) + if ipnhs is not None: + for ipnh in ipnhs.findall(str(QName(ns, "IPNextHop"))): + if ipnh.find(str(QName(ns, "Type"))).text == 'FineGrainedECMPGroupMember': + ipnhfmbr = ipnh.find(str(QName(ns, "AttachTo"))).text + ipnhaddr = ipnh.find(str(QName(ns, "Address"))).text + nhportlist.append(ipnhfmbr) + nhip_port_map[ipnhaddr] = ipnhfmbr + if "." in ipnhaddr: + port_nhipv4_map[ipnhfmbr] = ipnhaddr + elif ":" in ipnhaddr: + port_nhipv6_map[ipnhfmbr] = ipnhaddr + + if port_nhipv4_map is not None and port_nhipv6_map is not None: + subnet_check_ip = port_nhipv4_map.values()[0] + for subnet_range in ip_intfs_map: + if ("." in subnet_range): + a = ipaddress.IPAddress(unicode(subnet_check_ip)) + n = ipaddress.IPNetwork(unicode(subnet_range)) + if (n.Contains(a)): + nhg_int = ip_intfs_map[subnet_range] + dwnstrms = child.find(str(QName(ns, "DownstreamSummarySet"))) + for dwnstrm in dwnstrms.findall(str(QName(ns, "DownstreamSummary"))): + dwnstrmentry = str(ET.tostring(dwnstrm)) + if ("FineGrainedECMPGroupDestination" in dwnstrmentry): + subnet_ip = dwnstrm.find(str(QName(ns1, "Subnet"))).text + truncsubnet_ip = subnet_ip.split("/")[0] + if "." in (truncsubnet_ip): + nhgaddr[0] = subnet_ip + elif ":" in (truncsubnet_ip): + nhgaddr[1] = subnet_ip + ipv4_content = {"port_nhip_map": port_nhipv4_map, "nhgaddr": nhgaddr[0], "nhg_int": nhg_int} + ipv6_content = {"port_nhip_map": port_nhipv6_map, "nhgaddr": nhgaddr[1], "nhg_int": nhg_int} + dpg_ecmp_content['ipv4'] = ipv4_content + dpg_ecmp_content['ipv6'] = ipv6_content vlanintfs = child.find(str(QName(ns, "VlanInterfaces"))) vlan_intfs = [] @@ -276,9 +343,10 @@ def parse_dpg(dpg, hname): if acl_intfs: acls[aclname] = acl_intfs - return intfs, lo_intfs, mgmt_intf, vlans, pcs, acls, dhcp_servers + return intfs, lo_intfs, mgmt_intf, vlans, pcs, acls, dhcp_servers, dpg_ecmp_content return None, None, None, None, None, None + def parse_cpg(cpg, hname): bgp_sessions = [] myasn = None @@ -418,6 +486,7 @@ def reconcile_mini_graph_locations(filename, hostname): root = ET.parse(mini_graph_path).getroot() return mini_graph_path, root + def port_alias_to_name_map_50G(all_ports, s100G_ports): # 50G ports s50G_ports = list(set(all_ports) - set(s100G_ports)) @@ -431,9 +500,11 @@ def port_alias_to_name_map_50G(all_ports, s100G_ports): return port_alias_to_name_map + def parse_xml(filename, hostname): mini_graph_path, root = reconcile_mini_graph_locations(filename, hostname) - + dpg_ecmp_content = {} + png_ecmp_content = {} u_neighbors = None u_devices = None hwsku = None @@ -470,11 +541,13 @@ def parse_xml(filename, hostname): for child in root: if child.tag == str(QName(ns, "DpgDec")): - (intfs, lo_intfs, mgmt_intf, vlans, pcs, acls, dhcp_servers) = parse_dpg(child, hostname) + (intfs, lo_intfs, mgmt_intf, vlans, pcs, acls, dhcp_servers, dpg_ecmp_content) = parse_dpg(child, hostname) elif child.tag == str(QName(ns, "CpgDec")): (bgp_sessions, bgp_asn, bgp_peers_with_range) = parse_cpg(child, hostname) elif child.tag == str(QName(ns, "PngDec")): - (neighbors, devices, console_dev, console_port, mgmt_dev, mgmt_port) = parse_png(child, hostname) + (neighbors, devices, console_dev, console_port, mgmt_dev, mgmt_port, png_ecmp_content) = parse_png(child, + hostname, + dpg_ecmp_content) elif child.tag == str(QName(ns, "UngDec")): (u_neighbors, u_devices, _, _, _, _) = parse_png(child, hostname) elif child.tag == str(QName(ns, "MetadataDeclaration")): @@ -551,11 +624,22 @@ def parse_xml(filename, hostname): results['ntp_servers'] = ntp_servers results['forced_mgmt_routes'] = mgmt_routes results['deployment_id'] = deployment_id + if len(png_ecmp_content): + if len(png_ecmp_content): + results['FG_NHG_MEMBER'] = png_ecmp_content['FG_NHG_MEMBER'] + results['FG_NHG_PREFIX'] = png_ecmp_content['FG_NHG_PREFIX'] + results['FG_NHG'] = png_ecmp_content['FG_NHG'] + results['NEIGH'] = png_ecmp_content['NEIGH'] + if len(dpg_ecmp_content): + results['PORT_NHIPV4'] = dpg_ecmp_content['ipv4']['port_nhip_map'] + results['PORT_NHIPV6'] = dpg_ecmp_content['ipv6']['port_nhip_map'] return results + ports = {} port_alias_to_name_map = {} + def main(): module = AnsibleModule( argument_spec=dict( @@ -594,12 +678,76 @@ def main(): module.fail_json(msg=e.message) +def calculate_lcm_for_ecmp(nhdevices_bank_map, nhip_bank_map): + banks_enumerated = {} + lcm_array = [] + for value in nhdevices_bank_map.values(): + for key in nhip_bank_map.keys(): + if nhip_bank_map[key] == value: + if value not in banks_enumerated: + banks_enumerated[value] = 1 + else: + banks_enumerated[value] = banks_enumerated[value] + 1 + for bank_enumeration in banks_enumerated.values(): + lcm_list = range(1, bank_enumeration + 1) + lcm_comp = lcm_list[0] + for i in lcm_list[1:]: + lcm_comp = lcm_comp * i / gcd(lcm_comp, i) + lcm_array.append(lcm_comp) + + LCM = sum(lcm_array) + return LCM + + +def formulate_fine_grained_ecmp(version, dpg_ecmp_content, port_device_map, port_alias_to_name_map): + family = "" + tag = "" + neigh_key = [] + if version == "ipv4": + family = "IPV4" + tag = "fgnhg_v4" + elif version == "ipv6": + family = "IPV6" + tag = "fgnhg_v6" + + port_nhip_map = dpg_ecmp_content['port_nhip_map'] + nhgaddr = dpg_ecmp_content['nhgaddr'] + nhg_int = dpg_ecmp_content['nhg_int'] + + nhip_device_map = {port_nhip_map[x]: port_device_map[x] for x in port_device_map + if x in port_nhip_map} + nhip_devices = sorted(list(set(nhip_device_map.values()))) + nhdevices_ip_bank_map = {device: bank for bank, device in enumerate(nhip_devices)} + nhip_bank_map = {ip: nhdevices_ip_bank_map[device] for ip, device in nhip_device_map.items()} + LCM = calculate_lcm_for_ecmp(nhdevices_ip_bank_map, nhip_bank_map) + + FG_NHG_MEMBER = {ip: {"FG_NHG": tag, "bank": bank} for ip, bank in nhip_bank_map.items()} + nhip_port_map = dict(zip(port_nhip_map.values(), port_nhip_map.keys())) + + for nhip, memberinfo in FG_NHG_MEMBER.items(): + if nhip in nhip_port_map: + memberinfo["link"] = port_alias_to_name_map[nhip_port_map[nhip]] + FG_NHG_MEMBER[nhip] = memberinfo + + FG_NHG_PREFIX = {nhgaddr: {"FG_NHG": tag}} + FG_NHG = {tag: {"bucket_size": LCM}} + for ip in nhip_bank_map: + neigh_key.append(str(nhg_int + "|" + ip)) + NEIGH = {neigh_key: {"family": family} for neigh_key in neigh_key} + + fine_grained_content = {"FG_NHG_MEMBER": FG_NHG_MEMBER, "FG_NHG": FG_NHG, "FG_NHG_PREFIX": FG_NHG_PREFIX, + "NEIGH": NEIGH} + return fine_grained_content + + def print_parse_xml(hostname): filename = hostname + '.xml' results = parse_xml(filename, hostname) print(json.dumps(results, indent=3, cls=minigraph_encoder)) + from ansible.module_utils.basic import * if __name__ == "__main__": main() + diff --git a/ansible/module_utils/port_utils.py b/ansible/module_utils/port_utils.py index 3a7ad7192ac..dee155fc5c4 100644 --- a/ansible/module_utils/port_utils.py +++ b/ansible/module_utils/port_utils.py @@ -56,6 +56,9 @@ def get_port_alias_to_name_map(hwsku): elif hwsku == "Mellanox-SN2700" or hwsku == "ACS-MSN2700": for i in range(1, 33): port_alias_to_name_map["etp%d" % i] = "Ethernet%d" % ((i - 1) * 4) + elif hwsku == "ACS-MSN3800": + for i in range(1, 65): + port_alias_to_name_map["etp%d" % i] = "Ethernet%d" % ((i - 1) * 4) elif hwsku == "Arista-7060CX-32S-D48C8": # All possible breakout 50G port numbers: all_ports = [x for x in range(1, 33)] diff --git a/tests/ecmp/test_fgnhg.py b/tests/ecmp/test_fgnhg.py index ed4f370be83..2ee548f2c25 100644 --- a/tests/ecmp/test_fgnhg.py +++ b/tests/ecmp/test_fgnhg.py @@ -8,9 +8,9 @@ from tests.ptf_runner import ptf_runner from tests.common import config_reload -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] -from tests.common.fixtures.ptfhost_utils import remove_ip_addresses # lgtm[py/unused-import] +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] +from tests.common.fixtures.ptfhost_utils import remove_ip_addresses # lgtm[py/unused-import] # Constants NUM_NHs = 8 @@ -27,8 +27,11 @@ SUPPORTED_TOPO = ['t0'] SUPPORTED_PLATFORMS = ['mellanox'] +MINIGRAPH_PARSING = "OFF" + logger = logging.getLogger(__name__) + def configure_interfaces(cfg_facts, duthost, ptfhost, ptfadapter, vlan_ip): config_port_indices = cfg_facts['port_index_map'] port_list = [] @@ -67,7 +70,7 @@ def configure_interfaces(cfg_facts, duthost, ptfhost, ptfadapter, vlan_ip): return port_list, ip_to_port, bank_0_port, bank_1_port - + def generate_fgnhg_config(duthost, ip_to_port, bank_0_port, bank_1_port, prefix): if isinstance(ipaddress.ip_network(prefix), ipaddress.IPv4Network): fgnhg_name = 'fgnhg_v4' @@ -99,10 +102,10 @@ def generate_fgnhg_config(duthost, ip_to_port, bank_0_port, bank_1_port, prefix) logger.info("fgnhg entries programmed to DUT " + str(fgnhg_data)) duthost.copy(content=json.dumps(fgnhg_data, indent=2), dest="/tmp/fgnhg.json") duthost.shell("sonic-cfggen -j /tmp/fgnhg.json --write-to-db") - + def setup_neighbors(duthost, ptfhost, ip_to_port): - vlan_name = "Vlan"+ str(DEFAULT_VLAN_ID) + vlan_name = "Vlan" + str(DEFAULT_VLAN_ID) neigh_entries = {} neigh_entries['NEIGH'] = {} @@ -134,7 +137,7 @@ def create_fg_ptf_config(ptfhost, ip_to_port, port_list, bank_0_port, bank_1_por "dst_ip": prefix.split('/')[0], "net_ports": net_ports, "inner_hashing": USE_INNER_HASHING, - "num_flows": NUM_FLOWS + "num_flows": NUM_FLOWS } logger.info("fg_ecmp config sent to PTF: " + str(fg_ecmp)) @@ -151,7 +154,6 @@ def setup_test_config(ptfadapter, duthost, ptfhost, cfg_facts, router_mac, net_p def fg_ecmp(ptfhost, duthost, router_mac, net_ports, port_list, ip_to_port, bank_0_port, bank_1_port, prefix): - if isinstance(ipaddress.ip_network(prefix), ipaddress.IPv4Network): ipcmd = "ip route" else: @@ -175,12 +177,11 @@ def fg_ecmp(ptfhost, duthost, router_mac, net_ports, port_list, ip_to_port, bank "fg_ecmp_test.FgEcmpTest", platform_dir="ptftests", params={"test_case": 'create_flows', - "exp_flow_count": exp_flow_count, - "config_file": FG_ECMP_CFG}, + "exp_flow_count": exp_flow_count, + "config_file": FG_ECMP_CFG}, qlen=1000, log_file=log_file) - log_file = "/tmp/fg_ecmp_test.FgEcmpTest.{}.initial_hash_check.log".format(test_time) ptf_runner(ptfhost, @@ -191,7 +192,7 @@ def fg_ecmp(ptfhost, duthost, router_mac, net_ports, port_list, ip_to_port, bank "exp_flow_count": exp_flow_count, "config_file": FG_ECMP_CFG}, qlen=1000, - log_file=log_file) + log_file=log_file) exp_flow_count = {} flows_for_withdrawn_nh_bank = (NUM_FLOWS/2)/(len(bank_0_port) - 1) @@ -206,7 +207,6 @@ def fg_ecmp(ptfhost, duthost, router_mac, net_ports, port_list, ip_to_port, bank if port == withdraw_nh_port: duthost.shell("vtysh -c 'configure terminal' -c 'no {} {} {}'".format(ipcmd, prefix, nexthop)) - log_file = "/tmp/fg_ecmp_test.FgEcmpTest.{}.withdraw_nh.log".format(test_time) time.sleep(1) @@ -222,7 +222,6 @@ def fg_ecmp(ptfhost, duthost, router_mac, net_ports, port_list, ip_to_port, bank qlen=1000, log_file=log_file) - exp_flow_count = {} for port in port_list: exp_flow_count[port] = flows_per_nh @@ -231,7 +230,6 @@ def fg_ecmp(ptfhost, duthost, router_mac, net_ports, port_list, ip_to_port, bank if port == withdraw_nh_port: duthost.shell("vtysh -c 'configure terminal' -c '{} {} {}'".format(ipcmd, prefix, nexthop)) - log_file = "/tmp/fg_ecmp_test.FgEcmpTest.add_nh.{}.log".format(test_time) time.sleep(1) @@ -247,13 +245,11 @@ def fg_ecmp(ptfhost, duthost, router_mac, net_ports, port_list, ip_to_port, bank qlen=1000, log_file=log_file) - withdraw_nh_bank = bank_0_port for nexthop, port in ip_to_port.items(): if port in withdraw_nh_bank: duthost.shell("vtysh -c 'configure terminal' -c 'no {} {} {}'".format(ipcmd, prefix, nexthop)) - log_file = "/tmp/fg_ecmp_test.FgEcmpTest.{}.withdraw_bank.log".format(test_time) time.sleep(1) @@ -318,25 +314,104 @@ def common_setup_teardown(tbinfo, duthosts, rand_one_dut_hostname): try: mg_facts = duthost.get_extended_minigraph_facts(tbinfo) + #host_facts = duthost.setup()['ansible_facts'] cfg_facts = duthost.config_facts(host=duthost.hostname, source="persistent")['ansible_facts'] router_mac = duthost.facts['router_mac'] net_ports = [] for name, val in mg_facts['minigraph_portchannels'].items(): members = [mg_facts['minigraph_ptf_indices'][member] for member in val['members']] net_ports.extend(members) - yield duthost, cfg_facts, router_mac, net_ports + yield duthost, cfg_facts, router_mac, net_ports finally: cleanup(duthost) - -def test_fg_ecmp(common_setup_teardown, ptfadapter, ptfhost): +def extract_minigraph_config(tbinfo, duthost, cfg_facts): + mg_facts = duthost.get_extended_minigraph_facts(tbinfo) + prefix_ipv4 = "" + prefix_ipv6 = "" + bank_0_port_ipv4 = [] + bank_1_port_ipv4 = [] + bank_0_port_ipv6 = [] + bank_1_port_ipv6 = [] + ipv4_to_port = {} + ipv6_to_port = {} + + try: + nhg_prefixes = mg_facts['FG_NHG_PREFIX'] + except Exception as e: + logger.info("Minigraph does not contain the required ECMP entries. Terminating test...") + pytest.skip("") + + for nhg_prefix in nhg_prefixes.keys(): + if "." in nhg_prefix: + prefix_ipv4 = nhg_prefix + else: + prefix_ipv6 = nhg_prefix + + #We make the assumption below that IPV4 and IPV6 NHIPs are associated with the same set of ports + port_list =[int(cfg_facts['port_index_map'][mg_facts['minigraph_port_alias_to_name_map'][port]]) for port in mg_facts['PORT_NHIPV4'].keys()] + + nhipv4_port = dict((v, k) for k, v in mg_facts['PORT_NHIPV4'].items()) + nhipv6_port = dict((v, k) for k, v in mg_facts['PORT_NHIPV6'].items()) + + + for ip, bank_mapping in mg_facts['FG_NHG_MEMBER'].iteritems(): + if ip in nhipv4_port and bank_mapping['bank'] == 0: + bank_0_port_ipv4.append(int(cfg_facts['port_index_map'][mg_facts['minigraph_port_alias_to_name_map'][nhipv4_port[ip]]])) + if ip in nhipv4_port and bank_mapping['bank'] == 1: + bank_1_port_ipv4.append(int(cfg_facts['port_index_map'][mg_facts['minigraph_port_alias_to_name_map'][nhipv4_port[ip]]])) + if ip in nhipv6_port and bank_mapping['bank'] == 0: + bank_0_port_ipv6.append(int(cfg_facts['port_index_map'][mg_facts['minigraph_port_alias_to_name_map'][nhipv6_port[ip]]])) + if ip in nhipv6_port and bank_mapping['bank'] == 1: + bank_1_port_ipv6.append(int(cfg_facts['port_index_map'][mg_facts['minigraph_port_alias_to_name_map'][nhipv6_port[ip]]])) + + for ip, port in nhipv4_port.iteritems(): + ipv4_to_port[ip] = int(cfg_facts['port_index_map'][mg_facts['minigraph_port_alias_to_name_map'][nhipv4_port[ip]]]) + for ip, port in nhipv6_port.iteritems(): + ipv6_to_port[ip] = int(cfg_facts['port_index_map'][mg_facts['minigraph_port_alias_to_name_map'][nhipv6_port[ip]]]) + + + default_vlan_ipv4 = ipaddress.IPv4Interface(unicode(str(ipv4_to_port.keys()[0]) + "/2")) + default_vlan_ipv6 = ipaddress.IPv6Interface(unicode(str(ipv6_to_port.keys()[0]) + "/32")) + return prefix_ipv4, prefix_ipv6, bank_0_port_ipv4, bank_1_port_ipv4, bank_0_port_ipv6, bank_1_port_ipv6, ipv4_to_port, ipv6_to_port, default_vlan_ipv4, default_vlan_ipv6, port_list + +def test_fg_ecmp(tbinfo, common_setup_teardown, ptfadapter, ptfhost): duthost, cfg_facts, router_mac, net_ports = common_setup_teardown - # IPv4 test - port_list, ip_to_port, bank_0_port, bank_1_port = setup_test_config(ptfadapter, duthost, ptfhost, cfg_facts, router_mac, net_ports, DEFAULT_VLAN_IPv4, PREFIX_IPv4) - fg_ecmp(ptfhost, duthost, router_mac, net_ports, port_list, ip_to_port, bank_0_port, bank_1_port, PREFIX_IPv4) + if MINIGRAPH_PARSING == "OFF": + # IPv4 test + port_list, ip_to_port, bank_0_port, bank_1_port = setup_test_config(ptfadapter, duthost, ptfhost, cfg_facts, + router_mac, net_ports, DEFAULT_VLAN_IPv4, + PREFIX_IPv4) + fg_ecmp(ptfhost, duthost, router_mac, net_ports, port_list, ip_to_port, bank_0_port, bank_1_port, PREFIX_IPv4) + + # IPv6 test + port_list, ip_to_port, bank_0_port, bank_1_port = setup_test_config(ptfadapter, duthost, ptfhost, cfg_facts, + router_mac, net_ports, DEFAULT_VLAN_IPv6, + PREFIX_IPv6) + fg_ecmp(ptfhost, duthost, router_mac, net_ports, port_list, ip_to_port, bank_0_port, bank_1_port, PREFIX_IPv6) + + else: + logger.info("Minigraph Parsing Test Case Running...") + + prefix_ipv4_mg, prefix_ipv6_mg, bank_0_port_ipv4_mg, bank_1_port_ipv4_mg, bank_0_port_ipv6_mg, bank_1_port_ipv6_mg, ipv4_to_port_mg, ipv6_to_port_mg, default_vlan_ipv4_mg, default_vlan_ipv6_mg, port_list_mg = extract_minigraph_config(tbinfo, duthost, cfg_facts) + + # IPv4 test + duthost.command('config interface ip add Vlan' + str(DEFAULT_VLAN_ID) + ' ' + str(default_vlan_ipv4_mg)) + generate_fgnhg_config(duthost, ipv4_to_port_mg, bank_0_port_ipv4_mg, bank_1_port_ipv4_mg, prefix_ipv4_mg) + setup_neighbors(duthost, ptfhost, ipv4_to_port_mg) + create_fg_ptf_config(ptfhost, ipv4_to_port_mg, port_list_mg, bank_0_port_ipv4_mg, bank_1_port_ipv4_mg, router_mac, + net_ports, prefix_ipv4_mg) + fg_ecmp(ptfhost, duthost, router_mac, net_ports, port_list_mg, ipv4_to_port_mg, bank_0_port_ipv4_mg, bank_1_port_ipv4_mg, + prefix_ipv4_mg) + + # IPv6 test + duthost.command('config interface ip add Vlan' + str(DEFAULT_VLAN_ID) + ' ' + str(default_vlan_ipv6_mg)) + generate_fgnhg_config(duthost, ipv6_to_port_mg, bank_0_port_ipv6_mg, bank_1_port_ipv6_mg, prefix_ipv6_mg) + setup_neighbors(duthost, ptfhost, ipv6_to_port_mg) + create_fg_ptf_config(ptfhost, ipv6_to_port_mg, port_list_mg, bank_0_port_ipv6_mg, bank_1_port_ipv6_mg, router_mac, + net_ports, prefix_ipv6_mg) + fg_ecmp(ptfhost, duthost, router_mac, net_ports, port_list_mg, ipv6_to_port_mg, bank_0_port_ipv6_mg, bank_1_port_ipv6_mg, + prefix_ipv6_mg) - # IPv6 test - port_list, ip_to_port, bank_0_port, bank_1_port = setup_test_config(ptfadapter, duthost, ptfhost, cfg_facts, router_mac, net_ports, DEFAULT_VLAN_IPv6, PREFIX_IPv6) - fg_ecmp(ptfhost, duthost, router_mac, net_ports, port_list, ip_to_port, bank_0_port, bank_1_port, PREFIX_IPv6)