1import re 2from autotest_lib.client.common_lib import error 3from autotest_lib.client.virt import virt_utils, virt_vm, aexpect 4 5 6def run_pci_hotplug(test, params, env): 7 """ 8 Test hotplug of PCI devices. 9 10 (Elements between [] are configurable test parameters) 11 1) PCI add a deivce (NIC / block) 12 2) Compare output of monitor command 'info pci'. 13 3) Compare output of guest command [reference_cmd]. 14 4) Verify whether pci_model is shown in [pci_find_cmd]. 15 5) Check whether the newly added PCI device works fine. 16 6) PCI delete the device, verify whether could remove the PCI device. 17 18 @param test: KVM test object. 19 @param params: Dictionary with the test parameters. 20 @param env: Dictionary with test environment. 21 """ 22 vm = env.get_vm(params["main_vm"]) 23 vm.verify_alive() 24 timeout = int(params.get("login_timeout", 360)) 25 session = vm.wait_for_login(timeout=timeout) 26 27 # Modprobe the module if specified in config file 28 module = params.get("modprobe_module") 29 if module: 30 session.cmd("modprobe %s" % module) 31 32 # Get output of command 'info pci' as reference 33 info_pci_ref = vm.monitor.info("pci") 34 35 # Get output of command as reference 36 reference = session.cmd_output(params.get("reference_cmd")) 37 38 tested_model = params.get("pci_model") 39 test_type = params.get("pci_type") 40 image_format = params.get("image_format_stg") 41 42 # Probe qemu to verify what is the supported syntax for PCI hotplug 43 cmd_output = vm.monitor.cmd("?") 44 if len(re.findall("\ndevice_add", cmd_output)) > 0: 45 cmd_type = "device_add" 46 elif len(re.findall("\npci_add", cmd_output)) > 0: 47 cmd_type = "pci_add" 48 else: 49 raise error.TestError("Unknow version of qemu") 50 51 # Determine syntax of drive hotplug 52 # __com.redhat_drive_add == qemu-kvm-0.12 on RHEL 6 53 if len(re.findall("\n__com.redhat_drive_add", cmd_output)) > 0: 54 drive_cmd_type = "__com.redhat_drive_add" 55 # drive_add == qemu-kvm-0.13 onwards 56 elif len(re.findall("\ndrive_add", cmd_output)) > 0: 57 drive_cmd_type = "drive_add" 58 else: 59 raise error.TestError("Unknow version of qemu") 60 61 # Probe qemu for a list of supported devices 62 devices_support = vm.monitor.cmd("%s ?" % cmd_type) 63 64 if cmd_type == "pci_add": 65 if test_type == "nic": 66 pci_add_cmd = "pci_add pci_addr=auto nic model=%s" % tested_model 67 elif test_type == "block": 68 image_params = params.object_params("stg") 69 image_filename = virt_vm.get_image_filename(image_params, 70 test.bindir) 71 pci_add_cmd = ("pci_add pci_addr=auto storage file=%s,if=%s" % 72 (image_filename, tested_model)) 73 # Execute pci_add (should be replaced by a proper monitor method call) 74 add_output = vm.monitor.cmd(pci_add_cmd) 75 if not "OK domain" in add_output: 76 raise error.TestFail("Add PCI device failed. " 77 "Monitor command is: %s, Output: %r" % 78 (pci_add_cmd, add_output)) 79 after_add = vm.monitor.info("pci") 80 81 elif cmd_type == "device_add": 82 driver_id = test_type + "-" + virt_utils.generate_random_id() 83 device_id = test_type + "-" + virt_utils.generate_random_id() 84 if test_type == "nic": 85 if tested_model == "virtio": 86 tested_model = "virtio-net-pci" 87 pci_add_cmd = "device_add id=%s,driver=%s" % (device_id, 88 tested_model) 89 90 elif test_type == "block": 91 image_params = params.object_params("stg") 92 image_filename = virt_vm.get_image_filename(image_params, 93 test.bindir) 94 controller_model = None 95 if tested_model == "virtio": 96 tested_model = "virtio-blk-pci" 97 98 if tested_model == "scsi": 99 tested_model = "scsi-disk" 100 controller_model = "lsi53c895a" 101 if len(re.findall(controller_model, devices_support)) == 0: 102 raise error.TestError("scsi controller device (%s) not " 103 "supported by qemu" % 104 controller_model) 105 106 if controller_model is not None: 107 controller_id = "controller-" + device_id 108 controller_add_cmd = ("device_add %s,id=%s" % 109 (controller_model, controller_id)) 110 vm.monitor.cmd(controller_add_cmd) 111 112 if drive_cmd_type == "drive_add": 113 driver_add_cmd = ("drive_add auto " 114 "file=%s,if=none,id=%s,format=%s" % 115 (image_filename, driver_id, image_format)) 116 elif drive_cmd_type == "__com.redhat_drive_add": 117 driver_add_cmd = ("__com.redhat_drive_add " 118 "file=%s,format=%s,id=%s" % 119 (image_filename, image_format, driver_id)) 120 121 pci_add_cmd = ("device_add id=%s,driver=%s,drive=%s" % 122 (device_id, tested_model, driver_id)) 123 vm.monitor.cmd(driver_add_cmd) 124 125 # Check if the device is support in qemu 126 if len(re.findall(tested_model, devices_support)) > 0: 127 add_output = vm.monitor.cmd(pci_add_cmd) 128 else: 129 raise error.TestError("%s doesn't support device: %s" % 130 (cmd_type, tested_model)) 131 after_add = vm.monitor.info("pci") 132 133 if not device_id in after_add: 134 raise error.TestFail("Add device failed. Monitor command is: %s" 135 ". Output: %r" % (pci_add_cmd, add_output)) 136 137 # Define a helper function to delete the device 138 def pci_del(ignore_failure=False): 139 if cmd_type == "pci_add": 140 result_domain, bus, slot, function = add_output.split(',') 141 domain = int(result_domain.split()[2]) 142 bus = int(bus.split()[1]) 143 slot = int(slot.split()[1]) 144 pci_addr = "%x:%x:%x" % (domain, bus, slot) 145 cmd = "pci_del pci_addr=%s" % pci_addr 146 elif cmd_type == "device_add": 147 cmd = "device_del %s" % device_id 148 # This should be replaced by a proper monitor method call 149 vm.monitor.cmd(cmd) 150 151 def device_removed(): 152 after_del = vm.monitor.info("pci") 153 return after_del != after_add 154 155 if (not virt_utils.wait_for(device_removed, 10, 0, 1) 156 and not ignore_failure): 157 raise error.TestFail("Failed to hot remove PCI device: %s. " 158 "Monitor command: %s" % 159 (tested_model, cmd)) 160 161 try: 162 # Compare the output of 'info pci' 163 if after_add == info_pci_ref: 164 raise error.TestFail("No new PCI device shown after executing " 165 "monitor command: 'info pci'") 166 167 # Define a helper function to compare the output 168 def new_shown(): 169 o = session.cmd_output(params.get("reference_cmd")) 170 return o != reference 171 172 secs = int(params.get("wait_secs_for_hook_up")) 173 if not virt_utils.wait_for(new_shown, 30, secs, 3): 174 raise error.TestFail("No new device shown in output of command " 175 "executed inside the guest: %s" % 176 params.get("reference_cmd")) 177 178 # Define a helper function to catch PCI device string 179 def find_pci(): 180 o = session.cmd_output(params.get("find_pci_cmd")) 181 return params.get("match_string") in o 182 183 if not virt_utils.wait_for(find_pci, 30, 3, 3): 184 raise error.TestFail("PCI %s %s device not found in guest. " 185 "Command was: %s" % 186 (tested_model, test_type, 187 params.get("find_pci_cmd"))) 188 189 # Test the newly added device 190 try: 191 session.cmd(params.get("pci_test_cmd")) 192 except aexpect.ShellError, e: 193 raise error.TestFail("Check for %s device failed after PCI " 194 "hotplug. Output: %r" % (test_type, e.output)) 195 196 session.close() 197 198 except: 199 pci_del(ignore_failure=True) 200 raise 201 202 else: 203 pci_del() 204