def get_match_cdrom(session, serial_num): """ Find the cdrom in guest which is corresponding with the CML according to the serial number. :param session: VM session. :param serial num: serial number of the cdrom. :return match_cdrom: the cdrom in guest which is corresponding with the CML according to the serial number. """ error.context("Get matching cdrom in guest", logging.info) show_serial_num = "ls -l /dev/disk/by-id" serial_num_output = session.cmd_output(show_serial_num) if serial_num_output: serial_cdrom = "" for line in serial_num_output.splitlines(): if utils_misc.find_substring(str(line), str(serial_num)): serial_cdrom = line.split(" ")[-1].split("/")[-1] break if not serial_cdrom: qtree_info = vm.monitor.info("qtree") raise error.TestFail("Could not find the device whose " "serial number %s is same in Qemu" " CML.\n Qtree info: %s" % (qtree_info, serial_num)) show_cdrom_cmd = "ls -l /dev/cdrom*" dev_cdrom_output = session.cmd_output(show_cdrom_cmd) if dev_cdrom_output: for line in dev_cdrom_output.splitlines(): if utils_misc.find_substring(str(line), str(serial_cdrom)): match_cdrom = line.split(" ")[-3] return match_cdrom raise error.TestFail("Could not find the corresponding cdrom" "in guest which is same in Qemu CML.")
def get_match_cdrom(vm, session, serial_num): """ Find the cdrom in guest which is corresponding with the CML according to the serial number. :param session: VM session. :param serial num: serial number of the cdrom. :return match_cdrom: the cdrom in guest which is corresponding with the CML according to the serial number. """ error.context("Get matching cdrom in guest", logging.info) show_serial_num = "ls -l /dev/disk/by-id" serial_num_output = session.cmd_output(show_serial_num) if serial_num_output: serial_cdrom = "" for line in serial_num_output.splitlines(): if utils_misc.find_substring(str(line), str(serial_num)): serial_cdrom = line.split(" ")[-1].split("/")[-1] break if not serial_cdrom: qtree_info = vm.monitor.info("qtree") raise error.TestFail("Could not find the device whose " "serial number %s is same in Qemu" " CML.\n Qtree info: %s" % (serial_num, qtree_info)) show_cdrom_cmd = "ls -l /dev/cdrom*" dev_cdrom_output = session.cmd_output(show_cdrom_cmd) if dev_cdrom_output: for line in dev_cdrom_output.splitlines(): if utils_misc.find_substring(str(line), str(serial_cdrom)): match_cdrom = line.split(" ")[-3] return match_cdrom raise error.TestFail("Could not find the corresponding cdrom" "in guest which is same in Qemu CML.")
def check_support_device(dev): if vm.monitor.protocol == 'qmp': devices_supported = vm.monitor.human_monitor_cmd("%s ?" % cmd_type) else: devices_supported = vm.monitor.send_args_cmd("%s ?" % cmd_type) # Check if the device is support in qemu is_support = utils_misc.find_substring(devices_supported, dev) if not is_support: test.error("%s doesn't support device: %s" % (cmd_type, dev))
def check_support_device(dev): if vm.monitor.protocol == "qmp": devices_supported = vm.monitor.human_monitor_cmd("%s ?" % cmd_type) else: devices_supported = vm.monitor.send_args_cmd("%s ?" % cmd_type) # Check if the device is support in qemu is_support = utils_misc.find_substring(devices_supported, dev) if not is_support: raise error.TestError("%s doesn't support device: %s" % (cmd_type, dev))
def run(test, params, env): """ Test hotplug of sr-iov devices. (Elements between [] are configurable test parameters) 1) Set up sr-iov test environment in host. 2) Start VM. 3) Disable the primary link(s) of guest. 4) PCI add one/multi sr-io deivce with (or without) repeat 5) Compare output of monitor command 'info pci'. 6) Compare output of guest command [reference_cmd]. 7) Verify whether pci_model is shown in [pci_find_cmd]. 8) Check whether the newly added PCI device works fine. 9) Delete the device, verify whether could remove the sr-iov device. 10) Re-enabling the primary link(s) of guest. :param test: QEMU test object. :param params: Dictionary with the test parameters. :param env: Dictionary with test environment. """ def get_active_network_device(session, nic_filter): devnames = [] cmd = "ifconfig -a" status, output = session.cmd_status_output(cmd) if status: msg = "Guest command '%s' fail with output: %s." % (cmd, output) raise error.TestError(msg) devnames = re.findall(nic_filter, output) return devnames def pci_add_iov(pci_num): pci_add_cmd = ("pci_add pci_addr=auto host host=%s,if=%s" % (pa_pci_ids[pci_num], pci_model)) if params.get("hotplug_params"): assign_param = params.get("hotplug_params").split() for param in assign_param: value = params.get(param) if value: pci_add_cmd += ",%s=%s" % (param, value) return pci_add(pci_add_cmd) def pci_add(pci_add_cmd): error.context("Adding pci device with command 'pci_add'") add_output = vm.monitor.send_args_cmd(pci_add_cmd, convert=False) pci_info.append(['', add_output]) if not "OK domain" in add_output: raise error.TestFail("Add PCI device failed. " "Monitor command is: %s, Output: %r" % (pci_add_cmd, add_output)) return vm.monitor.info("pci") def check_support_device(dev): if vm.monitor.protocol == 'qmp': devices_supported = vm.monitor.human_monitor_cmd("%s ?" % cmd_type) else: devices_supported = vm.monitor.send_args_cmd("%s ?" % cmd_type) # Check if the device is support in qemu is_support = utils_misc.find_substring(devices_supported, dev) if not is_support: raise error.TestError("%s doesn't support device: %s" % (cmd_type, dev)) def device_add_iov(pci_num): device_id = "%s" % pci_model + "-" + utils_misc.generate_random_id() pci_info.append([device_id]) driver = params.get("device_driver", "pci-assign") check_support_device(driver) pci_add_cmd = ("device_add id=%s,driver=%s,host=%s" % (pci_info[pci_num][0], driver, pa_pci_ids[pci_num])) if params.get("hotplug_params"): assign_param = params.get("hotplug_params").split() for param in assign_param: value = params.get(param) if value: pci_add_cmd += ",%s=%s" % (param, value) return device_add(pci_num, pci_add_cmd) def device_add(pci_num, pci_add_cmd): error.context("Adding pci device with command 'device_add'") if vm.monitor.protocol == 'qmp': add_output = vm.monitor.send_args_cmd(pci_add_cmd) else: add_output = vm.monitor.send_args_cmd(pci_add_cmd, convert=False) pci_info[pci_num].append(add_output) after_add = vm.monitor.info("pci") if pci_info[pci_num][0] not in after_add: logging.debug("Print info pci after add the block: %s" % after_add) raise error.TestFail("Add device failed. Monitor command is: %s" ". Output: %r" % (pci_add_cmd, add_output)) return after_add # Hot add a pci device def add_device(pci_num): reference_cmd = params["reference_cmd"] find_pci_cmd = params["find_pci_cmd"] info_pci_ref = vm.monitor.info("pci") reference = session.cmd_output(reference_cmd) active_nics = get_active_network_device(session, nic_filter) try: # get function for adding device. add_fuction = local_functions["%s_iov" % cmd_type] except Exception: raise error.TestError( "No function for adding sr-iov dev with '%s'" % cmd_type) after_add = None if add_fuction: # Do add pci device. after_add = add_fuction(pci_num) try: # Define a helper function to compare the output def _new_shown(): output = session.cmd_output(reference_cmd) return output != reference # Define a helper function to make sure new nic could get ip. def _check_ip(): post_nics = get_active_network_device(session, nic_filter) return (len(active_nics) <= len(post_nics) and active_nics != post_nics) # Define a helper function to catch PCI device string def _find_pci(): output = session.cmd_output(find_pci_cmd) if re.search(match_string, output, re.IGNORECASE): return True else: return False error.context("Start checking new added device") # Compare the output of 'info pci' if after_add == info_pci_ref: raise error.TestFail("No new PCI device shown after executing " "monitor command: 'info pci'") secs = int(params["wait_secs_for_hook_up"]) if not utils_misc.wait_for(_new_shown, test_timeout, secs, 3): raise error.TestFail("No new device shown in output of command " "executed inside the guest: %s" % reference_cmd) if not utils_misc.wait_for(_find_pci, test_timeout, 3, 3): raise error.TestFail("New add device not found in guest. " "Command was: %s" % find_pci_cmd) # Test the newly added device if not utils_misc.wait_for(_check_ip, 30, 3, 3): ifconfig = session.cmd_output("ifconfig -a") raise error.TestFail("New hotpluged device could not get ip " "after 30s in guest. guest ifconfig " "output: \n%s" % ifconfig) try: session.cmd(params["pci_test_cmd"] % (pci_num + 1)) except aexpect.ShellError, e: raise error.TestFail("Check device failed after PCI " "hotplug. Output: %r" % e.output) except Exception: pci_del(pci_num, ignore_failure=True) raise # Hot delete a pci device def pci_del(pci_num, ignore_failure=False): def _device_removed(): after_del = vm.monitor.info("pci") return after_del != before_del before_del = vm.monitor.info("pci") if cmd_type == "pci_add": slot_id = "0" + pci_info[pci_num][1].split(",")[2].split()[1] cmd = "pci_del pci_addr=%s" % slot_id vm.monitor.send_args_cmd(cmd, convert=False) elif cmd_type == "device_add": cmd = "device_del id=%s" % pci_info[pci_num][0] vm.monitor.send_args_cmd(cmd) if (not utils_misc.wait_for(_device_removed, test_timeout, 0, 1) and not ignore_failure): raise error.TestFail("Failed to hot remove PCI device: %s. " "Monitor command: %s" % (pci_model, cmd)) vm = env.get_vm(params["main_vm"]) vm.verify_alive() timeout = int(params.get("login_timeout", 360)) session = vm.wait_for_serial_login(timeout=timeout) test_timeout = int(params.get("test_timeout", 360)) # Test if it is nic or block pci_num_range = int(params.get("pci_num", 1)) rp_times = int(params.get("repeat_times", 1)) pci_model = params.get("pci_model", "pci-assign") # Need udpate match_string if you use a card other than 82576 match_string = params.get("match_string", "82576") nic_filter = params["nic_interface_filter"] devices = [] device_type = params.get("hotplug_device_type", "vf") for i in xrange(pci_num_range): device = {} device["type"] = device_type device['mac'] = utils_net.generate_mac_address_simple() if params.get("device_name"): device["name"] = params.get("device_name") devices.append(device) device_driver = params.get("device_driver", "pci-assign") if vm.pci_assignable is None: vm.pci_assignable = test_setup.PciAssignable( driver=params.get("driver"), driver_option=params.get("driver_option"), host_set_flag=params.get("host_setup_flag"), kvm_params=params.get("kvm_default"), vf_filter_re=params.get("vf_filter_re"), pf_filter_re=params.get("pf_filter_re"), device_driver=device_driver) pa_pci_ids = vm.pci_assignable.request_devs(devices) # Modprobe the module if specified in config file module = params.get("modprobe_module") if module: error.context("modprobe the module %s" % module, logging.info) session.cmd("modprobe %s" % module) # Probe qemu to verify what is the supported syntax for PCI hotplug if vm.monitor.protocol == 'qmp': cmd_o = vm.monitor.info("commands") else: cmd_o = vm.monitor.send_args_cmd("help") cmd_type = utils_misc.find_substring(str(cmd_o), "device_add", "pci_add") if not cmd_o: raise error.TestError("Unknow version of qemu") local_functions = locals() error.context("Disable the primary link(s) of guest", logging.info) for nic in vm.virtnet: vm.set_link(nic.device_id, up=False) try: for j in range(rp_times): # pci_info is a list of list. # each element 'i' has 4 members: # pci_info[i][0] == device id, only used for device_add # pci_info[i][1] == output of device add command pci_info = [] for pci_num in xrange(pci_num_range): msg = "Start hot-adding %sth pci device," % (pci_num + 1) msg += " repeat %d" % (j + 1) error.context(msg, logging.info) add_device(pci_num) sub_type = params.get("sub_type_after_plug") if sub_type: error.context("Running sub test '%s' after hotplug" % sub_type, logging.info) utils_test.run_virt_sub_test(test, params, env, sub_type) if "guest_suspend" == sub_type: # Hotpluged device have been released after guest suspend, # so do not need unpluged step. break for pci_num in xrange(pci_num_range): msg = "start hot-deleting %sth pci device," % (pci_num + 1) msg += " repeat %d" % (j + 1) error.context(msg, logging.info) pci_del(-(pci_num + 1)) finally: error.context("Re-enabling the primary link(s) of guest", logging.info) for nic in vm.virtnet: vm.set_link(nic.device_id, up=True)
def run(test, params, env): """ Test hotplug of sr-iov devices. (Elements between [] are configurable test parameters) 1) Set up sr-iov test environment in host. 2) Start VM. 3) Disable the primary link(s) of guest. 4) PCI add one/multi sr-io deivce with (or without) repeat 5) Compare output of monitor command 'info pci'. 6) Compare output of guest command [reference_cmd]. 7) Verify whether pci_model is shown in [pci_find_cmd]. 8) Check whether the newly added PCI device works fine. 9) Delete the device, verify whether could remove the sr-iov device. 10) Re-enabling the primary link(s) of guest. :param test: QEMU test object. :param params: Dictionary with the test parameters. :param env: Dictionary with test environment. """ def get_active_network_device(session, nic_filter): devnames = [] cmd = "ifconfig -a" status, output = session.cmd_status_output(cmd) if status: msg = "Guest command '%s' fail with output: %s." % (cmd, output) raise error.TestError(msg) devnames = re.findall(nic_filter, output) return devnames def pci_add_iov(pci_num): pci_add_cmd = ("pci_add pci_addr=auto host host=%s,if=%s" % (pa_pci_ids[pci_num], pci_model)) if params.get("hotplug_params"): assign_param = params.get("hotplug_params").split() for param in assign_param: value = params.get(param) if value: pci_add_cmd += ",%s=%s" % (param, value) return pci_add(pci_add_cmd) def pci_add(pci_add_cmd): error.context("Adding pci device with command 'pci_add'") add_output = vm.monitor.send_args_cmd(pci_add_cmd, convert=False) pci_info.append(['', add_output]) if "OK domain" not in add_output: raise error.TestFail("Add PCI device failed. " "Monitor command is: %s, Output: %r" % (pci_add_cmd, add_output)) return vm.monitor.info("pci") def check_support_device(dev): if vm.monitor.protocol == 'qmp': devices_supported = vm.monitor.human_monitor_cmd("%s ?" % cmd_type) else: devices_supported = vm.monitor.send_args_cmd("%s ?" % cmd_type) # Check if the device is support in qemu is_support = utils_misc.find_substring(devices_supported, dev) if not is_support: raise error.TestError("%s doesn't support device: %s" % (cmd_type, dev)) def device_add_iov(pci_num): device_id = "%s" % pci_model + "-" + utils_misc.generate_random_id() pci_info.append([device_id]) driver = params.get("device_driver", "pci-assign") check_support_device(driver) pci_add_cmd = ("device_add id=%s,driver=%s,host=%s" % (pci_info[pci_num][0], driver, pa_pci_ids[pci_num])) if params.get("hotplug_params"): assign_param = params.get("hotplug_params").split() for param in assign_param: value = params.get(param) if value: pci_add_cmd += ",%s=%s" % (param, value) return device_add(pci_num, pci_add_cmd) def device_add(pci_num, pci_add_cmd): error.context("Adding pci device with command 'device_add'") if vm.monitor.protocol == 'qmp': add_output = vm.monitor.send_args_cmd(pci_add_cmd) else: add_output = vm.monitor.send_args_cmd(pci_add_cmd, convert=False) pci_info[pci_num].append(add_output) after_add = vm.monitor.info("pci") if pci_info[pci_num][0] not in str(after_add): logging.debug("Print info pci after add the block: %s" % after_add) raise error.TestFail("Add device failed. Monitor command is: %s" ". Output: %r" % (pci_add_cmd, add_output)) return after_add # Hot add a pci device def add_device(pci_num): reference_cmd = params["reference_cmd"] find_pci_cmd = params["find_pci_cmd"] info_pci_ref = vm.monitor.info("pci") reference = session.cmd_output(reference_cmd) active_nics = get_active_network_device(session, nic_filter) try: # get function for adding device. add_fuction = local_functions["%s_iov" % cmd_type] except Exception: raise error.TestError( "No function for adding sr-iov dev with '%s'" % cmd_type) after_add = None if add_fuction: # Do add pci device. after_add = add_fuction(pci_num) try: # Define a helper function to compare the output def _new_shown(): output = session.cmd_output(reference_cmd) return output != reference # Define a helper function to make sure new nic could get ip. def _check_ip(): post_nics = get_active_network_device(session, nic_filter) return (len(active_nics) <= len(post_nics) and active_nics != post_nics) # Define a helper function to catch PCI device string def _find_pci(): output = session.cmd_output(find_pci_cmd) if re.search(match_string, output, re.IGNORECASE): return True else: return False error.context("Start checking new added device") # Compare the output of 'info pci' if after_add == info_pci_ref: raise error.TestFail("No new PCI device shown after executing " "monitor command: 'info pci'") secs = int(params["wait_secs_for_hook_up"]) if not utils_misc.wait_for(_new_shown, test_timeout, secs, 3): raise error.TestFail( "No new device shown in output of command " "executed inside the guest: %s" % reference_cmd) if not utils_misc.wait_for(_find_pci, test_timeout, 3, 3): raise error.TestFail("New add device not found in guest. " "Command was: %s" % find_pci_cmd) # Test the newly added device if not utils_misc.wait_for(_check_ip, 120, 3, 3): ifconfig = session.cmd_output("ifconfig -a") raise error.TestFail("New hotpluged device could not get ip " "after 120s in guest. guest ifconfig " "output: \n%s" % ifconfig) try: session.cmd(params["pci_test_cmd"] % (pci_num + 1)) except aexpect.ShellError, e: raise error.TestFail("Check device failed after PCI " "hotplug. Output: %r" % e.output) except Exception: pci_del(pci_num, ignore_failure=True) raise # Hot delete a pci device def pci_del(pci_num, ignore_failure=False): def _device_removed(): after_del = vm.monitor.info("pci") return after_del != before_del before_del = vm.monitor.info("pci") if cmd_type == "pci_add": slot_id = "0" + pci_info[pci_num][1].split(",")[2].split()[1] cmd = "pci_del pci_addr=%s" % slot_id vm.monitor.send_args_cmd(cmd, convert=False) elif cmd_type == "device_add": cmd = "device_del id=%s" % pci_info[pci_num][0] vm.monitor.send_args_cmd(cmd) if (not utils_misc.wait_for(_device_removed, test_timeout, 0, 1) and not ignore_failure): raise error.TestFail("Failed to hot remove PCI device: %s. " "Monitor command: %s" % (pci_model, cmd)) vm = env.get_vm(params["main_vm"]) vm.verify_alive() timeout = int(params.get("login_timeout", 360)) session = vm.wait_for_serial_login(timeout=timeout) test_timeout = int(params.get("test_timeout", 360)) # Test if it is nic or block pci_num_range = int(params.get("pci_num", 1)) rp_times = int(params.get("repeat_times", 1)) pci_model = params.get("pci_model", "pci-assign") # Need udpate match_string if you use a card other than 82576 match_string = params.get("match_string", "82576") generate_mac = params.get("generate_mac", "yes") nic_filter = params["nic_interface_filter"] devices = [] device_type = params.get("hotplug_device_type", "vf") for i in xrange(pci_num_range): device = {} device["type"] = device_type if generate_mac == "yes": device['mac'] = utils_net.generate_mac_address_simple() if params.get("device_name"): device["name"] = params.get("device_name") devices.append(device) device_driver = params.get("device_driver", "pci-assign") if vm.pci_assignable is None: vm.pci_assignable = test_setup.PciAssignable( driver=params.get("driver"), driver_option=params.get("driver_option"), host_set_flag=params.get("host_setup_flag"), kvm_params=params.get("kvm_default"), vf_filter_re=params.get("vf_filter_re"), pf_filter_re=params.get("pf_filter_re"), device_driver=device_driver) pa_pci_ids = vm.pci_assignable.request_devs(devices) # Modprobe the module if specified in config file module = params.get("modprobe_module") if module: error.context("modprobe the module %s" % module, logging.info) session.cmd("modprobe %s" % module) # Probe qemu to verify what is the supported syntax for PCI hotplug if vm.monitor.protocol == 'qmp': cmd_o = vm.monitor.info("commands") else: cmd_o = vm.monitor.send_args_cmd("help") cmd_type = utils_misc.find_substring(str(cmd_o), "device_add", "pci_add") if not cmd_o: raise error.TestError("Unknown version of qemu") local_functions = locals() if params.get("enable_set_link" "yes") == "yes": error.context("Disable the primary link(s) of guest", logging.info) for nic in vm.virtnet: vm.set_link(nic.device_id, up=False) try: for j in range(rp_times): # pci_info is a list of list. # each element 'i' has 4 members: # pci_info[i][0] == device id, only used for device_add # pci_info[i][1] == output of device add command pci_info = [] for pci_num in xrange(pci_num_range): msg = "Start hot-adding %sth pci device," % (pci_num + 1) msg += " repeat %d" % (j + 1) error.context(msg, logging.info) add_device(pci_num) sub_type = params.get("sub_type_after_plug") if sub_type: error.context("Running sub test '%s' after hotplug" % sub_type, logging.info) utils_test.run_virt_sub_test(test, params, env, sub_type) if "guest_suspend" == sub_type: # Hotpluged device have been released after guest suspend, # so do not need unpluged step. break for pci_num in xrange(pci_num_range): msg = "start hot-deleting %sth pci device," % (pci_num + 1) msg += " repeat %d" % (j + 1) error.context(msg, logging.info) pci_del(-(pci_num + 1)) finally: if params.get("enable_set_link", "yes") == "yes": error.context("Re-enabling the primary link(s) of guest", logging.info) for nic in vm.virtnet: vm.set_link(nic.device_id, up=True)
def run(test, params, env): """ Test hot unplug of PCI devices. 1) Set up test environment in host if test sr-iov. 2) Start VM. 3) Get the device id that want to unplug. 4) Delete the device, verify whether could remove the PCI device. :param test: QEMU test object. :param params: Dictionary with the test parameters. :param env: Dictionary with test environment. """ def find_pci(): output = vm.monitor.info("qtree") devices = re.findall(match_string, output) return devices # Hot delete a pci device def pci_del(device, ignore_failure=False): def _device_removed(): after_del = vm.monitor.info("pci") return after_del != before_del before_del = vm.monitor.info("pci") if cmd_type == "device_del": cmd = "device_del id=%s" % device vm.monitor.send_args_cmd(cmd) else: raise error.TestFail("device_del command is not supported") if not utils_misc.wait_for(_device_removed, test_timeout, 0, 1) and not ignore_failure: raise error.TestFail("Failed to hot remove PCI device: %s. " "Monitor command: %s" % (pci_model, cmd)) vm = env.get_vm(params["main_vm"]) vm.verify_alive() timeout = int(params.get("login_timeout", 360)) session = vm.wait_for_login(timeout=timeout) test_timeout = int(params.get("test_timeout", 360)) # Test if it is nic or block pci_num = int(params.get("unplug_pci_num", 1)) pci_model = params.get("pci_model", "pci-assign") # Need udpate match_string if you use a card other than 82576 match_string = params.get("match_string", 'dev: %s, id "(.*)"') match_string = match_string % pci_model # Modprobe the module if specified in config file module = params.get("modprobe_module") if module: error.context("modprobe the module %s" % module, logging.info) session.cmd("modprobe %s" % module) # check monitor type is_qmp_monitor = utils_misc.qemu_has_option("qmp") and params.get("monitor_type") == "qmp" # Probe qemu to verify what is the supported syntax for PCI hotplug if is_qmp_monitor: cmd_o = vm.monitor.info("commands") else: cmd_o = vm.monitor.send_args_cmd("help") if not cmd_o: raise error.TestError("Unknow version of qemu") cmd_type = utils_misc.find_substring(str(cmd_o), "device_del") devices = find_pci() context_msg = "Running sub test '%s' %s" sub_type = params.get("sub_type_before_unplug") if sub_type: error.context(context_msg % (sub_type, "before unplug"), logging.info) utils_test.run_virt_sub_test(test, params, env, sub_type) if devices: for device in devices[:pci_num]: # (lmr) I think here is the place where pci_info should go pci_info = [] error.context("Hot unplug device %s" % device, logging.info) pci_del(device) sub_type = params.get("sub_type_after_unplug") if sub_type: error.context(context_msg % (sub_type, "after hotunplug"), logging.info) utils_test.run_virt_sub_test(test, params, env, sub_type)
def run_pci_hotplug(test, params, env): """ Test hotplug of PCI devices. (Elements between [] are configurable test parameters) 1) PCI add one/multi device (NIC / block) with(or without) repeat 2) Compare output of monitor command 'info pci'. 3) Compare output of guest command [reference_cmd]. 4) Verify whether pci_model is shown in [pci_find_cmd]. 5) Check whether the newly added PCI device works fine. 6) PCI delete the device, verify whether could remove the PCI device. 7) reboot VM after guest wakeup form S3/S4 status (Optional Step). :param test: QEMU test object. :param params: Dictionary with the test parameters. :param env: Dictionary with test environment. """ # Select an image file def find_image(pci_num): image_params = params.object_params("%s" % img_list[pci_num + 1]) o = storage.get_image_filename(image_params, data_dir.get_data_dir()) return o def pci_add_nic(pci_num): pci_add_cmd = "pci_add pci_addr=auto nic model=%s" % pci_model return pci_add(pci_add_cmd) def pci_add_block(pci_num): image_filename = find_image(pci_num) pci_add_cmd = "pci_add pci_addr=auto storage file=%s,if=%s" % (image_filename, pci_model) return pci_add(pci_add_cmd) def pci_add(pci_add_cmd): error.context("Adding pci device with command 'pci_add'") add_output = vm.monitor.send_args_cmd(pci_add_cmd, convert=False) pci_info.append(["", "", add_output, pci_model]) if not "OK domain" in add_output: raise error.TestFail( "Add PCI device failed. " "Monitor command is: %s, Output: %r" % (pci_add_cmd, add_output) ) return vm.monitor.info("pci") def is_supported_device(dev): # Probe qemu to verify what is the supported syntax for PCI hotplug cmd_output = vm.monitor.human_monitor_cmd("?") if len(re.findall("\ndevice_add", cmd_output)) > 0: cmd_type = "device_add" elif len(re.findall("\npci_add", cmd_output)) > 0: cmd_type = "pci_add" else: raise error.TestError("Unknow version of qemu") # Probe qemu for a list of supported devices probe_output = vm.monitor.human_monitor_cmd("%s ?" % cmd_type) devices_supported = [j.strip('"') for j in re.findall('"[a-z|0-9|\-|\_|\,|\.]*"', probe_output, re.MULTILINE)] logging.debug("QEMU reported the following supported devices for " "PCI hotplug: %s", devices_supported) return dev in devices_supported def verify_supported_device(dev): if not is_supported_device(dev): raise error.TestError("%s doesn't support device: %s" % (cmd_type, dev)) def device_add_nic(pci_num, queues=1): device_id = pci_type + "-" + utils_misc.generate_random_id() pci_info.append([device_id, device_id]) pci_model = params.get("pci_model") if pci_model == "virtio": pci_model = "virtio-net-pci" verify_supported_device(pci_model) pci_add_cmd = "device_add id=%s,driver=%s" % (pci_info[pci_num][1], pci_model) if queues > 1 and "virtio" in pci_model: pci_add_cmd += ",mq=on" return device_add(pci_num, pci_add_cmd) def device_add_block(pci_num): device_id = pci_type + "-" + utils_misc.generate_random_id() pci_info.append([device_id, device_id]) image_format = params.get("image_format_%s" % img_list[pci_num + 1]) if not image_format: image_format = params.get("image_format", "qcow2") image_filename = find_image(pci_num) pci_model = params.get("pci_model") controller_model = None if pci_model == "virtio": pci_model = "virtio-blk-pci" if pci_model == "scsi": pci_model = "scsi-disk" if arch.ARCH == "ppc64": controller_model = "spapr-vscsi" else: controller_model = "lsi53c895a" verify_supported_device(controller_model) controller_id = "controller-" + device_id controller_add_cmd = "device_add %s,id=%s" % (controller_model, controller_id) error.context("Adding SCSI controller.") vm.monitor.send_args_cmd(controller_add_cmd) verify_supported_device(pci_model) if drive_cmd_type == "drive_add": driver_add_cmd = "%s auto file=%s,if=none,format=%s,id=%s" % ( drive_cmd_type, image_filename, image_format, pci_info[pci_num][0], ) elif drive_cmd_type == "__com.redhat_drive_add": driver_add_cmd = "%s file=%s,format=%s,id=%s" % ( drive_cmd_type, image_filename, image_format, pci_info[pci_num][0], ) # add driver. error.context("Adding driver.") vm.monitor.send_args_cmd(driver_add_cmd, convert=False) pci_add_cmd = "device_add id=%s,driver=%s,drive=%s" % (pci_info[pci_num][1], pci_model, pci_info[pci_num][0]) return device_add(pci_num, pci_add_cmd) def device_add(pci_num, pci_add_cmd): error.context("Adding pci device with command 'device_add'") if vm.monitor.protocol == "qmp": add_output = vm.monitor.send_args_cmd(pci_add_cmd) else: add_output = vm.monitor.send_args_cmd(pci_add_cmd, convert=False) pci_info[pci_num].append(add_output) pci_info[pci_num].append(pci_model) after_add = vm.monitor.info("pci") if pci_info[pci_num][1] not in after_add: logging.error("Could not find matched id in monitor:" " %s" % pci_info[pci_num][1]) raise error.TestFail("Add device failed. Monitor command is: %s" ". Output: %r" % (pci_add_cmd, add_output)) return after_add # Hot add a pci device def add_device(pci_num, queues=1): info_pci_ref = vm.monitor.info("pci") reference = session.cmd_output(reference_cmd) try: # get function for adding device. add_fuction = local_functions["%s_%s" % (cmd_type, pci_type)] except Exception: raise error.TestError("No function for adding '%s' dev with '%s'" % (pci_type, cmd_type)) after_add = None if add_fuction: # Do add pci device. after_add = add_fuction(pci_num, queues) try: # Define a helper function to compare the output def _new_shown(): o = session.cmd_output(reference_cmd) return o != reference # Define a helper function to catch PCI device string def _find_pci(): output = session.cmd_output(params.get("find_pci_cmd")) output = map(string.strip, output.splitlines()) ref = map(string.strip, reference.splitlines()) output = [_ for _ in output if _ not in ref] output = "\n".join(output) if re.search(params.get("match_string"), output, re.I): return True return False error.context("Start checking new added device") # Compare the output of 'info pci' if after_add == info_pci_ref: raise error.TestFail("No new PCI device shown after executing " "monitor command: 'info pci'") secs = int(params.get("wait_secs_for_hook_up")) if not utils_misc.wait_for(_new_shown, test_timeout, secs, 3): raise error.TestFail( "No new device shown in output of command " "executed inside the guest: %s" % reference_cmd ) if not utils_misc.wait_for(_find_pci, test_timeout, 3, 3): raise error.TestFail( "PCI %s %s device not found in guest. " "Command was: %s" % (pci_model, pci_type, params.get("find_pci_cmd")) ) # Test the newly added device try: session.cmd(params.get("pci_test_cmd") % (pci_num + 1)) except aexpect.ShellError, e: raise error.TestFail( "Check for %s device failed after PCI " "hotplug. Output: %r" % (pci_type, e.output) ) except Exception: pci_del(pci_num, ignore_failure=True) raise # Hot delete a pci device def pci_del(pci_num, ignore_failure=False): def _device_removed(): after_del = vm.monitor.info("pci") return after_del != before_del before_del = vm.monitor.info("pci") if cmd_type == "pci_add": slot_id = int(pci_info[pci_num][2].split(",")[2].split()[1]) cmd = "pci_del pci_addr=%s" % hex(slot_id) vm.monitor.send_args_cmd(cmd, convert=False) elif cmd_type == "device_add": cmd = "device_del id=%s" % pci_info[pci_num][1] vm.monitor.send_args_cmd(cmd) if not utils_misc.wait_for(_device_removed, test_timeout, 0, 1) and not ignore_failure: raise error.TestFail( "Failed to hot remove PCI device: %s. " "Monitor command: %s" % (pci_info[pci_num][3], cmd) ) vm = env.get_vm(params["main_vm"]) vm.verify_alive() timeout = int(params.get("login_timeout", 360)) session = vm.wait_for_login(timeout=timeout) test_timeout = int(params.get("hotplug_timeout", 360)) reference_cmd = params["reference_cmd"] # Test if it is nic or block pci_type = params["pci_type"] pci_model = params["pci_model"] # Modprobe the module if specified in config file module = params.get("modprobe_module") if module: session.cmd("modprobe %s" % module) # check monitor type qemu_binary = params.get("qemu_binary", "/usr/libexec/qemu-kvm") qemu_binary = utils_misc.get_path(test.bindir, qemu_binary) # Probe qemu to verify what is the supported syntax for PCI hotplug if vm.monitor.protocol == "qmp": cmd_output = vm.monitor.info("commands") else: cmd_output = vm.monitor.human_monitor_cmd("help", debug=False) cmd_type = utils_misc.find_substring(str(cmd_output), "device_add", "pci_add") if not cmd_output: raise error.TestError("Could find a suitable method for hotplugging" " device in this version of qemu") # Determine syntax of drive hotplug # __com.redhat_drive_add == qemu-kvm-0.12 on RHEL 6 # drive_add == qemu-kvm-0.13 onwards drive_cmd_type = utils_misc.find_substring(str(cmd_output), "__com.redhat_drive_add", "drive_add") if not drive_cmd_type: raise error.TestError("Could find a suitable method for hotplugging" " drive in this version of qemu") local_functions = locals() pci_num_range = int(params.get("pci_num")) queues = int(params.get("queues", 1)) rp_times = int(params.get("repeat_times")) img_list = params.get("images").split() context_msg = "Running sub test '%s' %s" for j in range(rp_times): # pci_info is a list of list. # each element 'i' has 4 members: # pci_info[i][0] == device drive id, only used for device_add # pci_info[i][1] == device id, only used for device_add # pci_info[i][2] == output of device add command # pci_info[i][3] == device module name. pci_info = [] for pci_num in xrange(pci_num_range): sub_type = params.get("sub_type_before_plug") if sub_type: error.context(context_msg % (sub_type, "before hotplug"), logging.info) utils_test.run_virt_sub_test(test, params, env, sub_type) error.context("Start hot-adding pci device, repeat %d" % j) add_device(pci_num, queues) sub_type = params.get("sub_type_after_plug") if sub_type: error.context(context_msg % (sub_type, "after hotplug"), logging.info) utils_test.run_virt_sub_test(test, params, env, sub_type) for pci_num in xrange(pci_num_range): sub_type = params.get("sub_type_before_unplug") if sub_type: error.context(context_msg % (sub_type, "before hotunplug"), logging.info) utils_test.run_virt_sub_test(test, params, env, sub_type) error.context("start hot-deleting pci device, repeat %d" % j) pci_del(-(pci_num + 1)) sub_type = params.get("sub_type_after_unplug") if sub_type: error.context(context_msg % (sub_type, "after hotunplug"), logging.info) utils_test.run_virt_sub_test(test, params, env, sub_type) if params.get("reboot_vm", "no") == "yes": vm.reboot()
def run(test, params, env): """ Test hotplug of PCI devices and check the status in guest. 1 Boot up a guest 2 Hotplug virtio disk to the guest. Record the id and partition name of the disk in a list. 3 Random choice a disk in the list. Unplug the disk and check the partition status. 4 Hotpulg the disk back to guest with the same monitor cmdline and same id which is record in step 2. 5 Check the partition status in guest. And confirm the disk with dd cmd 6 Repeat step 3 to 5 for N times :param test: KVM test object. :param params: Dictionary with the test parameters. :param env: Dictionary with test environment. """ def prepare_image_params(params): pci_num = int(params['pci_num']) for i in xrange(pci_num): image_name = '%s_%s' % ('stg', i) params['images'] = ' '.join([params['images'], image_name]) image_image_name = '%s_%s' % ('image_name', image_name) params[image_image_name] = '%s_%s' % ('storage', i) image_image_format = '%s_%s' % ('image_format', image_name) params[image_image_format] = params.get('image_format_extra', 'qcow2') image_image_size = '%s_%s' % ('image_size', image_name) params[image_image_size] = params.get('image_size_extra', '128K') return params def find_new_device(check_cmd, device_string, chk_timeout=5.0): end_time = time.time() + chk_timeout idx = ("wmic" in check_cmd and [0] or [-1])[0] while time.time() < end_time: new_line = session.cmd_output(check_cmd) for line in re.split("\n+", new_line.strip()): dev_name = re.split("\s+", line.strip())[idx] if dev_name not in device_string: return dev_name time.sleep(0.1) return None def find_del_device(check_cmd, device_string, chk_timeout=5.0): end_time = time.time() + chk_timeout idx = ("wmic" in check_cmd and [0] or [-1])[0] while time.time() < end_time: new_line = session.cmd_output(check_cmd) for line in re.split("\n+", device_string.strip()): dev_name = re.split("\s+", line.strip())[idx] if dev_name not in new_line: return dev_name time.sleep(0.1) return None # Select an image file def find_image(pci_num): image_params = params.object_params("%s" % img_list[pci_num + 1]) o = storage.get_image_filename(image_params, data_dir.get_data_dir()) return o def pci_add_block(pci_num, queues, pci_id): image_filename = find_image(pci_num) pci_add_cmd = ("pci_add pci_addr=auto storage file=%s,if=%s" % (image_filename, pci_model)) return pci_add(pci_add_cmd) def pci_add(pci_add_cmd): guest_devices = session.cmd_output(chk_cmd) error.context("Adding pci device with command 'pci_add'") add_output = vm.monitor.send_args_cmd(pci_add_cmd, convert=False) guest_device = find_new_device(chk_cmd, guest_devices) pci_info.append(['', '', add_output, pci_model, guest_device]) if "OK domain" not in add_output: raise error.TestFail("Add PCI device failed. " "Monitor command is: %s, Output: %r" % (pci_add_cmd, add_output)) return vm.monitor.info("pci") def is_supported_device(dev): # Probe qemu to verify what is the supported syntax for PCI hotplug cmd_output = vm.monitor.human_monitor_cmd("?") if len(re.findall("\ndevice_add", cmd_output)) > 0: cmd_type = "device_add" elif len(re.findall("\npci_add", cmd_output)) > 0: cmd_type = "pci_add" else: raise error.TestError("Unknown version of qemu") # Probe qemu for a list of supported devices probe_output = vm.monitor.human_monitor_cmd("%s ?" % cmd_type) devices_supported = [ j.strip('"') for j in re.findall('\"[a-z|0-9|\-|\_|\,|\.]*\"', probe_output, re.MULTILINE) ] logging.debug( "QEMU reported the following supported devices for " "PCI hotplug: %s", devices_supported) return (dev in devices_supported) def verify_supported_device(dev): if not is_supported_device(dev): raise error.TestError("%s doesn't support device: %s" % (cmd_type, dev)) def device_add_block(pci_num, queues=1, pci_id=None): if pci_id is not None: device_id = pci_type + "-" + pci_id else: device_id = pci_type + "-" + utils_misc.generate_random_id() pci_info.append([device_id, device_id]) image_format = params.get("image_format_%s" % img_list[pci_num + 1]) if not image_format: image_format = params.get("image_format", "qcow2") image_filename = find_image(pci_num) pci_model = params.get("pci_model") controller_model = None if pci_model == "virtio": pci_model = "virtio-blk-pci" if pci_model == "scsi": pci_model = "scsi-disk" if arch.ARCH in ('ppc64', 'ppc64le'): controller_model = "spapr-vscsi" else: controller_model = "lsi53c895a" verify_supported_device(controller_model) controller_id = "controller-" + device_id controller_add_cmd = ("device_add %s,id=%s" % (controller_model, controller_id)) error.context("Adding SCSI controller.") vm.monitor.send_args_cmd(controller_add_cmd) verify_supported_device(pci_model) if drive_cmd_type == "drive_add": driver_add_cmd = ("%s auto file=%s,if=none,format=%s,id=%s" % (drive_cmd_type, image_filename, image_format, pci_info[pci_num][0])) elif drive_cmd_type == "__com.redhat_drive_add": driver_add_cmd = ("%s file=%s,format=%s,id=%s" % (drive_cmd_type, image_filename, image_format, pci_info[pci_num][0])) # add driver. error.context("Adding driver.") vm.monitor.send_args_cmd(driver_add_cmd, convert=False) pci_add_cmd = ("device_add id=%s,driver=%s,drive=%s" % (pci_info[pci_num][1], pci_model, pci_info[pci_num][0])) return device_add(pci_num, pci_add_cmd, pci_id=pci_id) def device_add(pci_num, pci_add_cmd, pci_id=None): error.context("Adding pci device with command 'device_add'") guest_devices = session.cmd_output(chk_cmd) if vm.monitor.protocol == 'qmp': add_output = vm.monitor.send_args_cmd(pci_add_cmd) else: add_output = vm.monitor.send_args_cmd(pci_add_cmd, convert=False) guest_device = find_new_device(chk_cmd, guest_devices) if pci_id is None: pci_info[pci_num].append(add_output) pci_info[pci_num].append(pci_model) pci_info[pci_num].append(guest_device) after_add = vm.monitor.info("pci") if pci_info[pci_num][1] not in str(after_add): logging.error("Could not find matched id in monitor:" " %s" % pci_info[pci_num][1]) raise error.TestFail("Add device failed. Monitor command is: %s" ". Output: %r" % (pci_add_cmd, add_output)) return after_add # Hot add a pci device def add_device(pci_num, queues=1, pci_id=None): info_pci_ref = vm.monitor.info("pci") reference = session.cmd_output(reference_cmd) try: # get function for adding device. add_fuction = local_functions["%s_%s" % (cmd_type, pci_type)] except Exception: raise error.TestError("No function for adding " + "'%s' dev " % pci_type + "with '%s'" % cmd_type) after_add = None if add_fuction: # Do add pci device. after_add = add_fuction(pci_num, queues, pci_id) try: # Define a helper function to compare the output def _new_shown(): o = session.cmd_output(reference_cmd) return o != reference # Define a helper function to catch PCI device string def _find_pci(): output = session.cmd_output(params.get("find_pci_cmd")) output = map(string.strip, output.splitlines()) ref = map(string.strip, reference.splitlines()) output = [_ for _ in output if _ not in ref] output = "\n".join(output) if re.search(params.get("match_string"), output, re.I): return True return False error.context("Start checking new added device") # Compare the output of 'info pci' if after_add == info_pci_ref: raise error.TestFail("No new PCI device shown after " "executing monitor command: 'info pci'") secs = int(params.get("wait_secs_for_hook_up")) if not utils_misc.wait_for(_new_shown, test_timeout, secs, 3): raise error.TestFail("No new device shown in output of" + "command executed inside the " + "guest: %s" % reference_cmd) if not utils_misc.wait_for(_find_pci, test_timeout, 3, 3): raise error.TestFail("PCI %s %s " % (pci_model, pci_type) + "device not found in guest. Command " + "was: %s" % params.get("find_pci_cmd")) # Test the newly added device try: session.cmd(params.get("pci_test_cmd") % (pci_num + 1)) except aexpect.ShellError, e: raise error.TestFail("Check for %s device failed" % pci_type + "after PCI hotplug." + "Output: %r" % e.output) except Exception: pci_del(pci_num, ignore_failure=True) raise # Hot delete a pci device def pci_del(pci_num, ignore_failure=False): def _device_removed(): after_del = vm.monitor.info("pci") return after_del != before_del before_del = vm.monitor.info("pci") if cmd_type == "pci_add": slot_id = int(pci_info[pci_num][2].split(",")[2].split()[1]) cmd = "pci_del pci_addr=%s" % hex(slot_id) vm.monitor.send_args_cmd(cmd, convert=False) elif cmd_type == "device_add": cmd = "device_del id=%s" % pci_info[pci_num][1] vm.monitor.send_args_cmd(cmd) if (not utils_misc.wait_for(_device_removed, test_timeout, 0, 1) and not ignore_failure): raise error.TestFail("Failed to hot remove PCI device: %s. " "Monitor command: %s" % (pci_info[pci_num][3], cmd)) params = prepare_image_params(params) env_process.process_images(env_process.preprocess_image, test, params) vm = env.get_vm(params["main_vm"]) vm.verify_alive() timeout = int(params.get("login_timeout", 360)) session = vm.wait_for_login(timeout=timeout) test_timeout = int(params.get("hotplug_timeout", 360)) reference_cmd = params["reference_cmd"] # Test if it is nic or block pci_type = params["pci_type"] pci_model = params["pci_model"] # Modprobe the module if specified in config file module = params.get("modprobe_module") if module: session.cmd("modprobe %s" % module) # check monitor type qemu_binary = utils_misc.get_qemu_binary(params) # Probe qemu to verify what is the supported syntax for PCI hotplug if vm.monitor.protocol == 'qmp': cmd_output = vm.monitor.info("commands") else: cmd_output = vm.monitor.human_monitor_cmd("help", debug=False) cmd_type = utils_misc.find_substring(str(cmd_output), "device_add", "pci_add") if not cmd_type: raise error.TestError("Could find a suitable method for hotplugging" " device in this version of qemu") # Determine syntax of drive hotplug # __com.redhat_drive_add == qemu-kvm-0.12 on RHEL 6 # drive_add == qemu-kvm-0.13 onwards drive_cmd_type = utils_misc.find_substring(str(cmd_output), "__com.redhat_drive_add", "drive_add") if not drive_cmd_type: raise error.TestError("Unknown version of qemu") local_functions = locals() pci_num_range = int(params.get("pci_num")) rp_times = int(params.get("repeat_times")) img_list = params.get("images").split() chk_cmd = params.get("guest_check_cmd") mark_cmd = params.get("mark_cmd") offset = params.get("offset") confirm_cmd = params.get("confirm_cmd") pci_info = [] # Add block device into guest for pci_num in xrange(pci_num_range): error.context("Prepare the %d removable pci device" % pci_num, logging.info) add_device(pci_num) if pci_info[pci_num][4] is not None: partition = pci_info[pci_num][4] cmd = mark_cmd % (partition, partition, offset) session.cmd(cmd) else: raise error.TestError("Device not init in guest") for j in range(rp_times): # pci_info is a list of list. # each element 'i' has 4 members: # pci_info[i][0] == device drive id, only used for device_add # pci_info[i][1] == device id, only used for device_add # pci_info[i][2] == output of device add command # pci_info[i][3] == device module name. # pci_info[i][4] == partition id in guest pci_num = random.randint(0, len(pci_info) - 1) error.context("start unplug pci device, repeat %d" % j, logging.info) guest_devices = session.cmd_output(chk_cmd) pci_del(pci_num) device_del = find_del_device(chk_cmd, guest_devices) if device_del != pci_info[pci_num][4]: raise error.TestFail("Device is not deleted in guest.") error.context("Start plug pci device, repeat %d" % j, logging.info) guest_devices = session.cmd_output(chk_cmd) add_device(pci_num, pci_id=pci_info[pci_num][0]) device_del = find_new_device(chk_cmd, guest_devices) if device_del != pci_info[pci_num][4]: raise error.TestFail("Device partition changed from %s to %s" % (pci_info[pci_num][4], device_del)) cmd = confirm_cmd % (pci_info[pci_num][4], offset) confirm_info = session.cmd_output(cmd) if device_del not in confirm_info: raise error.TestFail("Can not find partition tag in Guest: %s" % confirm_info)
def run(test, params, env): """ KVM sr-iov hotplug negatvie test: 1) Boot up VM. 2) Try to remove sr-iov device driver module (optional) 3) Hotplug sr-iov device to VM with negative parameters 4) Verify that qemu could handle the negative parameters check hotplug error message (optional) :param test: qemu test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment. """ def make_pci_add_cmd(pa_pci_id, pci_addr="auto"): pci_add_cmd = ("pci_add pci_addr=%s host host=%s,if=%s" % (pci_addr, pa_pci_id, pci_model)) if params.get("hotplug_params"): assign_param = params.get("hotplug_params").split() for param in assign_param: value = params.get(param) if value: pci_add_cmd += ",%s=%s" % (param, value) return pci_add_cmd def make_device_add_cmd(pa_pci_id, pci_addr=None): device_id = "%s" % pci_model + "-" + utils_misc.generate_random_id() pci_add_cmd = ("device_add id=%s,driver=pci-assign,host=%s" % (device_id, pa_pci_id)) if pci_addr is not None: pci_add_cmd += ",addr=%s" % pci_addr if params.get("hotplug_params"): assign_param = params.get("hotplug_params").split() for param in assign_param: value = params.get(param) if value: pci_add_cmd += ",%s=%s" % (param, value) return pci_add_cmd neg_msg = params.get("negative_msg") vm = env.get_vm(params["main_vm"]) vm.verify_alive() rp_times = int(params.get("repeat_times", 1)) pci_model = params.get("pci_model", "pci-assign") pci_invaild_addr = params.get("pci_invaild_addr") modprobe_cmd = params.get("modprobe_cmd") device = {} device["type"] = params.get("hotplug_device_type", "vf") device['mac'] = utils_net.generate_mac_address_simple() if params.get("device_name"): device["name"] = params.get("device_name") if vm.pci_assignable is not None: pa_pci_ids = vm.pci_assignable.request_devs(device) # Probe qemu to verify what is the supported syntax for PCI hotplug if vm.monitor.protocol == 'qmp': cmd_output = vm.monitor.info("commands") else: cmd_output = vm.monitor.send_args_cmd("help") if not cmd_output: raise error.TestError("Unknown version of qemu") cmd_type = utils_misc.find_substring(str(cmd_output), "pci_add", "device_add") for j in range(rp_times): if cmd_type == "pci_add": pci_add_cmd = make_pci_add_cmd(pa_pci_ids[0], pci_invaild_addr) elif cmd_type == "device_add": pci_add_cmd = make_device_add_cmd(pa_pci_ids[0], pci_invaild_addr) try: msg = "Adding pci device with command '%s'" % pci_add_cmd error.context(msg, logging.info) case_fail = False pci_add_cmd += ",bus=root_port" add_output = vm.monitor.send_args_cmd(pci_add_cmd, convert=False) case_fail = True except Exception, err: if neg_msg: msg = "Check negative hotplug error message" error.context(msg, logging.info) if neg_msg not in str(err): msg = "Could not find '%s' in" % neg_msg msg += " command output '%s'" % add_output raise error.TestFail(msg) logging.debug("Could not boot up vm, %s" % err) if case_fail: if neg_msg: msg = "Check negative hotplug error message" error.context(msg, logging.info) if neg_msg not in str(add_output): msg = "Could not find '%s' in" % neg_msg msg += " command output '%s'" % add_output raise error.TestFail(msg) logging.debug("Could not boot up vm, %s" % add_output)
def run(test, params, env): """ Test hotplug of PCI devices. (Elements between [] are configurable test parameters) 1) PCI add one/multi device (NIC / block) with(or without) repeat 2) Compare output of monitor command 'info pci'. 3) Compare output of guest command [reference_cmd]. 4) Verify whether pci_model is shown in [pci_find_cmd]. 5) Check whether the newly added PCI device works fine. 6) PCI delete the device, verify whether could remove the PCI device. 7) reboot VM after guest wakeup form S3/S4 status (Optional Step). :param test: QEMU test object. :param params: Dictionary with the test parameters. :param env: Dictionary with test environment. """ # Select an image file def find_image(pci_num): image_params = params.object_params("%s" % img_list[pci_num + 1]) o = storage.get_image_filename(image_params, data_dir.get_data_dir()) return o def pci_add_nic(pci_num): pci_add_cmd = "pci_add pci_addr=auto nic model=%s" % pci_model return pci_add(pci_add_cmd) def pci_add_block(pci_num): image_filename = find_image(pci_num) pci_add_cmd = ("pci_add pci_addr=auto storage file=%s,if=%s" % (image_filename, pci_model)) return pci_add(pci_add_cmd) def pci_add(pci_add_cmd): error.context("Adding pci device with command 'pci_add'", logging.info) add_output = vm.monitor.send_args_cmd(pci_add_cmd, convert=False) pci_info.append(['', '', add_output, pci_model]) if "OK domain" not in add_output: raise error.TestFail("Add PCI device failed. " "Monitor command is: %s, Output: %r" % (pci_add_cmd, add_output)) return vm.monitor.info("pci") def is_supported_device(dev): # Probe qemu to verify what is the supported syntax for PCI hotplug cmd_output = vm.monitor.human_monitor_cmd("?") if len(re.findall("\ndevice_add", cmd_output)) > 0: cmd_type = "device_add" elif len(re.findall("\npci_add", cmd_output)) > 0: cmd_type = "pci_add" else: raise error.TestError("Unknow version of qemu") # Probe qemu for a list of supported devices probe_output = vm.monitor.human_monitor_cmd("%s ?" % cmd_type) devices_supported = [ j.strip('"') for j in re.findall('\"[a-z|0-9|\-|\_|\,|\.]*\"', probe_output, re.MULTILINE) ] logging.debug( "QEMU reported the following supported devices for " "PCI hotplug: %s", devices_supported) return (dev in devices_supported) def verify_supported_device(dev): if not is_supported_device(dev): raise error.TestError("%s doesn't support device: %s" % (cmd_type, dev)) def device_add_nic(pci_num, queues=1): device_id = pci_type + "-" + utils_misc.generate_random_id() pci_info.append([device_id, device_id]) pci_model = params.get("pci_model") if pci_model == "virtio": pci_model = "virtio-net-pci" verify_supported_device(pci_model) pci_add_cmd = "device_add id=%s,driver=%s" % (pci_info[pci_num][1], pci_model) if queues > 1 and "virtio" in pci_model: pci_add_cmd += ",mq=on" return device_add(pci_num, pci_add_cmd) def device_add_block(pci_num, queues=1): device_id = pci_type + "-" + utils_misc.generate_random_id() pci_info.append([device_id, device_id]) image_format = params.get("image_format_%s" % img_list[pci_num + 1]) if not image_format: image_format = params.get("image_format", "qcow2") image_filename = find_image(pci_num) pci_model = params.get("pci_model") controller_model = None if pci_model == "virtio": pci_model = "virtio-blk-pci" if pci_model == "scsi" or pci_model == "scsi-hd": if pci_model == "scsi": pci_model = "scsi-disk" if arch.ARCH in ('ppc64', 'ppc64le'): controller_model = "spapr-vscsi" else: controller_model = "lsi53c895a" if pci_model == "scsi-hd": controller_model = "virtio-scsi-pci" verify_supported_device(controller_model) controller_id = "controller-" + device_id if vm.monitor.protocol == "human": controller_add_cmd = ("device_add %s,id=%s" % (controller_model, controller_id)) else: controller_add_cmd = ("device_add driver=%s,id=%s" % (controller_model, controller_id)) error.context("Adding SCSI controller.", logging.info) vm.monitor.send_args_cmd(controller_add_cmd, convert=False) verify_supported_device(pci_model) if drive_cmd_type == "drive_add": driver_add_cmd = ("%s auto file=%s,if=none,format=%s,id=%s" % (drive_cmd_type, image_filename, image_format, pci_info[pci_num][0])) elif drive_cmd_type == "__com.redhat_drive_add": driver_add_cmd = ("%s file=%s,format=%s,id=%s" % (drive_cmd_type, image_filename, image_format, pci_info[pci_num][0])) # add block device to vm device container image_name = img_list[pci_num + 1] image_params = params.object_params(image_name) image_name = pci_info[pci_num][0] blk_insert = vm.devices.images_define_by_params( image_name, image_params, 'disk') vm.devices.insert(blk_insert) env.register_vm(vm.name, vm) # add driver. error.context("Adding driver.", logging.info) vm.monitor.send_args_cmd(driver_add_cmd, convert=False) pci_add_cmd = ("device_add id=%s,driver=%s,drive=%s" % (pci_info[pci_num][1], pci_model, pci_info[pci_num][0])) return device_add(pci_num, pci_add_cmd) def device_add(pci_num, pci_add_cmd): error.context("Adding pci device with command 'device_add'", logging.info) if vm.monitor.protocol == 'qmp': add_output = vm.monitor.send_args_cmd(pci_add_cmd, convert=False) else: add_output = vm.monitor.send_args_cmd(pci_add_cmd, convert=False) pci_info[pci_num].append(add_output) pci_info[pci_num].append(pci_model) after_add = vm.monitor.info("pci") if pci_info[pci_num][1] not in str(after_add): logging.error("Could not find matched id in monitor:" " %s" % pci_info[pci_num][1]) raise error.TestFail("Add device failed. Monitor command is: %s" ". Output: %r" % (pci_add_cmd, add_output)) return after_add # Hot add a pci device def add_device(pci_num, queues=1): info_pci_ref = vm.monitor.info("pci") reference = session.cmd_output(reference_cmd) try: # get function for adding device. add_fuction = local_functions["%s_%s" % (cmd_type, pci_type)] except Exception: raise error.TestError("No function for adding '%s' dev with '%s'" % (pci_type, cmd_type)) after_add = None if add_fuction: # Do add pci device. after_add = add_fuction(pci_num, queues) try: # Define a helper function to compare the output def _new_shown(): o = session.cmd_output(reference_cmd) return o != reference # Define a helper function to catch PCI device string def _find_pci(): output = session.cmd_output(params.get("find_pci_cmd")) output = map(string.strip, output.splitlines()) ref = map(string.strip, reference.splitlines()) output = [_ for _ in output if _ not in ref] output = "\n".join(output) if re.search(params.get("match_string"), output, re.I | re.M): return True return False error.context("Start checking new added device", logging.info) # Compare the output of 'info pci' if after_add == info_pci_ref: raise error.TestFail("No new PCI device shown after executing " "monitor command: 'info pci'") secs = int(params.get("wait_secs_for_hook_up")) if not utils_misc.wait_for(_new_shown, test_timeout, secs, 3): raise error.TestFail( "No new device shown in output of command " "executed inside the guest: %s" % reference_cmd) if not utils_misc.wait_for(_find_pci, test_timeout, 3, 3): raise error.TestFail( "PCI %s %s device not found in guest. " "Command was: %s" % (pci_model, pci_type, params.get("find_pci_cmd"))) # Test the newly added device try: if params.get("pci_test_cmd"): test_cmd = re.sub("PCI_NUM", "%s" % (pci_num + 1), params.get("pci_test_cmd")) session.cmd(test_cmd, timeout=disk_op_timeout) except aexpect.ShellError, e: raise error.TestFail("Check for %s device failed after PCI " "hotplug. Output: %r" % (pci_type, e.output)) except Exception: pci_del(pci_num, ignore_failure=True) raise # Hot delete a pci device def pci_del(pci_num, ignore_failure=False): def _device_removed(): after_del = vm.monitor.info("pci") return after_del != before_del before_del = vm.monitor.info("pci") blk_removed = [] if cmd_type == "pci_add": slot_id = int(pci_info[pci_num][2].split(",")[2].split()[1]) cmd = "pci_del pci_addr=%s" % hex(slot_id) vm.monitor.send_args_cmd(cmd, convert=False) blk_removed.append(pci_info[pci_num][1]) elif cmd_type == "device_add": if vm.monitor.protocol == "human": cmd = "device_del %s" % pci_info[pci_num][1] else: cmd = "device_del id=%s" % pci_info[pci_num][1] vm.monitor.send_args_cmd(cmd, convert=False) if params.get("cmd_after_unplug_dev"): cmd = re.sub("PCI_NUM", "%s" % (pci_num + 1), params.get("cmd_after_unplug_dev")) session.cmd(cmd, timeout=disk_op_timeout) blk_removed.append(pci_info[pci_num][1]) pci_model = params.get("pci_model") if pci_model == "scsi" or pci_model == "scsi-hd": controller_id = "controller-" + pci_info[pci_num][0] if vm.monitor.protocol == "human": controller_del_cmd = "device_del %s" % controller_id else: controller_del_cmd = "device_del id=%s" % controller_id error.context("Deleting SCSI controller.", logging.info) vm.monitor.send_args_cmd(controller_del_cmd, convert=False) blk_removed.append(controller_id) if (not utils_misc.wait_for(_device_removed, test_timeout, 0, 1) and not ignore_failure): raise error.TestFail("Failed to hot remove PCI device: %s. " "Monitor command: %s" % (pci_info[pci_num][3], cmd)) # Remove the device from vm device container for device in vm.devices: if device.str_short() in blk_removed: vm.devices.remove(device) env.register_vm(vm.name, vm) vm = env.get_vm(params["main_vm"]) vm.verify_alive() timeout = int(params.get("login_timeout", 360)) session = vm.wait_for_login(timeout=timeout) test_timeout = int(params.get("hotplug_timeout", 360)) disk_op_timeout = int(params.get("disk_op_timeout", 360)) reference_cmd = params["reference_cmd"] # Test if it is nic or block pci_type = params["pci_type"] pci_model = params["pci_model"] # Modprobe the module if specified in config file module = params.get("modprobe_module") if module: session.cmd("modprobe %s" % module) # check monitor type qemu_binary = utils_misc.get_qemu_binary(params) qemu_binary = utils_misc.get_path(test.bindir, qemu_binary) # Probe qemu to verify what is the supported syntax for PCI hotplug if vm.monitor.protocol == 'qmp': cmd_output = vm.monitor.info("commands") else: cmd_output = vm.monitor.human_monitor_cmd("help", debug=False) cmd_type = utils_misc.find_substring(str(cmd_output), "device_add", "pci_add") if not cmd_output: raise error.TestError("Could find a suitable method for hotplugging" " device in this version of qemu") # Determine syntax of drive hotplug # __com.redhat_drive_add == qemu-kvm-0.12 on RHEL 6 # drive_add == qemu-kvm-0.13 onwards drive_cmd_type = utils_misc.find_substring(str(cmd_output), "__com.redhat_drive_add", "drive_add") if not drive_cmd_type: raise error.TestError("Could find a suitable method for hotplugging" " drive in this version of qemu") local_functions = locals() pci_num_range = int(params.get("pci_num")) queues = int(params.get("queues", 1)) rp_times = int(params.get("repeat_times")) img_list = params.get("images").split() context_msg = "Running sub test '%s' %s" for j in range(rp_times): # pci_info is a list of list. # each element 'i' has 4 members: # pci_info[i][0] == device drive id, only used for device_add # pci_info[i][1] == device id, only used for device_add # pci_info[i][2] == output of device add command # pci_info[i][3] == device module name. pci_info = [] for pci_num in xrange(pci_num_range): sub_type = params.get("sub_type_before_plug") if sub_type: error.context(context_msg % (sub_type, "before hotplug"), logging.info) utils_test.run_virt_sub_test(test, params, env, sub_type) error.context("Start hot-adding pci device, repeat %d" % j, logging.info) add_device(pci_num, queues) sub_type = params.get("sub_type_after_plug") if sub_type: error.context(context_msg % (sub_type, "after hotplug"), logging.info) utils_test.run_virt_sub_test(test, params, env, sub_type) for pci_num in xrange(pci_num_range): sub_type = params.get("sub_type_before_unplug") if sub_type: error.context(context_msg % (sub_type, "before hotunplug"), logging.info) utils_test.run_virt_sub_test(test, params, env, sub_type) error.context("start hot-deleting pci device, repeat %d" % j, logging.info) pci_del(-(pci_num + 1)) sub_type = params.get("sub_type_after_unplug") if sub_type: error.context(context_msg % (sub_type, "after hotunplug"), logging.info) utils_test.run_virt_sub_test(test, params, env, sub_type) if params.get("reboot_vm", "no") == "yes": vm.reboot()
def run(test, params, env): """ Test hotplug of PCI devices and check the status in guest. 1 Boot up a guest 2 Hotplug virtio disk to the guest. Record the id and partition name of the disk in a list. 3 Random choice a disk in the list. Unplug the disk and check the partition status. 4 Hotpulg the disk back to guest with the same monitor cmdline and same id which is record in step 2. 5 Check the partition status in guest. And confirm the disk with dd cmd 6 Repeat step 3 to 5 for N times :param test: KVM test object. :param params: Dictionary with the test parameters. :param env: Dictionary with test environment. """ def prepare_image_params(params): pci_num = int(params['pci_num']) for i in xrange(pci_num): image_name = '%s_%s' % ('stg', i) params['images'] = ' '.join([params['images'], image_name]) image_image_name = '%s_%s' % ('image_name', image_name) params[image_image_name] = '%s_%s' % ('storage', i) image_image_format = '%s_%s' % ('image_format', image_name) params[image_image_format] = params.get('image_format_extra', 'qcow2') image_image_size = '%s_%s' % ('image_size', image_name) params[image_image_size] = params.get('image_size_extra', '128K') return params def find_new_device(check_cmd, device_string, chk_timeout=5.0): end_time = time.time() + chk_timeout idx = ("wmic" in check_cmd and [0] or [-1])[0] while time.time() < end_time: new_line = session.cmd_output(check_cmd) for line in re.split("\n+", new_line.strip()): dev_name = re.split("\s+", line.strip())[idx] if dev_name not in device_string: return dev_name time.sleep(0.1) return None def find_del_device(check_cmd, device_string, chk_timeout=5.0): end_time = time.time() + chk_timeout idx = ("wmic" in check_cmd and [0] or [-1])[0] while time.time() < end_time: new_line = session.cmd_output(check_cmd) for line in re.split("\n+", device_string.strip()): dev_name = re.split("\s+", line.strip())[idx] if dev_name not in new_line: return dev_name time.sleep(0.1) return None # Select an image file def find_image(pci_num): image_params = params.object_params("%s" % img_list[pci_num + 1]) o = storage.get_image_filename(image_params, data_dir.get_data_dir()) return o def pci_add_block(pci_num, queues, pci_id): image_filename = find_image(pci_num) pci_add_cmd = ("pci_add pci_addr=auto storage file=%s,if=%s" % (image_filename, pci_model)) return pci_add(pci_add_cmd) def pci_add(pci_add_cmd): guest_devices = session.cmd_output(chk_cmd) error.context("Adding pci device with command 'pci_add'") add_output = vm.monitor.send_args_cmd(pci_add_cmd, convert=False) guest_device = find_new_device(chk_cmd, guest_devices) pci_info.append(['', '', add_output, pci_model, guest_device]) if "OK domain" not in add_output: raise error.TestFail("Add PCI device failed. " "Monitor command is: %s, Output: %r" % (pci_add_cmd, add_output)) return vm.monitor.info("pci") def is_supported_device(dev): # Probe qemu to verify what is the supported syntax for PCI hotplug cmd_output = vm.monitor.human_monitor_cmd("?") if len(re.findall("\ndevice_add", cmd_output)) > 0: cmd_type = "device_add" elif len(re.findall("\npci_add", cmd_output)) > 0: cmd_type = "pci_add" else: raise error.TestError("Unknown version of qemu") # Probe qemu for a list of supported devices probe_output = vm.monitor.human_monitor_cmd("%s ?" % cmd_type) devices_supported = [j.strip('"') for j in re.findall('\"[a-z|0-9|\-|\_|\,|\.]*\"', probe_output, re.MULTILINE)] logging.debug("QEMU reported the following supported devices for " "PCI hotplug: %s", devices_supported) return (dev in devices_supported) def verify_supported_device(dev): if not is_supported_device(dev): raise error.TestError("%s doesn't support device: %s" % (cmd_type, dev)) def device_add_block(pci_num, queues=1, pci_id=None): if pci_id is not None: device_id = pci_type + "-" + pci_id else: device_id = pci_type + "-" + utils_misc.generate_random_id() pci_info.append([device_id, device_id]) image_format = params.get("image_format_%s" % img_list[pci_num + 1]) if not image_format: image_format = params.get("image_format", "qcow2") image_filename = find_image(pci_num) pci_model = params.get("pci_model") controller_model = None if pci_model == "virtio": pci_model = "virtio-blk-pci" if pci_model == "scsi": pci_model = "scsi-disk" if arch.ARCH in ('ppc64', 'ppc64le'): controller_model = "spapr-vscsi" else: controller_model = "lsi53c895a" verify_supported_device(controller_model) controller_id = "controller-" + device_id controller_add_cmd = ("device_add %s,id=%s" % (controller_model, controller_id)) error.context("Adding SCSI controller.") vm.monitor.send_args_cmd(controller_add_cmd) verify_supported_device(pci_model) if drive_cmd_type == "drive_add": driver_add_cmd = ("%s auto file=%s,if=none,format=%s,id=%s" % (drive_cmd_type, image_filename, image_format, pci_info[pci_num][0])) elif drive_cmd_type == "__com.redhat_drive_add": driver_add_cmd = ("%s file=%s,format=%s,id=%s" % (drive_cmd_type, image_filename, image_format, pci_info[pci_num][0])) # add driver. error.context("Adding driver.") vm.monitor.send_args_cmd(driver_add_cmd, convert=False) pci_add_cmd = ("device_add id=%s,driver=%s,drive=%s" % (pci_info[pci_num][1], pci_model, pci_info[pci_num][0]) ) return device_add(pci_num, pci_add_cmd, pci_id=pci_id) def device_add(pci_num, pci_add_cmd, pci_id=None): error.context("Adding pci device with command 'device_add'") guest_devices = session.cmd_output(chk_cmd) if vm.monitor.protocol == 'qmp': add_output = vm.monitor.send_args_cmd(pci_add_cmd) else: add_output = vm.monitor.send_args_cmd(pci_add_cmd, convert=False) guest_device = find_new_device(chk_cmd, guest_devices) if pci_id is None: pci_info[pci_num].append(add_output) pci_info[pci_num].append(pci_model) pci_info[pci_num].append(guest_device) after_add = vm.monitor.info("pci") if pci_info[pci_num][1] not in str(after_add): logging.error("Could not find matched id in monitor:" " %s" % pci_info[pci_num][1]) raise error.TestFail("Add device failed. Monitor command is: %s" ". Output: %r" % (pci_add_cmd, add_output)) return after_add # Hot add a pci device def add_device(pci_num, queues=1, pci_id=None): info_pci_ref = vm.monitor.info("pci") reference = session.cmd_output(reference_cmd) try: # get function for adding device. add_fuction = local_functions["%s_%s" % (cmd_type, pci_type)] except Exception: raise error.TestError("No function for adding " + "'%s' dev " % pci_type + "with '%s'" % cmd_type) after_add = None if add_fuction: # Do add pci device. after_add = add_fuction(pci_num, queues, pci_id) try: # Define a helper function to compare the output def _new_shown(): o = session.cmd_output(reference_cmd) return o != reference # Define a helper function to catch PCI device string def _find_pci(): output = session.cmd_output(params.get("find_pci_cmd")) output = map(string.strip, output.splitlines()) ref = map(string.strip, reference.splitlines()) output = [_ for _ in output if _ not in ref] output = "\n".join(output) if re.search(params.get("match_string"), output, re.I): return True return False error.context("Start checking new added device") # Compare the output of 'info pci' if after_add == info_pci_ref: raise error.TestFail("No new PCI device shown after " "executing monitor command: 'info pci'") secs = int(params.get("wait_secs_for_hook_up", 3)) if not utils_misc.wait_for(_new_shown, test_timeout, secs, 3): raise error.TestFail("No new device shown in output of" + "command executed inside the " + "guest: %s" % reference_cmd) if not utils_misc.wait_for(_find_pci, test_timeout, 3, 3): raise error.TestFail("PCI %s %s " % (pci_model, pci_type) + "device not found in guest. Command " + "was: %s" % params.get("find_pci_cmd")) # Test the newly added device try: session.cmd(params.get("pci_test_cmd") % (pci_num + 1)) except aexpect.ShellError, e: raise error.TestFail("Check for %s device failed" % pci_type + "after PCI hotplug." + "Output: %r" % e.output) except Exception: pci_del(pci_num, ignore_failure=True) raise # Hot delete a pci device def pci_del(pci_num, ignore_failure=False): def _device_removed(): after_del = vm.monitor.info("pci") return after_del != before_del before_del = vm.monitor.info("pci") if cmd_type == "pci_add": slot_id = int(pci_info[pci_num][2].split(",")[2].split()[1]) cmd = "pci_del pci_addr=%s" % hex(slot_id) vm.monitor.send_args_cmd(cmd, convert=False) elif cmd_type == "device_add": cmd = "device_del id=%s" % pci_info[pci_num][1] vm.monitor.send_args_cmd(cmd) if (not utils_misc.wait_for(_device_removed, test_timeout, 0, 1) and not ignore_failure): raise error.TestFail("Failed to hot remove PCI device: %s. " "Monitor command: %s" % (pci_info[pci_num][3], cmd)) params = prepare_image_params(params) env_process.process_images(env_process.preprocess_image, test, params) vm = env.get_vm(params["main_vm"]) vm.verify_alive() timeout = int(params.get("login_timeout", 360)) session = vm.wait_for_login(timeout=timeout) test_timeout = int(params.get("hotplug_timeout", 360)) reference_cmd = params["reference_cmd"] # Test if it is nic or block pci_type = params["pci_type"] pci_model = params["pci_model"] # Modprobe the module if specified in config file module = params.get("modprobe_module") if module: session.cmd("modprobe %s" % module) # check monitor type qemu_binary = utils_misc.get_qemu_binary(params) # Probe qemu to verify what is the supported syntax for PCI hotplug if vm.monitor.protocol == 'qmp': cmd_output = vm.monitor.info("commands") else: cmd_output = vm.monitor.human_monitor_cmd("help", debug=False) cmd_type = utils_misc.find_substring(str(cmd_output), "device_add", "pci_add") if not cmd_type: raise error.TestError("Could find a suitable method for hotplugging" " device in this version of qemu") # Determine syntax of drive hotplug # __com.redhat_drive_add == qemu-kvm-0.12 on RHEL 6 # drive_add == qemu-kvm-0.13 onwards drive_cmd_type = utils_misc.find_substring(str(cmd_output), "__com.redhat_drive_add", "drive_add") if not drive_cmd_type: raise error.TestError("Unknown version of qemu") local_functions = locals() pci_num_range = int(params.get("pci_num")) rp_times = int(params.get("repeat_times")) img_list = params.get("images").split() chk_cmd = params.get("guest_check_cmd") mark_cmd = params.get("mark_cmd") offset = params.get("offset") confirm_cmd = params.get("confirm_cmd") pci_info = [] # Add block device into guest for pci_num in xrange(pci_num_range): error.context("Prepare the %d removable pci device" % pci_num, logging.info) add_device(pci_num) if pci_info[pci_num][4] is not None: partition = pci_info[pci_num][4] cmd = mark_cmd % (partition, partition, offset) session.cmd(cmd) else: raise error.TestError("Device not init in guest") for j in range(rp_times): # pci_info is a list of list. # each element 'i' has 4 members: # pci_info[i][0] == device drive id, only used for device_add # pci_info[i][1] == device id, only used for device_add # pci_info[i][2] == output of device add command # pci_info[i][3] == device module name. # pci_info[i][4] == partition id in guest pci_num = random.randint(0, len(pci_info) - 1) error.context("start unplug pci device, repeat %d" % j, logging.info) guest_devices = session.cmd_output(chk_cmd) pci_del(pci_num) device_del = find_del_device(chk_cmd, guest_devices) if device_del != pci_info[pci_num][4]: raise error.TestFail("Device is not deleted in guest.") error.context("Start plug pci device, repeat %d" % j, logging.info) guest_devices = session.cmd_output(chk_cmd) add_device(pci_num, pci_id=pci_info[pci_num][0]) device_del = find_new_device(chk_cmd, guest_devices) if device_del != pci_info[pci_num][4]: raise error.TestFail("Device partition changed from %s to %s" % (pci_info[pci_num][4], device_del)) cmd = confirm_cmd % (pci_info[pci_num][4], offset) confirm_info = session.cmd_output(cmd) if device_del not in confirm_info: raise error.TestFail("Can not find partition tag in Guest: %s" % confirm_info)
def run(test, params, env): """ KVM sr-iov hotplug negatvie test: 1) Boot up VM. 2) Try to remove sr-iov device driver module (optional) 3) Hotplug sr-iov device to VM with negative parameters 4) Verify that qemu could handle the negative parameters check hotplug error message (optional) :param test: qemu test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment. """ def make_pci_add_cmd(pa_pci_id, pci_addr="auto"): pci_add_cmd = ("pci_add pci_addr=%s host host=%s,if=%s" % (pci_addr, pa_pci_id, pci_model)) if params.get("hotplug_params"): assign_param = params.get("hotplug_params").split() for param in assign_param: value = params.get(param) if value: pci_add_cmd += ",%s=%s" % (param, value) return pci_add_cmd def make_device_add_cmd(pa_pci_id, pci_addr=None): device_id = "%s" % pci_model + "-" + utils_misc.generate_random_id() pci_add_cmd = ("device_add id=%s,driver=pci-assign,host=%s" % (device_id, pa_pci_id)) if pci_addr is not None: pci_add_cmd += ",addr=%s" % pci_addr if params.get("hotplug_params"): assign_param = params.get("hotplug_params").split() for param in assign_param: value = params.get(param) if value: pci_add_cmd += ",%s=%s" % (param, value) return pci_add_cmd neg_msg = params.get("negative_msg") vm = env.get_vm(params["main_vm"]) vm.verify_alive() rp_times = int(params.get("repeat_times", 1)) pci_model = params.get("pci_model", "pci-assign") pci_invaild_addr = params.get("pci_invaild_addr") modprobe_cmd = params.get("modprobe_cmd") device = {} device["type"] = params.get("hotplug_device_type", "vf") device['mac'] = utils_net.generate_mac_address_simple() if params.get("device_name"): device["name"] = params.get("device_name") if vm.pci_assignable is not None: pa_pci_ids = vm.pci_assignable.request_devs(device) # Probe qemu to verify what is the supported syntax for PCI hotplug if vm.monitor.protocol == 'qmp': cmd_output = vm.monitor.info("commands") else: cmd_output = vm.monitor.send_args_cmd("help") if not cmd_output: raise error.TestError("Unknown version of qemu") cmd_type = utils_misc.find_substring(str(cmd_output), "pci_add", "device_add") for j in range(rp_times): if cmd_type == "pci_add": pci_add_cmd = make_pci_add_cmd(pa_pci_ids[0], pci_invaild_addr) elif cmd_type == "device_add": pci_add_cmd = make_device_add_cmd(pa_pci_ids[0], pci_invaild_addr) try: msg = "Adding pci device with command '%s'" % pci_add_cmd error.context(msg, logging.info) case_fail = False add_output = vm.monitor.send_args_cmd(pci_add_cmd, convert=False) case_fail = True except Exception, err: if neg_msg: msg = "Check negative hotplug error message" error.context(msg, logging.info) if neg_msg not in str(err): msg = "Could not find '%s' in" % neg_msg msg += " command output '%s'" % add_output raise error.TestFail(msg) logging.debug("Could not boot up vm, %s" % err) if case_fail: if neg_msg: msg = "Check negative hotplug error message" error.context(msg, logging.info) if neg_msg not in str(add_output): msg = "Could not find '%s' in" % neg_msg msg += " command output '%s'" % add_output raise error.TestFail(msg) logging.debug("Could not boot up vm, %s" % add_output)
def run(test, params, env): """ Test hotplug of sr-iov devices. (Elements between [] are configurable test parameters) 1) Set up sr-iov test environment in host. 2) Start VM. 3) Disable the primary link(s) of guest. 4) PCI add one/multi sr-io deivce with (or without) repeat 5) Compare output of monitor command 'info pci'. 6) Compare output of guest command [reference_cmd]. 7) Verify whether pci_model is shown in [pci_find_cmd]. 8) Check whether the newly added PCI device works fine. 9) Delete the device, verify whether could remove the sr-iov device. 10) Re-enabling the primary link(s) of guest. :param test: QEMU test object. :param params: Dictionary with the test parameters. :param env: Dictionary with test environment. """ def check_interface(iface, nic_filter): cmd = "ifconfig %s" % str(iface) session = vm.wait_for_serial_login(timeout=timeout) status, output = session.cmd_status_output(cmd) if status: test.error("Guest command '%s' fail with output: %s." % (cmd, output)) if re.findall(nic_filter, output, re.MULTILINE | re.DOTALL): return True return False def get_active_network_device(session, nic_filter): devnames = [] cmd = "ifconfig -a" nic_reg = r"\w+(?=: flags)|\w+(?=\s*Link)" status, output = session.cmd_status_output(cmd) if status: test.error("Guest command '%s' fail with output: %s." % (cmd, output)) ifaces = re.findall(nic_reg, output) for iface in ifaces: if check_interface(str(iface), nic_filter): devnames.append(iface) return devnames def pci_add_iov(pci_num): pci_add_cmd = ("pci_add pci_addr=auto host host=%s,if=%s" % (pa_pci_ids[pci_num], pci_model)) if params.get("hotplug_params"): assign_param = params.get("hotplug_params").split() for param in assign_param: value = params.get(param) if value: pci_add_cmd += ",%s=%s" % (param, value) return pci_add(pci_add_cmd) def pci_add(pci_add_cmd): error_context.context("Adding pci device with command 'pci_add'") add_output = vm.monitor.send_args_cmd(pci_add_cmd, convert=False) pci_info.append(['', add_output]) if "OK domain" not in add_output: test.fail("Add PCI device failed. Monitor command is: %s, " "Output: %r" % (pci_add_cmd, add_output)) return vm.monitor.info("pci") def check_support_device(dev): if vm.monitor.protocol == 'qmp': devices_supported = vm.monitor.human_monitor_cmd("%s ?" % cmd_type) else: devices_supported = vm.monitor.send_args_cmd("%s ?" % cmd_type) # Check if the device is support in qemu is_support = utils_misc.find_substring(devices_supported, dev) if not is_support: test.error("%s doesn't support device: %s" % (cmd_type, dev)) def device_add_iov(pci_num): device_id = "%s" % pci_model + "-" + utils_misc.generate_random_id() pci_info.append([device_id]) driver = params.get("device_driver", "pci-assign") check_support_device(driver) pci_add_cmd = ("device_add id=%s,driver=%s,host=%s" % (pci_info[pci_num][0], driver, pa_pci_ids[pci_num])) if params.get("hotplug_params"): assign_param = params.get("hotplug_params").split() for param in assign_param: value = params.get(param) if value: pci_add_cmd += ",%s=%s" % (param, value) return device_add(pci_num, pci_add_cmd) def device_add(pci_num, pci_add_cmd): error_context.context("Adding pci device with command 'device_add'") if vm.monitor.protocol == 'qmp': add_output = vm.monitor.send_args_cmd(pci_add_cmd) else: add_output = vm.monitor.send_args_cmd(pci_add_cmd, convert=False) pci_info[pci_num].append(add_output) after_add = vm.monitor.info("pci") if pci_info[pci_num][0] not in str(after_add): logging.debug("Print info pci after add the block: %s", after_add) test.fail("Add device failed. Monitor command is: %s" ". Output: %r" % (pci_add_cmd, add_output)) return after_add def clean_network_scripts(): logging.debug("Clean up network scripts in guest") session = vm.wait_for_serial_login(timeout=timeout) if "ubuntu" in vm.get_distro().lower(): iface_script = "/etc/network/interfaces" cmd = "cat %s.BACKUP" % iface_script if not session.cmd_status(cmd): cmd = "mv %s.BACKUP %s" % (iface_script, iface_script) status, output = session.cmd_status_output(cmd) if status: test.error("Failed to cleanup network script in guest: " "%s" % output) else: global iface_scripts for iface_script in iface_scripts: cmd = "rm -f %s" % iface_script status, output = session.cmd_status_output(cmd) if status: test.error("Failed to delete iface_script") iface_scripts.remove(iface_script) # Hot add a pci device def add_device(pci_num): global iface_scripts reference_cmd = params["reference_cmd"] info_pci_ref = vm.monitor.info("pci") session = vm.wait_for_serial_login(timeout=timeout) reference = session.cmd_output(reference_cmd) active_nics = get_active_network_device(session, nic_filter) logging.debug("Active nics before hotplug - %s", active_nics) # Stop the VM monitor and try hot adding SRIOV dev if params.get("vm_stop", "no") == "yes": logging.debug("stop the monitor of the VM before hotplug") vm.pause() try: # get function for adding device. add_function = local_functions["%s_iov" % cmd_type] except Exception: test.error("No function for adding sr-iov dev with '%s'" % cmd_type) after_add = None if add_function: # Do add pci device. after_add = add_function(pci_num) try: # Define a helper function to compare the output def _new_shown(): output = session.cmd_output(reference_cmd) return output != reference # Define a helper function to make sure new nic could get ip. def _check_ip(): post_nics = get_active_network_device(session, nic_filter) logging.debug("Active nics after hotplug - %s", post_nics) return (len(active_nics) <= len(post_nics) and active_nics != post_nics) # Define a helper function to catch PCI device string def _find_pci(): output = session.cmd_output("lspci -nn") if re.search(vf_filter, output, re.IGNORECASE): return True else: return False # Resume the VM if params.get("vm_resume", "no") == "yes": logging.debug("resuming the VM after hotplug") vm.resume() # Reboot the VM if params.get("vm_reboot", "no") == "yes": logging.debug("Rebooting the VM after hotplug") vm.reboot() session = vm.wait_for_serial_login(timeout=timeout) error_context.context("Start checking new added device") # Compare the output of 'info pci' if after_add == info_pci_ref: test.fail("No new PCI device shown after executing " "monitor command: 'info pci'") secs = int(params["wait_secs_for_hook_up"]) if not utils_misc.wait_for(_new_shown, test_timeout, secs, 3): test.fail("No new device shown in output of command " "executed inside the guest: %s" % reference_cmd) if not utils_misc.wait_for(_find_pci, test_timeout, 3, 3): test.fail("New add device not found in guest. " "Command was: lspci -nn") # Assign static IP to the hotplugged interface if params.get("assign_static_ip", "no") == "yes": cmd = "service networking restart" static_ip = next(ip_gen) net_mask = params.get("static_net_mask", "255.255.255.0") broadcast = params.get("static_broadcast", "10.10.10.255") pci_id = utils_misc.get_pci_id_using_filter(vf_filter, session) logging.debug("PCIs associated with %s - %s", vf_filter, ', '.join(map(str, pci_id))) for each_pci in pci_id: iface_name = utils_misc.get_interface_from_pci_id( each_pci, session) logging.debug("Interface associated with PCI %s - %s", each_pci, iface_name) mac = session.cmd_output("ethtool -P %s" % iface_name) mac = mac.split("Permanent address:")[-1].strip() logging.debug("mac address of %s: %s", iface_name, mac) # backup the network script for other distros if "ubuntu" not in vm.get_distro().lower(): cmd = "service network restart" iface_scripts.append( utils_net.get_network_cfg_file(iface_name)) if not check_interface(str(iface_name), nic_filter): utils_net.create_network_script(iface_name, mac, boot_proto="static", net_mask=net_mask, vm=vm, ip_addr=static_ip) status, output = session.cmd_status_output(cmd) if status: test.error("Failed to set static ip in guest: " "%s" % output) # Test the newly added device if not utils_misc.wait_for(_check_ip, 120, 3, 3): ifconfig = session.cmd_output("ifconfig -a") test.fail("New hotpluged device could not get ip " "after 120s in guest. guest ifconfig " "output: \n%s" % ifconfig) try: session.cmd(params["pci_test_cmd"] % (pci_num + 1)) except aexpect.ShellError as e: test.fail("Check device failed after PCI " "hotplug. Output: %r" % e.output) except Exception: pci_del(pci_num, ignore_failure=True) raise # Hot delete a pci device def pci_del(pci_num, ignore_failure=False): def _device_removed(): after_del = vm.monitor.info("pci") return after_del != before_del before_del = vm.monitor.info("pci") if cmd_type == "pci_add": slot_id = "0" + pci_info[pci_num][1].split(",")[2].split()[1] cmd = "pci_del pci_addr=%s" % slot_id vm.monitor.send_args_cmd(cmd, convert=False) elif cmd_type == "device_add": cmd = "device_del id=%s" % pci_info[pci_num][0] vm.monitor.send_args_cmd(cmd) if (not utils_misc.wait_for(_device_removed, test_timeout, 0, 1) and not ignore_failure): test.fail("Failed to hot remove PCI device: %s. " "Monitor command: %s" % (pci_model, cmd)) vm = env.get_vm(params["main_vm"]) vm.verify_alive() timeout = int(params.get("login_timeout", 360)) session = vm.wait_for_serial_login(timeout=timeout) test_timeout = int(params.get("test_timeout", 360)) # Test if it is nic or block pci_num_range = int(params.get("pci_num", 1)) rp_times = int(params.get("repeat_times", 1)) pci_model = params.get("pci_model", "pci-assign") vf_filter = params.get("vf_filter_re") generate_mac = params.get("generate_mac", "yes") nic_filter = params["nic_interface_filter"] devices = [] device_type = params.get("hotplug_device_type", "vf") for i in range(pci_num_range): device = {} device["type"] = device_type if generate_mac == "yes": device['mac'] = utils_net.generate_mac_address_simple() if params.get("device_name"): device["name"] = params.get("device_name") devices.append(device) device_driver = params.get("device_driver", "pci-assign") if vm.pci_assignable is None: vm.pci_assignable = test_setup.PciAssignable( driver=params.get("driver"), driver_option=params.get("driver_option"), host_set_flag=params.get("host_setup_flag"), kvm_params=params.get("kvm_default"), vf_filter_re=vf_filter, pf_filter_re=params.get("pf_filter_re"), device_driver=device_driver, pa_type=params.get("pci_assignable")) pa_pci_ids = vm.pci_assignable.request_devs(devices) # Modprobe the module if specified in config file module = params.get("modprobe_module") if module: error_context.context("modprobe the module %s" % module, logging.info) session.cmd("modprobe %s" % module) # Probe qemu to verify what is the supported syntax for PCI hotplug if vm.monitor.protocol == 'qmp': cmd_o = vm.monitor.info("commands") else: cmd_o = vm.monitor.send_args_cmd("help") cmd_type = utils_misc.find_substring(str(cmd_o), "device_add", "pci_add") if not cmd_o: test.error("Unknown version of qemu") local_functions = locals() if params.get("enable_set_link" "yes") == "yes": error_context.context("Disable the primary link(s) of guest", logging.info) for nic in vm.virtnet: vm.set_link(nic.device_id, up=False) try: for j in range(rp_times): # pci_info is a list of list. # each element 'i' has 4 members: # pci_info[i][0] == device id, only used for device_add # pci_info[i][1] == output of device add command pci_info = [] if params.get("assign_static_ip", "no") == "yes": ip_gen = utils_net.gen_ipv4_addr(exclude_ips=[]) # backup the network script file if it is ubuntu if "ubuntu" in vm.get_distro().lower(): session = vm.wait_for_serial_login(timeout=timeout) iface_script = "/etc/network/interfaces" cmd = "cat %s" % iface_script if not session.cmd_status(cmd): logging.debug("Backup network script in guest - %s", iface_script) cmd = "cp %s %s.BACKUP" % (iface_script, iface_script) status, output = session.cmd_status_output(cmd) if status: test.error("Failed to backup in guest: %s" % output) for pci_num in range(pci_num_range): msg = "Start hot-adding %sth pci device," % (pci_num + 1) msg += " repeat %d" % (j + 1) error_context.context(msg, logging.info) add_device(pci_num) sub_type = params.get("sub_type_after_plug") if sub_type: error_context.context( "Running sub test '%s' after hotplug" % sub_type, logging.info) utils_test.run_virt_sub_test(test, params, env, sub_type) if "guest_suspend" == sub_type: # Hotpluged device have been released after guest suspend, # so do not need unpluged step. break for pci_num in range(pci_num_range): msg = "start hot-deleting %sth pci device," % (pci_num + 1) msg += " repeat %d" % (j + 1) error_context.context(msg, logging.info) pci_del(-(pci_num + 1)) # cleanup network script after hot deleting pci device clean_network_scripts() finally: # clean network scripts on error clean_network_scripts() if params.get("enable_set_link", "yes") == "yes": error_context.context("Re-enabling the primary link(s) of guest", logging.info) for nic in vm.virtnet: vm.set_link(nic.device_id, up=True) if session: session.close()
def run(test, params, env): """ Test hot unplug of PCI devices. 1) Set up test environment in host if test sr-iov. 2) Start VM. 3) Get the device id that want to unplug. 4) Delete the device, verify whether could remove the PCI device. :param test: QEMU test object. :param params: Dictionary with the test parameters. :param env: Dictionary with test environment. """ def find_pci(): output = vm.monitor.info("qtree") devices = re.findall(match_string, output) return devices # Hot delete a pci device def pci_del(device, ignore_failure=False): def _device_removed(): after_del = vm.monitor.info("pci") return after_del != before_del before_del = vm.monitor.info("pci") if cmd_type == "device_del": cmd = "device_del id=%s" % device vm.monitor.send_args_cmd(cmd) else: raise error.TestFail("device_del command is not supported") if (not utils_misc.wait_for(_device_removed, test_timeout, 0, 1) and not ignore_failure): raise error.TestFail("Failed to hot remove PCI device: %s. " "Monitor command: %s" % (pci_model, cmd)) vm = env.get_vm(params["main_vm"]) vm.verify_alive() timeout = int(params.get("login_timeout", 360)) session = vm.wait_for_login(timeout=timeout) test_timeout = int(params.get("test_timeout", 360)) # Test if it is nic or block pci_num = int(params.get("unplug_pci_num", 1)) pci_model = params.get("pci_model", "pci-assign") # Need udpate match_string if you use a card other than 82576 match_string = params.get("match_string", "dev: %s, id \"(.*)\"") match_string = match_string % pci_model # Modprobe the module if specified in config file module = params.get("modprobe_module") if module: error.context("modprobe the module %s" % module, logging.info) session.cmd("modprobe %s" % module) # Probe qemu to verify what is the supported syntax for PCI hotplug if vm.monitor.protocol == "qmp": cmd_o = vm.monitor.info("commands") else: cmd_o = vm.monitor.send_args_cmd("help") if not cmd_o: raise error.TestError("Unknown version of qemu") cmd_type = utils_misc.find_substring(str(cmd_o), "device_del") devices = find_pci() context_msg = "Running sub test '%s' %s" sub_type = params.get("sub_type_before_unplug") if sub_type: error.context(context_msg % (sub_type, "before unplug"), logging.info) utils_test.run_virt_sub_test(test, params, env, sub_type) if devices: for device in devices[:pci_num]: # (lmr) I think here is the place where pci_info should go pci_info = [] error.context("Hot unplug device %s" % device, logging.info) pci_del(device) sub_type = params.get("sub_type_after_unplug") if sub_type: error.context(context_msg % (sub_type, "after hotunplug"), logging.info) utils_test.run_virt_sub_test(test, params, env, sub_type)
def run(test, params, env): """ Test hotplug of sr-iov devices. (Elements between [] are configurable test parameters) 1) Set up sr-iov test environment in host. 2) Start VM. 3) Disable the primary link(s) of guest. 4) PCI add one/multi sr-io deivce with (or without) repeat 5) Compare output of monitor command 'info pci'. 6) Compare output of guest command [reference_cmd]. 7) Verify whether pci_model is shown in [pci_find_cmd]. 8) Check whether the newly added PCI device works fine. 9) Delete the device, verify whether could remove the sr-iov device. 10) Re-enabling the primary link(s) of guest. :param test: QEMU test object. :param params: Dictionary with the test parameters. :param env: Dictionary with test environment. """ def check_interface(iface, nic_filter): cmd = "ifconfig %s" % str(iface) session = vm.wait_for_serial_login(timeout=timeout) status, output = session.cmd_status_output(cmd) if status: test.error("Guest command '%s' fail with output: %s." % (cmd, output)) if re.findall(nic_filter, output, re.MULTILINE | re.DOTALL): return True return False def get_active_network_device(session, nic_filter): devnames = [] cmd = "ifconfig -a" nic_reg = r"\w+(?=: flags)|\w+(?=\s*Link)" status, output = session.cmd_status_output(cmd) if status: test.error("Guest command '%s' fail with output: %s." % (cmd, output)) ifaces = re.findall(nic_reg, output) for iface in ifaces: if check_interface(str(iface), nic_filter): devnames.append(iface) return devnames def pci_add_iov(pci_num): pci_add_cmd = ("pci_add pci_addr=auto host host=%s,if=%s" % (pa_pci_ids[pci_num], pci_model)) if params.get("hotplug_params"): assign_param = params.get("hotplug_params").split() for param in assign_param: value = params.get(param) if value: pci_add_cmd += ",%s=%s" % (param, value) return pci_add(pci_add_cmd) def pci_add(pci_add_cmd): error_context.context("Adding pci device with command 'pci_add'") add_output = vm.monitor.send_args_cmd(pci_add_cmd, convert=False) pci_info.append(['', add_output]) if "OK domain" not in add_output: test.fail("Add PCI device failed. Monitor command is: %s, " "Output: %r" % (pci_add_cmd, add_output)) return vm.monitor.info("pci") def check_support_device(dev): if vm.monitor.protocol == 'qmp': devices_supported = vm.monitor.human_monitor_cmd("%s ?" % cmd_type) else: devices_supported = vm.monitor.send_args_cmd("%s ?" % cmd_type) # Check if the device is support in qemu is_support = utils_misc.find_substring(devices_supported, dev) if not is_support: test.error("%s doesn't support device: %s" % (cmd_type, dev)) def device_add_iov(pci_num): device_id = "%s" % pci_model + "-" + utils_misc.generate_random_id() pci_info.append([device_id]) driver = params.get("device_driver", "pci-assign") check_support_device(driver) pci_add_cmd = ("device_add id=%s,driver=%s,host=%s" % (pci_info[pci_num][0], driver, pa_pci_ids[pci_num])) if params.get("hotplug_params"): assign_param = params.get("hotplug_params").split() for param in assign_param: value = params.get(param) if value: pci_add_cmd += ",%s=%s" % (param, value) return device_add(pci_num, pci_add_cmd) def device_add(pci_num, pci_add_cmd): error_context.context("Adding pci device with command 'device_add'") if vm.monitor.protocol == 'qmp': add_output = vm.monitor.send_args_cmd(pci_add_cmd) else: add_output = vm.monitor.send_args_cmd(pci_add_cmd, convert=False) pci_info[pci_num].append(add_output) after_add = vm.monitor.info("pci") if pci_info[pci_num][0] not in str(after_add): logging.debug("Print info pci after add the block: %s" % after_add) test.fail("Add device failed. Monitor command is: %s" ". Output: %r" % (pci_add_cmd, add_output)) return after_add def clean_network_scripts(): logging.debug("Clean up network scripts in guest") session = vm.wait_for_serial_login(timeout=timeout) if "ubuntu" in vm.get_distro().lower(): iface_script = "/etc/network/interfaces" cmd = "cat %s.BACKUP" % iface_script if not session.cmd_status(cmd): cmd = "mv %s.BACKUP %s" % (iface_script, iface_script) status, output = session.cmd_status_output(cmd) if status: test.error("Failed to cleanup network script in guest: " "%s" % output) else: global iface_scripts for iface_script in iface_scripts: cmd = "rm -f %s" % iface_script status, output = session.cmd_status_output(cmd) if status: test.error("Failed to delete iface_script") iface_scripts.remove(iface_script) # Hot add a pci device def add_device(pci_num): global iface_scripts reference_cmd = params["reference_cmd"] info_pci_ref = vm.monitor.info("pci") session = vm.wait_for_serial_login(timeout=timeout) reference = session.cmd_output(reference_cmd) active_nics = get_active_network_device(session, nic_filter) logging.debug("Active nics before hotplug - %s", active_nics) # Stop the VM monitor and try hot adding SRIOV dev if params.get("vm_stop", "no") == "yes": logging.debug("stop the monitor of the VM before hotplug") vm.pause() try: # get function for adding device. add_function = local_functions["%s_iov" % cmd_type] except Exception: test.error("No function for adding sr-iov dev with '%s'" % cmd_type) after_add = None if add_function: # Do add pci device. after_add = add_function(pci_num) try: # Define a helper function to compare the output def _new_shown(): output = session.cmd_output(reference_cmd) return output != reference # Define a helper function to make sure new nic could get ip. def _check_ip(): post_nics = get_active_network_device(session, nic_filter) logging.debug("Active nics after hotplug - %s", post_nics) return (len(active_nics) <= len(post_nics) and active_nics != post_nics) # Define a helper function to catch PCI device string def _find_pci(): output = session.cmd_output("lspci -nn") if re.search(vf_filter, output, re.IGNORECASE): return True else: return False # Resume the VM if params.get("vm_resume", "no") == "yes": logging.debug("resuming the VM after hotplug") vm.resume() # Reboot the VM if params.get("vm_reboot", "no") == "yes": logging.debug("Rebooting the VM after hotplug") vm.reboot() session = vm.wait_for_serial_login(timeout=timeout) error_context.context("Start checking new added device") # Compare the output of 'info pci' if after_add == info_pci_ref: test.fail("No new PCI device shown after executing " "monitor command: 'info pci'") secs = int(params["wait_secs_for_hook_up"]) if not utils_misc.wait_for(_new_shown, test_timeout, secs, 3): test.fail("No new device shown in output of command " "executed inside the guest: %s" % reference_cmd) if not utils_misc.wait_for(_find_pci, test_timeout, 3, 3): test.fail("New add device not found in guest. " "Command was: lspci -nn") # Assign static IP to the hotplugged interface if params.get("assign_static_ip", "no") == "yes": cmd = "service networking restart" static_ip = next(ip_gen) net_mask = params.get("static_net_mask", "255.255.255.0") broadcast = params.get("static_broadcast", "10.10.10.255") pci_id = utils_misc.get_pci_id_using_filter(vf_filter, session) logging.debug("PCIs associated with %s - %s", vf_filter, ', '.join(map(str, pci_id))) for each_pci in pci_id: iface_name = utils_misc.get_interface_from_pci_id(each_pci, session) logging.debug("Interface associated with PCI %s - %s", each_pci, iface_name) mac = session.cmd_output("ethtool -P %s" % iface_name) mac = mac.split("Permanent address:")[-1].strip() logging.debug("mac address of %s: %s", iface_name, mac) # backup the network script for other distros if "ubuntu" not in vm.get_distro().lower(): cmd = "service network restart" iface_scripts.append(utils_net.get_network_cfg_file(iface_name)) if not check_interface(str(iface_name), nic_filter): utils_net.create_network_script(iface_name, mac, boot_proto="static", net_mask=net_mask, vm=vm, ip_addr=static_ip) status, output = session.cmd_status_output(cmd) if status: test.error("Failed to set static ip in guest: " "%s" % output) # Test the newly added device if not utils_misc.wait_for(_check_ip, 120, 3, 3): ifconfig = session.cmd_output("ifconfig -a") test.fail("New hotpluged device could not get ip " "after 120s in guest. guest ifconfig " "output: \n%s" % ifconfig) try: session.cmd(params["pci_test_cmd"] % (pci_num + 1)) except aexpect.ShellError as e: test.fail("Check device failed after PCI " "hotplug. Output: %r" % e.output) except Exception: pci_del(pci_num, ignore_failure=True) raise # Hot delete a pci device def pci_del(pci_num, ignore_failure=False): def _device_removed(): after_del = vm.monitor.info("pci") return after_del != before_del before_del = vm.monitor.info("pci") if cmd_type == "pci_add": slot_id = "0" + pci_info[pci_num][1].split(",")[2].split()[1] cmd = "pci_del pci_addr=%s" % slot_id vm.monitor.send_args_cmd(cmd, convert=False) elif cmd_type == "device_add": cmd = "device_del id=%s" % pci_info[pci_num][0] vm.monitor.send_args_cmd(cmd) if (not utils_misc.wait_for(_device_removed, test_timeout, 0, 1) and not ignore_failure): test.fail("Failed to hot remove PCI device: %s. " "Monitor command: %s" % (pci_model, cmd)) vm = env.get_vm(params["main_vm"]) vm.verify_alive() timeout = int(params.get("login_timeout", 360)) session = vm.wait_for_serial_login(timeout=timeout) test_timeout = int(params.get("test_timeout", 360)) # Test if it is nic or block pci_num_range = int(params.get("pci_num", 1)) rp_times = int(params.get("repeat_times", 1)) pci_model = params.get("pci_model", "pci-assign") vf_filter = params.get("vf_filter_re") generate_mac = params.get("generate_mac", "yes") nic_filter = params["nic_interface_filter"] devices = [] device_type = params.get("hotplug_device_type", "vf") for i in range(pci_num_range): device = {} device["type"] = device_type if generate_mac == "yes": device['mac'] = utils_net.generate_mac_address_simple() if params.get("device_name"): device["name"] = params.get("device_name") devices.append(device) device_driver = params.get("device_driver", "pci-assign") if vm.pci_assignable is None: vm.pci_assignable = test_setup.PciAssignable( driver=params.get("driver"), driver_option=params.get("driver_option"), host_set_flag=params.get("host_setup_flag"), kvm_params=params.get("kvm_default"), vf_filter_re=vf_filter, pf_filter_re=params.get("pf_filter_re"), device_driver=device_driver, pa_type=params.get("pci_assignable")) pa_pci_ids = vm.pci_assignable.request_devs(devices) # Modprobe the module if specified in config file module = params.get("modprobe_module") if module: error_context.context("modprobe the module %s" % module, logging.info) session.cmd("modprobe %s" % module) # Probe qemu to verify what is the supported syntax for PCI hotplug if vm.monitor.protocol == 'qmp': cmd_o = vm.monitor.info("commands") else: cmd_o = vm.monitor.send_args_cmd("help") cmd_type = utils_misc.find_substring(str(cmd_o), "device_add", "pci_add") if not cmd_o: test.error("Unknown version of qemu") local_functions = locals() if params.get("enable_set_link" "yes") == "yes": error_context.context("Disable the primary link(s) of guest", logging.info) for nic in vm.virtnet: vm.set_link(nic.device_id, up=False) try: for j in range(rp_times): # pci_info is a list of list. # each element 'i' has 4 members: # pci_info[i][0] == device id, only used for device_add # pci_info[i][1] == output of device add command pci_info = [] if params.get("assign_static_ip", "no") == "yes": ip_gen = utils_net.gen_ipv4_addr(exclude_ips=[]) # backup the network script file if it is ubuntu if "ubuntu" in vm.get_distro().lower(): session = vm.wait_for_serial_login(timeout=timeout) iface_script = "/etc/network/interfaces" cmd = "cat %s" % iface_script if not session.cmd_status(cmd): logging.debug("Backup network script in guest - %s", iface_script) cmd = "cp %s %s.BACKUP" % (iface_script, iface_script) status, output = session.cmd_status_output(cmd) if status: test.error("Failed to backup in guest: %s" % output) for pci_num in range(pci_num_range): msg = "Start hot-adding %sth pci device," % (pci_num + 1) msg += " repeat %d" % (j + 1) error_context.context(msg, logging.info) add_device(pci_num) sub_type = params.get("sub_type_after_plug") if sub_type: error_context.context("Running sub test '%s' after hotplug" % sub_type, logging.info) utils_test.run_virt_sub_test(test, params, env, sub_type) if "guest_suspend" == sub_type: # Hotpluged device have been released after guest suspend, # so do not need unpluged step. break for pci_num in range(pci_num_range): msg = "start hot-deleting %sth pci device," % (pci_num + 1) msg += " repeat %d" % (j + 1) error_context.context(msg, logging.info) pci_del(-(pci_num + 1)) # cleanup network script after hot deleting pci device clean_network_scripts() finally: # clean network scripts on error clean_network_scripts() if params.get("enable_set_link", "yes") == "yes": error_context.context("Re-enabling the primary link(s) of guest", logging.info) for nic in vm.virtnet: vm.set_link(nic.device_id, up=True) if session: session.close()