def recover_vf(pf_pci, params, default_vf=0): """ Recover vf setting :param pf_pci: The pci of PF :param params: the parameters dict :param default_vf: The value to be set """ pf_pci_path = utils_misc.get_pci_path(pf_pci) vf_no = int(params.get("vf_no", "4")) if default_vf != vf_no: utils_sriov.set_vf(pf_pci_path, default_vf)
def __init__(self, pf_pci, vf_no=4): self.pf_pci = pf_pci self.vf_no = vf_no self.pf_pci_path = utils_misc.get_pci_path(self.pf_pci) utils_sriov.set_vf(self.pf_pci_path, 0) self.pf_iface = utils_sriov.get_pf_info_by_pci( self.pf_pci).get('iface') if not self.pf_iface: raise exceptions.TestCancel("NO available pf found.") self.br_name = self.pf_iface + '_br' self.ovs = factory(openvswitch.OpenVSwitchSystem)()
def setup_vf(pf_pci, params): """ Enable vf setting :param pf_pci: The pci of PF :return: The original vf value """ default_vf = 0 try: vf_no = int(params.get("vf_no", "4")) except ValueError as e: raise exceptions.TestError(e) pf_pci_path = utils_misc.get_pci_path(pf_pci) cmd = "cat %s/sriov_numvfs" % (pf_pci_path) default_vf = process.run(cmd, shell=True, verbose=True).stdout_text if not utils_sriov.set_vf(pf_pci_path, vf_no): raise exceptions.TestError("Failed to set vf.") return default_vf
def run(test, params, env): """ Test virsh migrate command. """ def check_vm_network_accessed(session=None, ping_dest="www.baidu.com"): """ The operations to the VM need to be done before or after migration happens :param session: The session object to the host :param ping_dest: The destination to be ping :raise: test.fail when ping fails """ # Confirm local/remote VM can be accessed through network. logging.info("Check VM network connectivity") status, output = utils_test.ping(ping_dest, count=10, timeout=20, output_func=logging.debug, session=session) if status != 0: test.fail("Ping failed, status: %s," " output: %s" % (status, output)) def get_vm_ifaces(session=None): """ Get interfaces of vm :param session: The session object to the host :return: interfaces """ p_iface, v_iface = utils_net.get_remote_host_net_ifs(session) return p_iface def check_vm_iface_num(iface_list, exp_num=3): """ Check he number of interfaces :param iface_list: The interface list :param exp_num: The expected number :raise: test.fail when interfaces' number is not equal to exp_num """ if len(iface_list) != exp_num: test.fail("%d interfaces should be found on the vm, " "but find %s." % (exp_num, iface_list)) def create_or_del_networks(pf_name, params, remote_virsh_session=None, is_del=False): """ Create or delete network on local or remote :param params: Dictionary with the test parameters :param pf_name: The name of PF :param remote_virsh_session: The virsh session object to the remote host :param is_del: Whether the networks should be deleted :raise: test.fail when fails to define/start network """ net_hostdev_name = params.get("net_hostdev_name", "hostdev-net") net_hostdev_fwd = params.get("net_hostdev_fwd", '{"mode": "hostdev", "managed": "yes"}') net_bridge_name = params.get("net_bridge_name", "host-bridge") net_bridge_fwd = params.get("net_bridge_fwd", '{"mode": "bridge"}') bridge_name = params.get("bridge_name", "br0") net_dict = {"net_name": net_hostdev_name, "net_forward": net_hostdev_fwd, "net_forward_pf": '{"dev": "%s"}' % pf_name} bridge_dict = {"net_name": net_bridge_name, "net_forward": net_bridge_fwd, "net_bridge": '{"name": "%s"}' % bridge_name} if not is_del: for net_params in (net_dict, bridge_dict): net_dev = libvirt.create_net_xml(net_params.get("net_name"), net_params) if not remote_virsh_session: if net_dev.get_active(): net_dev.undefine() net_dev.define() net_dev.start() else: remote.scp_to_remote(server_ip, '22', server_user, server_pwd, net_dev.xml, net_dev.xml, limit="", log_filename=None, timeout=600, interface=None) remote_virsh_session.net_define(net_dev.xml, **virsh_args) remote_virsh_session.net_start(net_params.get("net_name"), **virsh_args) else: virsh_session = virsh if remote_virsh_session: virsh_session = remote_virsh_session for nname in (net_hostdev_name, net_bridge_name): if nname not in virsh_session.net_state_dict(): continue virsh_session.net_destroy(nname, debug=True, ignore_status=True) virsh_session.net_undefine(nname, debug=True, ignore_status=True) def check_vm_network_connection(net_name, expected_conn=0): """ Check network connections in network xml :param net_name: The network to be checked :param expected_conn: The expected value :raise: test.fail when fails """ output = virsh.net_dumpxml(net_name, debug=True).stdout_text if expected_conn == 0: reg_pattern = r"<network>" else: reg_pattern = r"<network connections='(\d)'>" res = re.findall(reg_pattern, output, re.I) if not res: test.fail("Unable to find expected connection in %s." % net_name) if expected_conn != 0: if expected_conn != int(res[0]): test.fail("Unable to get expected connection number." "Expected: %s, Actual %s" % (expected_conn, int(res[0]))) def get_hostdev_addr_from_xml(): """ Get VM hostdev address :return: pci driver id """ address_dict = {} for ifac in vm_xml.VMXML.new_from_dumpxml(vm_name).devices.by_device_tag("interface"): if ifac.type_name == "hostdev": address_dict = ifac.hostdev_address.attrs return libvirt.pci_info_from_address(address_dict, 16, "id") def check_vfio_pci(pci_path, status_error=False): """ Check if vf driver is vfio-pci :param pci_path: The absolute path of pci device :param status_error: Whether the driver should be vfio-pci """ cmd = "readlink %s/driver | awk -F '/' '{print $NF}'" % pci_path output = process.run(cmd, shell=True, verbose=True).stdout_text.strip() if (output == "vfio-pci") == status_error: test.fail("Get incorrect dirver %s, it should%s be vfio-pci." % (output, ' not' if status_error else '')) def update_iface_xml(vmxml): """ Update interfaces for guest :param vmxml: vm_xml.VMXML object """ vmxml.remove_all_device_by_type('interface') vmxml.sync() iface_dict = {"type": "network", "source": "{'network': 'host-bridge'}", "mac": mac_addr, "model": "virtio", "teaming": '{"type":"persistent"}', "alias": '{"name": "ua-backup0"}', "inbound": '{"average":"5"}', "outbound": '{"average":"5"}'} iface_dict2 = {"type": "network", "source": "{'network': 'hostdev-net'}", "mac": mac_addr, "model": "virtio", "teaming": '{"type":"transient", "persistent": "ua-backup0"}'} iface = interface.Interface('network') for ifc in (iface_dict, iface_dict2): iface.xml = libvirt.modify_vm_iface(vm.name, "get_xml", ifc) vmxml.add_device(iface) vmxml.sync() migration_test = migration.MigrationTest() migration_test.check_parameters(params) # Params for NFS shared storage shared_storage = params.get("migrate_shared_storage", "") if shared_storage == "": default_guest_asset = defaults.get_default_guest_os_info()['asset'] default_guest_asset = "%s.qcow2" % default_guest_asset shared_storage = os.path.join(params.get("nfs_mount_dir"), default_guest_asset) logging.debug("shared_storage:%s", shared_storage) # Params to update disk using shared storage params["disk_type"] = "file" params["disk_source_protocol"] = "netfs" params["mnt_path_name"] = params.get("nfs_mount_dir") # Local variables virsh_args = {"debug": True} virsh_options = params.get("virsh_options", "") server_ip = params.get("server_ip") server_user = params.get("server_user", "root") server_pwd = params.get("server_pwd") client_ip = params.get("client_ip") client_pwd = params.get("client_pwd") extra = params.get("virsh_migrate_extra") options = params.get("virsh_migrate_options") bridge_name = params.get("bridge_name", "br0") net_hostdev_name = params.get("net_hostdev_name", "hostdev-net") net_bridge_name = params.get("net_bridge_name", "host-bridge") driver = params.get("driver", "ixgbe") vm_tmp_file = params.get("vm_tmp_file", "/tmp/test.txt") cmd_during_mig = params.get("cmd_during_mig") net_failover_test = "yes" == params.get("net_failover_test", "no") cancel_migration = "yes" == params.get("cancel_migration", "no") try: vf_no = int(params.get("vf_no", "4")) except ValueError as e: test.error(e) migr_vm_back = "yes" == params.get("migrate_vm_back", "no") err_msg = params.get("err_msg") status_error = "yes" == params.get("status_error", "no") cmd_parms = {'server_ip': server_ip, 'server_user': server_user, 'server_pwd': server_pwd} remote_virsh_dargs = {'remote_ip': server_ip, 'remote_user': server_user, 'remote_pwd': server_pwd, 'unprivileged_user': None, 'ssh_remote_auth': True} destparams_dict = copy.deepcopy(params) remote_virsh_session = None vm_session = None vm = None mig_result = None func_name = None extra_args = {} default_src_vf = 0 default_dest_vf = 0 default_src_rp_filter = 1 default_dest_rp_filer = 1 if not libvirt_version.version_compare(6, 0, 0): test.cancel("This libvirt version doesn't support migration with " "net failover devices.") # params for migration connection params["virsh_migrate_desturi"] = libvirt_vm.complete_uri( params.get("migrate_dest_host")) params["virsh_migrate_connect_uri"] = libvirt_vm.complete_uri( params.get("migrate_source_host")) src_uri = params.get("virsh_migrate_connect_uri") dest_uri = params.get("virsh_migrate_desturi") vm_name = params.get("migrate_main_vm") vm = env.get_vm(vm_name) vm.verify_alive() # For safety reasons, we'd better back up xmlfile. new_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) orig_config_xml = new_xml.copy() try: # Create a remote runner for later use runner_on_target = remote.RemoteRunner(host=server_ip, username=server_user, password=server_pwd) server_session = remote.wait_for_login('ssh', server_ip, '22', server_user, server_pwd, r"[\#\$]\s*$") if net_failover_test: src_pf, src_pf_pci = utils_sriov.find_pf(driver) logging.debug("src_pf is %s. src_pf_pci: %s", src_pf, src_pf_pci) params['pf_name'] = src_pf dest_pf, dest_pf_pci = utils_sriov.find_pf(driver, server_session) logging.debug("dest_pf is %s. dest_pf_pci: %s", dest_pf, dest_pf_pci) destparams_dict['pf_name'] = dest_pf src_pf_pci_path = utils_misc.get_pci_path(src_pf_pci) dest_pf_pci_path = utils_misc.get_pci_path(dest_pf_pci, server_session) cmd = "cat %s/sriov_numvfs" % (src_pf_pci_path) default_src_vf = process.run(cmd, shell=True, verbose=True).stdout_text cmd = "cat %s/sriov_numvfs" % (dest_pf_pci_path) status, default_dest_vf = utils_misc.cmd_status_output(cmd, shell=True, session=server_session) if status: test.error("Unable to get default sriov_numvfs on target!" "status: %s, output: %s" % (status, default_dest_vf)) if not utils_sriov.set_vf(src_pf_pci_path, vf_no): test.error("Failed to set vf on source.") if not utils_sriov.set_vf(dest_pf_pci_path, vf_no, session=server_session): test.error("Failed to set vf on target.") # Create PF and bridge connection on source and target host cmd = 'cat /proc/sys/net/ipv4/conf/all/rp_filter' default_src_rp_filter = process.run(cmd, shell=True, verbose=True).stdout_text status, default_dest_rp_filter = utils_misc.cmd_status_output(cmd, shell=True, session=server_session) if status: test.error("Unable to get default rp_filter on target!" "status: %s, output: %s" % (status, default_dest_rp_filter)) cmd = 'echo 0 >/proc/sys/net/ipv4/conf/all/rp_filter' process.run(cmd, shell=True, verbose=True) utils_misc.cmd_status_output(cmd, shell=True, session=server_session) utils_sriov.add_or_del_connection(params, is_del=False) utils_sriov.add_or_del_connection(destparams_dict, is_del=False, session=server_session) if not remote_virsh_session: remote_virsh_session = virsh.VirshPersistent(**remote_virsh_dargs) create_or_del_networks(dest_pf, params, remote_virsh_session=remote_virsh_session) remote_virsh_session.close_session() create_or_del_networks(src_pf, params) # Change network interface xml mac_addr = utils_net.generate_mac_address_simple() update_iface_xml(new_xml) # Change the disk of the vm libvirt.set_vm_disk(vm, params) if not vm.is_alive(): vm.start() # Check local guest network connection before migration if vm.serial_console is not None: vm.cleanup_serial_console() vm.create_serial_console() vm_session = vm.wait_for_serial_login(timeout=240) if net_failover_test: utils_net.restart_guest_network(vm_session) iface_list = get_vm_ifaces(vm_session) vm_ipv4, vm_ipv6 = utils_net.get_linux_ipaddr(vm_session, iface_list[0]) check_vm_network_accessed(ping_dest=vm_ipv4) if net_failover_test: check_vm_iface_num(iface_list) check_vm_network_connection(net_hostdev_name, 1) check_vm_network_connection(net_bridge_name, 1) hostdev_pci_id = get_hostdev_addr_from_xml() vf_path = utils_misc.get_pci_path(hostdev_pci_id) check_vfio_pci(vf_path) if cmd_during_mig: s, o = utils_misc.cmd_status_output(cmd_during_mig, shell=True, session=vm_session) if s: test.fail("Failed to run %s in vm." % cmd_during_mig) if extra.count("--postcopy"): func_name = virsh.migrate_postcopy extra_args.update({'func_params': params}) if cancel_migration: func_name = migration_test.do_cancel # Execute migration process vms = [vm] migration_test.do_migration(vms, None, dest_uri, 'orderly', options, thread_timeout=900, ignore_status=True, virsh_opt=virsh_options, func=func_name, extra_opts=extra, **extra_args) mig_result = migration_test.ret migration_test.check_result(mig_result, params) if int(mig_result.exit_status) == 0: server_session = remote.wait_for_login('ssh', server_ip, '22', server_user, server_pwd, r"[\#\$]\s*$") check_vm_network_accessed(server_session, vm_ipv4) server_session.close() if net_failover_test: # Check network connection check_vm_network_connection(net_hostdev_name) check_vm_network_connection(net_bridge_name) # VF driver should not be vfio-pci check_vfio_pci(vf_path, True) cmd_parms.update({'vm_ip': vm_ipv4, 'vm_pwd': params.get("password")}) vm_after_mig = remote.VMManager(cmd_parms) vm_after_mig.setup_ssh_auth() cmd = "ip link" cmd_result = vm_after_mig.run_command(cmd) libvirt.check_result(cmd_result) p_iface = re.findall(r"\d+:\s+(\w+):\s+.*", cmd_result.stdout_text) p_iface = [x for x in p_iface if x != 'lo'] check_vm_iface_num(p_iface) # Check the output of ping command cmd = 'cat %s' % vm_tmp_file cmd_result = vm_after_mig.run_command(cmd) libvirt.check_result(cmd_result) if re.findall('Destination Host Unreachable', cmd_result.stdout_text, re.M): test.fail("The network does not work well during " "the migration peirod. ping output: %s" % cmd_result.stdout_text) # Execute migration from remote if migr_vm_back: ssh_connection = utils_conn.SSHConnection(server_ip=client_ip, server_pwd=client_pwd, client_ip=server_ip, client_pwd=server_pwd) try: ssh_connection.conn_check() except utils_conn.ConnectionError: ssh_connection.conn_setup() ssh_connection.conn_check() # Pre migration setup for local machine migration_test.migrate_pre_setup(src_uri, params) cmd = "virsh migrate %s %s %s" % (vm_name, virsh_options, src_uri) logging.debug("Start migration: %s", cmd) cmd_result = remote.run_remote_cmd(cmd, params, runner_on_target) logging.info(cmd_result) if cmd_result.exit_status: test.fail("Failed to run '%s' on remote: %s" % (cmd, cmd_result)) logging.debug("migration back done") check_vm_network_accessed(ping_dest=vm_ipv4) if net_failover_test: if vm_session: vm_session.close() vm_session = vm.wait_for_login() iface_list = get_vm_ifaces(vm_session) check_vm_iface_num(iface_list) else: check_vm_network_accessed(ping_dest=vm_ipv4) if net_failover_test: iface_list = get_vm_ifaces(vm_session) check_vm_iface_num(iface_list) finally: logging.debug("Recover test environment") # Clean VM on destination migration_test.cleanup_dest_vm(vm, vm.connect_uri, dest_uri) if vm.is_alive(): vm.destroy(gracefully=False) logging.info("Recovery VM XML configration") orig_config_xml.sync() logging.debug("The current VM XML:\n%s", orig_config_xml.xmltreefile) server_session = remote.wait_for_login('ssh', server_ip, '22', server_user, server_pwd, r"[\#\$]\s*$") if 'src_pf' in locals(): cmd = 'echo %s >/proc/sys/net/ipv4/conf/all/rp_filter' % default_src_rp_filter process.run(cmd, shell=True, verbose=True) utils_sriov.add_or_del_connection(params, is_del=True) create_or_del_networks(src_pf, params, is_del=True) if 'dest_pf' in locals(): cmd = 'echo %s >/proc/sys/net/ipv4/conf/all/rp_filter' % default_dest_rp_filter utils_misc.cmd_status_output(cmd, shell=True, session=server_session) utils_sriov.add_or_del_connection(destparams_dict, session=server_session, is_del=True) remote_virsh_session = virsh.VirshPersistent(**remote_virsh_dargs) create_or_del_networks(dest_pf, params, remote_virsh_session, is_del=True) remote_virsh_session.close_session() if 'dest_pf_pci_path' in locals() and default_dest_vf != vf_no: utils_sriov.set_vf(dest_pf_pci_path, default_dest_vf, server_session) if 'src_pf_pci_path' in locals() and default_src_vf != vf_no: utils_sriov.set_vf(src_pf_pci_path, default_src_vf) # Clean up of pre migration setup for local machine if migr_vm_back: if 'ssh_connection' in locals(): ssh_connection.auto_recover = True migration_test.migrate_pre_setup(src_uri, params, cleanup=True) server_session.close() if remote_virsh_session: remote_virsh_session.close_session() logging.info("Remove local NFS image") source_file = params.get("source_file") if source_file: libvirt.delete_local_disk("file", path=source_file)
def run(test, params, env): """ Sriov net failover related test. """ def setup_hotplug_hostdev_iface_with_teaming(): logging.info("Create hostdev network.") net_hostdev_fwd = params.get("net_hostdev_fwd", '{"mode": "hostdev", "managed": "yes"}') net_hostdev_dict = { "net_name": net_hostdev_name, "net_forward": net_hostdev_fwd, "net_forward_pf": '{"dev": "%s"}' % pf_name } libvirt_network.create_or_del_network(net_hostdev_dict) logging.info("Clear up VM interface.") libvirt_vmxml.remove_vm_devices_by_type(vm, 'interface') iface = interface.Interface("network") iface.xml = create_bridge_iface_xml(vm, mac_addr, params) virsh.attach_device(vm_name, iface.xml, flagstr='--persistent', debug=True, ignore_status=False) vm.start() vm.wait_for_serial_login(timeout=180).close() def teardown_hotplug_hostdev_iface_with_teaming(): logging.info("Delete hostdev network.") net_hostdev_dict = {"net_name": net_hostdev_name} libvirt_network.create_or_del_network(net_hostdev_dict, is_del=True) def test_hotplug_hostdev_iface_with_teaming(): logging.info("Attach a hostdev interface.") hostdev_iface_xml = create_hostdev_iface_xml(vm, mac_addr, params) virsh.attach_device(vm_name, hostdev_iface_xml, debug=True, ignore_status=False) check_ifaces(vm_name, expected_ifaces={"bridge", "hostdev"}) vm_session = vm.wait_for_serial_login(timeout=240) ping_ip = get_ping_dest(vm_session, mac_addr) check_vm_network_accessed(vm_session, ping_dest=ping_ip, tcpdump_iface=bridge_name, tcpdump_status_error=True) logging.info("Detach the hostdev interface.") hostdev_iface = interface.Interface("network") for ifc in vm_xml.VMXML.new_from_dumpxml( vm_name).devices.by_device_tag("interface"): if ifc.type_name == "hostdev": ifc.del_address() hostdev_iface = ifc virsh.detach_device(vm_name, hostdev_iface.xml, wait_remove_event=True, debug=True, ignore_status=False) check_ifaces(vm_name, expected_ifaces={"hostdev"}, status_error=True) check_vm_network_accessed(vm_session, 2, ping_dest=ping_ip, tcpdump_iface=bridge_name, tcpdump_status_error=False) libvirt_vfio.check_vfio_pci(vf_pci, status_error=True) logging.info("Re-attach the hostdev interface.") virsh.attach_device(vm_name, hostdev_iface.xml, debug=True, ignore_status=False) check_vm_network_accessed(vm_session, ping_dest=ping_ip, tcpdump_iface=bridge_name, tcpdump_status_error=True) def setup_hotplug_hostdev_device_with_teaming(): libvirt_vmxml.remove_vm_devices_by_type(vm, 'interface') vm.start() vm.wait_for_serial_login(timeout=240).close() def test_hotplug_hostdev_device_with_teaming(): default_vf_mac = utils_sriov.get_vf_mac(pf_name) utils_sriov.set_vf_mac(pf_name, mac_addr) logging.info("Attach the bridge interface.") brg_iface_xml = create_bridge_iface_xml(vm, mac_addr, params) virsh.attach_device(vm_name, brg_iface_xml, debug=True, ignore_status=False) # Wait for 10s before attaching the hostdev device time.sleep(10) logging.info("Attach the hostdev device.") hostdev_dev = libvirt.create_hostdev_xml(vf_pci, teaming=hostdev_teaming_dict) virsh.attach_device(vm_name, hostdev_dev.xml, debug=True, ignore_status=False) vm_session = vm.wait_for_serial_login(timeout=240) ping_ip = get_ping_dest(vm_session, mac_addr) check_vm_network_accessed(vm_session, ping_dest=ping_ip, tcpdump_iface=bridge_name, tcpdump_status_error=True) logging.info("Detach the hostdev device.") virsh.detach_device(vm_name, hostdev_dev.xml, wait_remove_event=True, debug=True, ignore_status=False) logging.debug("Recover vf's mac to %s.", default_vf_mac) utils_sriov.set_vf_mac(pf_name, default_vf_mac) check_hostdev = vm_xml.VMXML.new_from_dumpxml(vm_name)\ .devices.by_device_tag('hostdev') if check_hostdev: test.fail("The hostdev device exists after detaching %s." % check_hostdev) libvirt_vfio.check_vfio_pci(vf_pci, status_error=True) check_vm_network_accessed(vm_session, 2, ping_dest=ping_ip, tcpdump_iface=bridge_name, tcpdump_status_error=False) def setup_save_restore_hostdev_device_with_teaming(): logging.info("Start a VM with bridge iface and hostdev device.") libvirt_vmxml.remove_vm_devices_by_type(vm, 'interface') vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) iface = interface.Interface("network") iface.xml = create_bridge_iface_xml(vm, mac_addr, params) vmxml.add_device(iface) hostdev_dev = libvirt.create_hostdev_xml(vf_pci, teaming=hostdev_teaming_dict) vmxml.add_device(hostdev_dev) vmxml.sync() vm.start() utils_sriov.set_vf_mac(pf_name, mac_addr) vm.wait_for_serial_login(timeout=240).close() def test_save_restore_hostdev_device_with_teaming(): logging.info("Save/restore VM.") save_file = os.path.join(data_dir.get_tmp_dir(), "save_file") virsh.save(vm_name, save_file, debug=True, ignore_status=False, timeout=10) if not libvirt.check_vm_state(vm_name, "shut off"): test.fail("The guest should be down after executing 'virsh save'.") virsh.restore(save_file, debug=True, ignore_status=False) if not libvirt.check_vm_state(vm_name, "running"): test.fail( "The guest should be running after executing 'virsh restore'.") vm.cleanup_serial_console() vm.create_serial_console() vm_session = vm.wait_for_serial_login() ping_ip = get_ping_dest(vm_session, mac_addr) check_vm_network_accessed(vm_session, ping_dest=ping_ip, tcpdump_iface=bridge_name, tcpdump_status_error=True) logging.info("Detach the hostdev device.") hostdev_dev = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name).devices.\ by_device_tag("hostdev") virsh.detach_device(vm_name, hostdev_dev.xml, wait_remove_event=True, debug=True, ignore_status=False) check_hostdev = vm_xml.VMXML.new_from_dumpxml(vm_name)\ .devices.by_device_tag('hostdev') if check_hostdev: test.fail("The hostdev device exists after detaching %s." % check_hostdev) check_vm_network_accessed(vm_session, 2, ping_dest=ping_ip, tcpdump_iface=bridge_name, tcpdump_status_error=False) logging.info("Attach the hostdev device.") virsh.attach_device(vm_name, hostdev_dev.xml, debug=True, ignore_status=False) check_vm_network_accessed(vm_session, ping_dest=ping_ip, tcpdump_iface=bridge_name, tcpdump_status_error=True) def setup_save_restore_hostdev_iface_with_teaming(): logging.info("Create hostdev network.") net_hostdev_fwd = params.get("net_hostdev_fwd", '{"mode": "hostdev", "managed": "yes"}') net_hostdev_dict = { "net_name": net_hostdev_name, "net_forward": net_hostdev_fwd, "net_forward_pf": '{"dev": "%s"}' % pf_name } libvirt_network.create_or_del_network(net_hostdev_dict) libvirt_vmxml.remove_vm_devices_by_type(vm, 'interface') vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) iface = interface.Interface("network") iface.xml = create_bridge_iface_xml(vm, mac_addr, params) vmxml.add_device(iface) iface.xml = create_hostdev_iface_xml(vm, mac_addr, params) vmxml.add_device(iface) vmxml.sync() logging.debug("VMXML after updating ifaces: %s.", vm_xml.VMXML.new_from_dumpxml(vm_name)) vm.start() vm_session = vm.wait_for_serial_login(timeout=240) ping_ip = get_ping_dest(vm_session, mac_addr) check_vm_network_accessed(vm_session, ping_dest=ping_ip, tcpdump_iface=bridge_name, tcpdump_status_error=True) def teardown_save_restore_hostdev_iface_with_teaming(): teardown_hotplug_hostdev_iface_with_teaming() def test_save_restore_hostdev_iface_with_teaming(): logging.info("Save/restore VM.") save_file = os.path.join(data_dir.get_tmp_dir(), "save_file") virsh.save(vm_name, save_file, debug=True, ignore_status=False, timeout=10) if not libvirt.check_vm_state(vm_name, "shut off"): test.fail("The guest should be down after executing 'virsh save'.") virsh.restore(save_file, debug=True, ignore_status=False) if not libvirt.check_vm_state(vm_name, "running"): test.fail( "The guest should be running after executing 'virsh restore'.") vm.cleanup_serial_console() vm.create_serial_console() vm_session = vm.wait_for_serial_login(timeout=240) ping_ip = get_ping_dest(vm_session, mac_addr, False) logging.debug(ping_ip) check_vm_network_accessed(vm_session, ping_dest=ping_ip, tcpdump_iface=bridge_name, tcpdump_status_error=True) def check_vm_iface_num(session, exp_num=3): """ Check he number of interfaces :param session: The session to the guest :param exp_num: The expected number :return: True when interfaces' number is equal to exp_num """ p_iface = utils_net.get_remote_host_net_ifs(session)[0] logging.debug("Ifaces in VM: %s", p_iface) return len(p_iface) == exp_num def check_vm_network_accessed(vm_session, expected_iface_no=3, ping_dest="8.8.8.8", timeout=30, tcpdump_iface=None, tcpdump_status_error=False): """ Test VM's network by checking ifaces' number and the accessibility :param vm_session: The session object to the guest :param expected_iface_no: The expected number of ifaces :param ping_dest: The destination to be ping :param timeout: The timeout of the checking :param tcpdump_iface: The interface to check :param tcpdump_status_error: Whether the tcpdump's output should include the string "ICMP echo request" :raise: test.fail when ifaces' number is incorrect or ping fails. """ if not utils_misc.wait_for( lambda: check_vm_iface_num(vm_session, expected_iface_no), first=3, timeout=timeout): test.fail("%d interfaces should be found on the vm." % expected_iface_no) if tcpdump_iface: cmd = "tcpdump -i %s icmp" % tcpdump_iface tcpdump_session = aexpect.ShellSession('bash') tcpdump_session.sendline(cmd) if not utils_misc.wait_for( lambda: not utils_test.ping(ping_dest, count=3, timeout=5, output_func=logging.debug, session=vm_session)[0], first=5, timeout=timeout): test.fail("Failed to ping %s." % ping_dest) if tcpdump_iface: output = tcpdump_session.get_stripped_output() logging.debug("tcpdump's output: %s.", output) pat_str = "ICMP echo request" if re.search(pat_str, output): if tcpdump_status_error: test.fail( "Get incorrect tcpdump output: {}, it should not " "include '{}'.".format(output, pat_str)) else: if not tcpdump_status_error: test.fail("Get incorrect tcpdump output: {}, it should " "include '{}'.".format(output, pat_str)) def get_ping_dest(vm_session, mac_addr, restart_network=True): """ Get an ip address to ping :param vm_session: The session object to the guest :param mac_addr: mac address of given interface :param restart_network: Whether to restart guest's network :return: ip address """ if restart_network: utils_misc.cmd_status_output("dhclient -r; sleep 5; dhclient", shell=True, session=vm_session) vm_iface_info = utils_net.get_linux_iface_info( mac_addr, vm_session)['addr_info'][0]['local'] return re.sub('\d+$', '1', vm_iface_info) def create_bridge_iface_xml(vm, mac_addr, params): """ Create xml of bridge interface :param vm: The vm object :param mac_address: The mac address :param params: Dictionary with the test parameters :return: The interface xml """ net_bridge_name = params.get("net_bridge_name", "host-bridge") iface_bridge_dict = { "type": "network", "source": "{'network': '%s'}" % net_bridge_name, "mac": mac_addr, "model": "virtio", "teaming": '{"type":"persistent"}', "alias": '{"name": "ua-backup0"}' } return libvirt.modify_vm_iface(vm.name, "get_xml", iface_bridge_dict) def create_hostdev_iface_xml(vm, mac_addr, params): """ Create xml of hostdev interface :param vm: The vm object :param mac_address: The mac address :param params: Dictionary with the test parameters :return: The interface xml """ net_hostdev_name = params.get("net_hostdev_name", "hostdev-net") hostdev_iface_dict = { "type": "network", "source": "{'network': '%s'}" % net_hostdev_name, "mac": mac_addr, "teaming": '{"type":"transient", "persistent": "ua-backup0"}' } return libvirt.modify_vm_iface(vm.name, "get_xml", hostdev_iface_dict, 4) def check_ifaces(vm_name, expected_ifaces={"bridge", "hostdev"}, status_error=False): """ Check VM's interfaces :param vm_name: The name of VM :param expected_ifaces: The expected interfaces :param status_error: Whether the ifaces should be same with the expected_ifaces :raise: test.fail if the interface(s) is(are) as expected """ if not expected_ifaces: return else: expected_ifaces = set(expected_ifaces) vm_ifaces = [ iface for iface in vm_xml.VMXML.new_from_dumpxml( vm_name).devices.by_device_tag("interface") ] ifaces_net = {iface.get_type_name() for iface in vm_ifaces} if expected_ifaces.issubset(ifaces_net) == status_error: test.fail( "Unable to get expected interface. The interface %s " "should%s be %s." % (ifaces_net, ' not' if status_error else '', expected_ifaces)) else: logging.debug("{}Found iface(s) as expected: {}.".format( 'Not ' if status_error else '', expected_ifaces)) test_case = params.get("test_case", "") run_test = eval("test_%s" % test_case) setup_test = eval("setup_%s" % test_case) if "setup_%s" % test_case in \ locals() else "setup_%s" % test_case teardown_test = eval("teardown_%s" % test_case) if "teardown_%s" % \ test_case in locals() else "teardown_%s" % test_case vm_name = params.get("main_vm", "avocado-vt-vm1") vm = env.get_vm(params["main_vm"]) driver = params.get("driver", "ixgbe") bridge_name = params.get("bridge_name", "br0") net_bridge_name = params.get("net_bridge_name", "host-bridge") net_bridge_fwd = params.get("net_bridge_fwd", '{"mode": "bridge"}') net_hostdev_name = params.get("net_hostdev_name", "hostdev-net") bridge_name = params.get("bridge_name", "br0") hostdev_teaming_dict = params.get("hostdev_device_teaming_dict", '{}') default_vf = 0 try: vf_no = int(params.get("vf_no", "4")) except ValueError as e: test.error(e) libvirt_version.is_libvirt_feature_supported(params) mac_addr = utils_net.generate_mac_address_simple() pf_pci = utils_sriov.get_pf_pci() if not pf_pci: test.cancel("NO available pf found.") pf_name = utils_sriov.get_pf_info_by_pci(pf_pci).get('iface') brg_dict = {'pf_name': pf_name, 'bridge_name': bridge_name} bridge_dict = { "net_name": net_bridge_name, "net_forward": net_bridge_fwd, "net_bridge": '{"name": "%s"}' % bridge_name } pf_pci_path = utils_misc.get_pci_path(pf_pci) cmd = "cat %s/sriov_numvfs" % (pf_pci_path) default_vf = process.run(cmd, shell=True, verbose=True).stdout_text new_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) orig_config_xml = new_xml.copy() try: if not utils_sriov.set_vf(pf_pci_path, vf_no): test.error("Failed to set vf.") utils_sriov.add_or_del_connection(brg_dict, is_del=False) libvirt_network.create_or_del_network(bridge_dict) vf_pci = utils_sriov.get_vf_pci_id(pf_pci) exec_function(setup_test) run_test() finally: logging.info("Recover test enviroment.") utils_sriov.add_or_del_connection(brg_dict, is_del=True) libvirt_network.create_or_del_network(bridge_dict, is_del=True) if 'pf_pci_path' in locals() and default_vf != vf_no: utils_sriov.set_vf(pf_pci_path, default_vf) if vm.is_alive(): vm.destroy(gracefully=False) try: orig_config_xml.sync() except: # FIXME: Workaround for 'save'/'managedsave' hanging issue utils_libvirtd.Libvirtd().restart() orig_config_xml.sync() exec_function(teardown_test)