def _setup_interfaces_dualtor(mg_facts, peer_count): try: connections = [] vlan_intf = _find_vlan_intferface(mg_facts) loopback_intf = _find_loopback_interface(mg_facts) vlan_intf_addr = vlan_intf["addr"] vlan_intf_prefixlen = vlan_intf["prefixlen"] loopback_intf_addr = loopback_intf["addr"] loopback_intf_prefixlen = loopback_intf["prefixlen"] mux_configs = mux_cable_server_ip(duthost) local_interfaces = random.sample(mux_configs.keys(), peer_count) for local_interface in local_interfaces: connections.append( { "local_intf": loopback_intf["name"], "local_addr": "%s/%s" % (loopback_intf_addr, loopback_intf_prefixlen), "neighbor_intf": "eth%s" % mg_facts["minigraph_port_indices"][local_interface], "neighbor_addr": "%s/%s" % (mux_configs[local_interface]["server_ipv4"].split("/")[0], vlan_intf_prefixlen) } ) ptfhost.remove_ip_addresses() for conn in connections: ptfhost.shell("ifconfig %s %s" % (conn["neighbor_intf"], conn["neighbor_addr"])) ptfhost.shell("ip route add %s via %s" % (loopback_intf_addr, vlan_intf_addr)) yield connections finally: ptfhost.shell("ip route delete %s" % loopback_intf_addr) for conn in connections: ptfhost.shell("ifconfig %s 0.0.0.0" % conn["neighbor_intf"])
def _setup_arp_responder(rand_selected_dut, ptfhost, tbinfo, ip_type): logging.info('Setup ARP responder in the PTF container {}'\ .format(ptfhost.hostname)) duthost = rand_selected_dut mg_facts = duthost.get_extended_minigraph_facts(tbinfo) minigraph_ptf_indices = mg_facts['minigraph_ptf_indices'] mux_config = mux_cable_server_ip(duthost) if ip_type == 'ipv4': arp_responder_conf = { "eth%s" % minigraph_ptf_indices[port]: [config["server_ipv4"].split("/")[0]] for port, config in mux_config.items() } else: arp_responder_conf = { "eth%s" % minigraph_ptf_indices[port]: [config["server_ipv6"].split("/")[0]] for port, config in mux_config.items() } ptfhost.copy(content=json.dumps(arp_responder_conf, indent=4), dest="/tmp/from_t1.json") ptfhost.host.options["variable_manager"].extra_vars.update( {"arp_responder_args": ""}) ptfhost.template(src="templates/arp_responder.conf.j2", dest="/etc/supervisor/conf.d/arp_responder.conf") ptfhost.shell('supervisorctl reread && supervisorctl update') ptfhost.shell('supervisorctl restart arp_responder')
def run_arp_responder_ipv6(rand_selected_dut, ptfhost, tbinfo, apply_mock_dual_tor_tables, copy_arp_responder_py): """Run arp_responder to enable ptf to respond neighbor solicitation messages""" duthost = rand_selected_dut mg_facts = duthost.get_extended_minigraph_facts(tbinfo) minigraph_ptf_indices = mg_facts['minigraph_ptf_indices'] mux_config = mux_cable_server_ip(duthost) arp_responder_conf = { "eth%s" % minigraph_ptf_indices[port]: [config["server_ipv6"].split("/")[0]] for port, config in mux_config.items() } ptfhost.copy(content=json.dumps(arp_responder_conf, indent=4), dest="/tmp/from_t1.json") ptfhost.host.options["variable_manager"].extra_vars.update( {"arp_responder_args": ""}) ptfhost.template(src="templates/arp_responder.conf.j2", dest="/etc/supervisor/conf.d/arp_responder.conf") ptfhost.shell('supervisorctl reread && supervisorctl update') ptfhost.shell('supervisorctl restart arp_responder') yield ptfhost.shell('supervisorctl restart arp_responder')
def announce_new_neighbor(ptfadapter, rand_selected_dut, tbinfo): """Utility fixture to announce new neighbor from a mux port.""" def _announce_new_neighbor_gen(): """Generator to announce the neighbor to a different interface at each iteration.""" for dut_iface in dut_ifaces: update_iface_func = yield dut_iface if callable(update_iface_func): update_iface_func(dut_iface) ptf_iface = dut_to_ptf_intf_map[dut_iface] garp_packet = testutils.simple_arp_packet( eth_src=NEW_NEIGHBOR_HWADDR, hw_snd=NEW_NEIGHBOR_HWADDR, ip_snd=NEW_NEIGHBOR_IPV4_ADDR, ip_tgt=NEW_NEIGHBOR_IPV4_ADDR, arp_op=2) logging.info( "GARP packet to announce new neighbor %s to mux interface %s:\n%s", NEW_NEIGHBOR_IPV4_ADDR, dut_iface, dump_scapy_packet_show_output(garp_packet)) testutils.send(ptfadapter, int(ptf_iface), garp_packet, count=5) # let the generator stops here to allow the caller to execute testings yield dut_to_ptf_intf_map = rand_selected_dut.get_extended_minigraph_facts( tbinfo)['minigraph_ptf_indices'] mux_configs = mux_cable_server_ip(rand_selected_dut) dut_ifaces = mux_configs.keys() random.shuffle(dut_ifaces) return _announce_new_neighbor_gen()
def get_nexthops(duthost, tbinfo, ipv6=False, count=1): mg_facts = duthost.get_extended_minigraph_facts(tbinfo) vlan_intf = mg_facts['minigraph_vlan_interfaces'][1 if ipv6 else 0] prefix_len = vlan_intf['prefixlen'] if is_dualtor(tbinfo): server_ips = mux_cable_server_ip(duthost) vlan_intfs = natsort.natsorted(server_ips.keys()) nexthop_devs = [ mg_facts["minigraph_ptf_indices"][_] for _ in vlan_intfs ] server_ip_key = "server_ipv6" if ipv6 else "server_ipv4" nexthop_addrs = [ server_ips[_][server_ip_key].split("/")[0] for _ in vlan_intfs ] else: vlan_subnet = ipaddress.ip_network(vlan_intf['subnet']) vlan_ports = mg_facts['minigraph_vlans'][ mg_facts['minigraph_vlan_interfaces'][1 if ipv6 else 0] ['attachto']]['members'] vlan_ptf_ports = [ mg_facts['minigraph_ptf_indices'][port] for port in vlan_ports ] nexthop_devs = vlan_ptf_ports nexthop_addrs = [ str(vlan_subnet[i + 2]) for i in range(len(nexthop_devs)) ] count = min(count, len(nexthop_devs)) indices = random.sample(list(range(len(nexthop_devs))), k=count) return prefix_len, [nexthop_addrs[_] for _ in indices], [nexthop_devs[_] for _ in indices]
def get_nexthops(duthost, tbinfo, ipv6=False, count=1): mg_facts = duthost.get_extended_minigraph_facts(tbinfo) vlan_intf = mg_facts['minigraph_vlan_interfaces'][1 if ipv6 else 0] prefix_len = vlan_intf['prefixlen'] is_backend_topology = mg_facts.get(constants.IS_BACKEND_TOPOLOGY_KEY, False) if is_dualtor(tbinfo): server_ips = mux_cable_server_ip(duthost) vlan_intfs = natsort.natsorted(server_ips.keys()) nexthop_devs = [mg_facts["minigraph_ptf_indices"][_] for _ in vlan_intfs] server_ip_key = "server_ipv6" if ipv6 else "server_ipv4" nexthop_addrs = [server_ips[_][server_ip_key].split("/")[0] for _ in vlan_intfs] nexthop_interfaces = nexthop_devs else: vlan_subnet = ipaddress.ip_network(vlan_intf['subnet']) vlan = mg_facts['minigraph_vlans'][mg_facts['minigraph_vlan_interfaces'][1 if ipv6 else 0]['attachto']] vlan_ports = vlan['members'] vlan_id = vlan['vlanid'] vlan_ptf_ports = [mg_facts['minigraph_ptf_indices'][port] for port in vlan_ports] nexthop_devs = vlan_ptf_ports # backend topology use ethx.x(e.g. eth30.1000) during servers and T0 in ptf # in other topology use ethx(e.g. eth30) if is_backend_topology: nexthop_interfaces = [str(dev) + constants.VLAN_SUB_INTERFACE_SEPARATOR + str(vlan_id) for dev in nexthop_devs] else: nexthop_interfaces = nexthop_devs nexthop_addrs = [str(vlan_subnet[i + 2]) for i in range(len(nexthop_devs))] count = min(count, len(nexthop_devs)) indices = random.sample(list(range(len(nexthop_devs))), k=count) return prefix_len, [nexthop_addrs[_] for _ in indices], [nexthop_devs[_] for _ in indices], [nexthop_interfaces[_] for _ in indices]
def pfc_test_setup(duthosts, rand_one_dut_hostname, tbinfo, ptfhost): """ Generate configurations for the tests Args: duthosts(AnsibleHost) : multi dut instance rand_one_dut_hostname(string) : one of the dut instances from the multi dut Yields: setup(dict): DUT interfaces, PTF interfaces, PTF IP addresses, and PTF MAC addresses """ """ Get all the active physical interfaces enslaved to the Vlan """ """ These interfaces are actually server-faced interfaces at T0 """ duthost = duthosts[rand_one_dut_hostname] vlan_members, vlan_id = get_active_vlan_members(duthost) """ Get Vlan subnet """ vlan_subnet = get_vlan_subnet(duthost) """ Generate IP addresses for servers in the Vlan """ vlan_ip_addrs = list() if 'dualtor' in tbinfo['topo']['name']: servers = mux_cable_server_ip(duthost) for intf, value in natsorted(servers.items()): vlan_ip_addrs.append(value['server_ipv4'].split('/')[0]) else: vlan_ip_addrs = get_addrs_in_subnet(vlan_subnet, len(vlan_members)) """ Find correspoinding interfaces on PTF """ phy_intfs = get_phy_intfs(duthost) phy_intfs.sort(key=natural_keys) vlan_members.sort(key=natural_keys) vlan_members_index = [phy_intfs.index(intf) for intf in vlan_members] ptf_intfs = ['eth' + str(i) for i in vlan_members_index] duthost.command('sonic-clear fdb all') """ Disable DUT's PFC wd """ duthost.shell('sudo pfcwd stop') testbed_type = tbinfo['topo']['name'] yield { 'vlan_members': vlan_members, 'vlan_id': vlan_id, 'ptf_intfs': ptf_intfs, 'vlan_ip_addrs': vlan_ip_addrs, 'testbed_type': testbed_type } duthost.command('sonic-clear fdb all') """ Enable DUT's PFC wd """ duthost.shell('sudo pfcwd start_default')
def setup_interfaces(ptfhost, upper_tor_host, lower_tor_host, tbinfo): """Setup the interfaces used by the new BGP sessions on PTF.""" def _find_test_lo_interface(mg_facts): for loopback in mg_facts["minigraph_lo_interfaces"]: if loopback["name"] == TEST_DEVICE_INTERFACE: return loopback def _find_ipv4_vlan(mg_facts): for vlan_intf in mg_facts["minigraph_vlan_interfaces"]: if is_ipv4_address(vlan_intf["addr"]): return vlan_intf # find the DUT interface ip used in the bgp session upper_tor_mg_facts = upper_tor_host.get_extended_minigraph_facts(tbinfo) lower_tor_mg_facts = lower_tor_host.get_extended_minigraph_facts(tbinfo) upper_tor_intf = _find_test_lo_interface(upper_tor_mg_facts) lower_tor_intf = _find_test_lo_interface(lower_tor_mg_facts) assert upper_tor_intf assert lower_tor_intf upper_tor_intf_addr = "%s/%s" % (upper_tor_intf["addr"], upper_tor_intf["prefixlen"]) lower_tor_intf_addr = "%s/%s" % (lower_tor_intf["addr"], lower_tor_intf["prefixlen"]) # find the server ip used in the bgp session mux_configs = mux_cable_server_ip(upper_tor_host) test_iface = random.choice(mux_configs.keys()) test_server = mux_configs[test_iface] test_server_ip = test_server["server_ipv4"] upper_tor_server_ptf_intf_idx = upper_tor_mg_facts["minigraph_port_indices"][test_iface] lower_tor_server_ptf_intf_idx = lower_tor_mg_facts["minigraph_port_indices"][test_iface] upper_tor_server_ptf_intf = "eth%s" % upper_tor_server_ptf_intf_idx lower_tor_server_ptf_intf = "eth%s" % lower_tor_server_ptf_intf_idx assert upper_tor_server_ptf_intf == lower_tor_server_ptf_intf # find the vlan interface ip, used as next-hop for routes added on ptf upper_tor_vlan = _find_ipv4_vlan(upper_tor_mg_facts) lower_tor_vlan = _find_ipv4_vlan(lower_tor_mg_facts) assert upper_tor_vlan assert lower_tor_vlan assert upper_tor_vlan["addr"] == lower_tor_vlan["addr"] vlan_intf_addr = upper_tor_vlan["addr"] vlan_intf_prefixlen = upper_tor_vlan["prefixlen"] # construct the server ip with the vlan prefix length upper_tor_server_ip = "%s/%s" % (test_server_ip.split("/")[0], vlan_intf_prefixlen) lower_tor_server_ip = "%s/%s" % (test_server_ip.split("/")[0], vlan_intf_prefixlen) # find ToRs' ASNs upper_tor_asn = upper_tor_mg_facts["minigraph_bgp_asn"] lower_tor_asn = lower_tor_mg_facts["minigraph_bgp_asn"] assert upper_tor_asn == lower_tor_asn upper_tor_slb_asn = upper_tor_host.shell("sonic-cfggen -m -d -y /etc/sonic/constants.yml -v \"constants.deployment_id_asn_map[DEVICE_METADATA['localhost']['deployment_id']]\"")["stdout"] lower_tor_slb_asn = lower_tor_host.shell("sonic-cfggen -m -d -y /etc/sonic/constants.yml -v \"constants.deployment_id_asn_map[DEVICE_METADATA['localhost']['deployment_id']]\"")["stdout"] connections = { "upper_tor": { "localhost": upper_tor_host, "local_intf": TEST_DEVICE_INTERFACE, "local_addr": upper_tor_intf_addr, "local_asn": upper_tor_asn, "test_intf": test_iface, "neighbor_intf": upper_tor_server_ptf_intf, "neighbor_addr": upper_tor_server_ip, "neighbor_asn": upper_tor_slb_asn, "exabgp_port": EXABGP_PORT_UPPER_TOR, }, "lower_tor": { "localhost": lower_tor_host, "local_intf": TEST_DEVICE_INTERFACE, "local_addr": lower_tor_intf_addr, "local_asn": lower_tor_asn, "test_intf": test_iface, "neighbor_intf": lower_tor_server_ptf_intf, "neighbor_addr": lower_tor_server_ip, "neighbor_asn": lower_tor_slb_asn, "exabgp_port": EXABGP_PORT_LOWER_TOR, } } try: ptfhost.shell("ifconfig %s %s" % (upper_tor_server_ptf_intf, upper_tor_server_ip)) for conn in connections.values(): ptfhost.shell("ip route add %s via %s" % (conn["local_addr"], vlan_intf_addr)) yield connections finally: for conn in connections.values(): ptfhost.shell("ifconfig %s 0.0.0.0" % conn["neighbor_intf"], module_ignore_errors=True) ptfhost.shell("ip route del %s" % conn["local_addr"], module_ignore_errors=True)
def unknownMacSetup(duthosts, rand_one_dut_hostname, tbinfo): """ Fixture to populate all the parameters needed for the test Args: duthosts(AnsibleHost) : multi dut instance rand_one_dut_hostname(string) : one of the dut instances from the multi dut tbinfo(TestbedInfo) : testbed info Yields: setup(dict): dict of vlan, ptf, portchannel intf mappings """ duthost = duthosts[rand_one_dut_hostname] mg_facts = duthost.get_extended_minigraph_facts(tbinfo) server_ips = [] if 'dualtor' in tbinfo['topo']['name']: servers = mux_cable_server_ip(duthost) for ips in servers.values(): server_ips.append(ips['server_ipv4'].split('/')[0]) # populate vlan info vlan = dict() vlan['addr'] = mg_facts['minigraph_vlan_interfaces'][0]['addr'] vlan['pfx'] = mg_facts['minigraph_vlan_interfaces'][0]['prefixlen'] vlan['ips'] = duthost.get_ip_in_range( num=1, prefix="{}/{}".format(vlan['addr'], vlan['pfx']), exclude_ips=[vlan['addr']] + server_ips)['ansible_facts']['generated_ips'] vlan['hostip'] = vlan['ips'][0].split('/')[0] vlan['ports'] = mg_facts["minigraph_vlans"].values()[0]["members"] # populate dst intf and ptf id ptf_portmap = mg_facts['minigraph_ptf_indices'] dst_port = random.choice(vlan['ports']) ptf_dst_port = ptf_portmap[dst_port] ptf_vlan_ports = [ptf_portmap[ifname] for ifname in vlan['ports']] # populate portchannel intf, peer address and ptf ids pc = dict() pc_intfs = list() ptf_pc_ports = dict() for key in mg_facts['minigraph_portchannels']: value = mg_facts['minigraph_portchannels'][key] for item in value['members']: pc_intfs.append(item) ptf_pc_ports[item] = (ptf_portmap[item], item, None) pc.setdefault(key, []).append(item) for element in mg_facts['minigraph_portchannel_interfaces']: if key in element['attachto']: for member in pc[key]: tmp_list = list(ptf_pc_ports[member]) tmp_list[2] = element['peer_addr'] ptf_pc_ports[member] = tuple(tmp_list) break setup = { 'vlan': vlan, 'dst_port': dst_port, 'ptf_dst_port': ptf_dst_port, 'ptf_vlan_ports': ptf_vlan_ports, 'pc_intfs': pc_intfs, 'ptf_pc_ports': ptf_pc_ports } yield setup
def test_tunnel_memory_leak( toggle_all_simulator_ports_to_upper_tor, upper_tor_host, lower_tor_host, ptfhost, ptfadapter, conn_graph_facts, tbinfo, vmhost ): """ Test if there is memory leak for service tunnel_packet_handler. Send ip packets from standby TOR T1 to Server, standby TOR will forward the packets to active TOR with tunnel, active TOR will decapsulate the IPinIP packets, but there is no neighbor for destination as we remove neighbor before test, tunnel_packet_handler will be triggered and neighbor will be added. Server will receive the packets. Check if memory usage is increased after tunnel_packet_handler's operation. Since tunnel_packet_handler is only triggered by the first packet, loop the process for all severs to trigger it as much as possible. """ @contextlib.contextmanager def prepare_services(ptfhost): """ Temporarily start arp and icmp service. Make sure to stop garp service, otherwise, it will add neighbor entry back automatically. It has to stop garp_service for triggering tunnel_packet_handler. It has to start arp and icmp service for receiving packets at server side. """ ptfhost.shell("supervisorctl stop garp_service") ptfhost.shell("supervisorctl start arp_responder") ptfhost.shell("supervisorctl start icmp_responder") yield ptfhost.shell("supervisorctl stop arp_responder") ptfhost.shell("supervisorctl stop icmp_responder") @contextlib.contextmanager def remove_neighbor(duthost, server_ip): """ Remove ip neighbor before test for triggering tunnel_packet_handler, restore it after test """ flush_neighbor_ct = flush_neighbor(duthost, server_ip, True) with flush_neighbor_ct: command = "ip neighbor show %s" % server_ip output = [_.strip() for _ in duthost.shell(command)["stdout_lines"]] pytest_assert(not output, "server ip {} isn't flushed in neighbor table.".format(server_ip)) yield pytest_assert(is_tunnel_packet_handler_running(upper_tor_host), "tunnel_packet_handler is not running in SWSS conainter.") ptf_t1_intf = random.choice(get_t1_ptf_ports(lower_tor_host, tbinfo)) all_servers_ips = mux_cable_server_ip(upper_tor_host) with prepare_services(ptfhost): # Get the original memeory percent before test check_memory_leak(upper_tor_host) for iface, server_ips in all_servers_ips.items(): server_ipv4 = server_ips["server_ipv4"].split("/")[0] logging.info("Select DUT interface {} and server IP {} to test.".format(iface, server_ipv4)) pkt, exp_pkt = build_packet_to_server(lower_tor_host, ptfadapter, server_ipv4) rm_neighbor = remove_neighbor(upper_tor_host, server_ipv4) server_traffic_monitor = ServerTrafficMonitor( upper_tor_host, ptfhost, vmhost, tbinfo, iface, conn_graph_facts, exp_pkt, existing=True, is_mocked=True ) with rm_neighbor, server_traffic_monitor: testutils.send(ptfadapter, int(ptf_t1_intf.strip("eth")), pkt, count=PACKET_COUNT) logging.info("Sent {} packets from ptf t1 interface {} on standby TOR {}" .format(PACKET_COUNT, ptf_t1_intf, lower_tor_host.hostname)) # Check memory usage for every operation, used for debugging if test failed check_memory_leak(upper_tor_host) pytest_assert(validate_neighbor_entry_exist(upper_tor_host, server_ipv4), "The server ip {} doesn't exist in neighbor table on dut {}. \ tunnel_packet_handler isn't triggered.".format(server_ipv4, upper_tor_host.hostname)) pytest_assert(len(server_traffic_monitor.matched_packets) > PACKET_COUNT /2, "Received {} expected packets for server {}, drop more than 50%." .format(len(server_traffic_monitor.matched_packets), server_ipv4)) # sleep 10s to wait memory usage stable, check if there is memory leak time.sleep(10) check_result = check_memory_leak(upper_tor_host) pytest_assert(check_result == False, "Test failed because there is memory leak on {}" .format(upper_tor_host.hostname))
def get_neighbors(duthost, tbinfo, ipv6=False, count=1): topo_type = tbinfo['topo']['name'] mg_facts = duthost.get_extended_minigraph_facts(tbinfo) if 't0' in topo_type: vlan_intf = mg_facts['minigraph_vlan_interfaces'][1 if ipv6 else 0] prefix_len = vlan_intf['prefixlen'] vlan_addr = vlan_intf["addr"] is_backend_topology = mg_facts.get(constants.IS_BACKEND_TOPOLOGY_KEY, False) if is_dualtor(tbinfo): server_ips = mux_cable_server_ip(duthost) vlan_intfs = natsort.natsorted(server_ips.keys()) neighbor_devs = [ mg_facts["minigraph_ptf_indices"][_] for _ in vlan_intfs ] server_ip_key = "server_ipv6" if ipv6 else "server_ipv4" neighbor_addrs = [ server_ips[_][server_ip_key].split("/")[0] for _ in vlan_intfs ] neighbor_interfaces = neighbor_devs else: vlan_subnet = ipaddress.ip_network(vlan_intf['subnet']) vlan = mg_facts['minigraph_vlans'][mg_facts[ 'minigraph_vlan_interfaces'][1 if ipv6 else 0]['attachto']] vlan_ports = vlan['members'] vlan_id = vlan['vlanid'] vlan_ptf_ports = [ mg_facts['minigraph_ptf_indices'][port] for port in vlan_ports ] neighbor_devs = vlan_ptf_ports # backend topology use ethx.x(e.g. eth30.1000) during servers and T0 in ptf # in other topology use ethx(e.g. eth30) if is_backend_topology: neighbor_interfaces = [ str(dev) + constants.VLAN_SUB_INTERFACE_SEPARATOR + str(vlan_id) for dev in neighbor_devs ] else: neighbor_interfaces = neighbor_devs neighbor_addrs = [ str(vlan_subnet[i + 2]) for i in range(len(neighbor_devs)) ] count = min(count, len(neighbor_devs)) indices = random.sample(list(range(len(neighbor_devs))), k=count) return [vlan_addr for _ in indices], prefix_len, [ neighbor_addrs[_] for _ in indices ], [neighbor_devs[_] for _ in indices], [neighbor_interfaces[_] for _ in indices] elif 't1' in topo_type: t1_ipv4_pattern = '101.0.0.{}' t1_ipv6_pattern = '2000:2000::{:x}' t0_intfs = get_t0_intfs(mg_facts) ptf_ports = [ mg_facts['minigraph_ptf_indices'][port] for port in t0_intfs ] count = min(count, len(t0_intfs)) indices = random.sample(list(range(len(t0_intfs))), k=count) if ipv6: return [t1_ipv6_pattern.format(idx * 2) for idx in indices], 127, [ t1_ipv6_pattern.format(idx * 2 + 1) for idx in indices ], [t0_intfs[_] for _ in indices], [ptf_ports[_] for _ in indices] else: return [t1_ipv4_pattern.format(idx * 2) for idx in indices], 31, [ t1_ipv4_pattern.format(idx * 2 + 1) for idx in indices ], [t0_intfs[_] for _ in indices], [ptf_ports[_] for _ in indices]
def unknownMacSetup(duthosts, rand_one_dut_hostname, tbinfo): """ Fixture to populate all the parameters needed for the test Args: duthosts(AnsibleHost) : multi dut instance rand_one_dut_hostname(string) : one of the dut instances from the multi dut tbinfo(TestbedInfo) : testbed info Yields: setup(dict): dict of vlan, ptf, portchannel intf mappings """ duthost = duthosts[rand_one_dut_hostname] # The behavior on Mellanox for unknown MAC is flooding rather than DROP, # so we need to skip this test on Mellanox platform asic_type = duthost.facts["asic_type"] pytest_require(asic_type != "mellanox", "Skip on Mellanox platform") mg_facts = duthost.get_extended_minigraph_facts(tbinfo) is_backend_topology = mg_facts.get(constants.IS_BACKEND_TOPOLOGY_KEY, False) server_ips = [] if 'dualtor' in tbinfo['topo']['name']: servers = mux_cable_server_ip(duthost) for ips in servers.values(): server_ips.append(ips['server_ipv4'].split('/')[0]) # populate vlan info vlan = dict() vlan['addr'] = mg_facts['minigraph_vlan_interfaces'][0]['addr'] vlan['pfx'] = mg_facts['minigraph_vlan_interfaces'][0]['prefixlen'] vlan['ips'] = duthost.get_ip_in_range(num=1, prefix="{}/{}".format(vlan['addr'], vlan['pfx']), exclude_ips=[vlan['addr']] + server_ips)['ansible_facts']['generated_ips'] vlan['hostip'] = vlan['ips'][0].split('/')[0] vlan['ports'] = mg_facts["minigraph_vlans"].values()[0]["members"] # populate dst intf and ptf id ptf_portmap = mg_facts['minigraph_ptf_indices'] dst_port = random.choice(vlan['ports']) if is_backend_topology: ptf_dst_port = str(ptf_portmap[dst_port]) + constants.VLAN_SUB_INTERFACE_SEPARATOR + \ mg_facts["minigraph_vlans"].values()[0]["vlanid"] else: ptf_dst_port = ptf_portmap[dst_port] ptf_vlan_ports = [ptf_portmap[ifname] for ifname in vlan['ports']] # populate portchannel intf, peer address and ptf ids pc = dict() intfs = list() ptf_ports = dict() sub_intfs = set() if is_backend_topology: for vlan_sub_interface in mg_facts['minigraph_vlan_sub_interfaces']: sub_intf_name = vlan_sub_interface['attachto'] if sub_intf_name in intfs: continue vlan_id = vlan_sub_interface['vlan'] intf_name = get_intf_by_sub_intf(sub_intf_name, vlan_id) sub_intfs.add(sub_intf_name) ptf_ports[sub_intf_name] = (ptf_portmap[intf_name], sub_intf_name, vlan_sub_interface['peer_addr'], vlan_id) intfs = list(sub_intfs) else: for key in mg_facts['minigraph_portchannels']: value = mg_facts['minigraph_portchannels'][key] for item in value['members']: intfs.append(item) ptf_ports[item] = (ptf_portmap[item], item, None, None) pc.setdefault(key, []).append(item) for element in mg_facts['minigraph_portchannel_interfaces']: if key in element['attachto']: for member in pc[key]: tmp_list = list(ptf_ports[member]) tmp_list[2] = element['peer_addr'] ptf_ports[member] = tuple(tmp_list) break setup = {'vlan': vlan, 'dst_port': dst_port, 'ptf_dst_port': ptf_dst_port, 'ptf_vlan_ports': ptf_vlan_ports, 'intfs': intfs, 'ptf_ports': ptf_ports } yield setup