From 1f57f56bcb620b14024bddc230b0cd17da57843b Mon Sep 17 00:00:00 2001 From: Vaclav Hodina Date: Mon, 30 Jan 2023 17:44:25 +0100 Subject: [PATCH] PCIe, Slots in pcie-root numbered [1,31] This commit adds automation of tests where pcie-root-port controllers should have target with slot numbered from 1 to 31 (in hexadecimal numbers). VIRT-55414 --- .../controller/pcie_root_port_controller.cfg | 29 ++++- .../controller/pcie_root_port_controller.py | 102 ++++++++++++++---- 2 files changed, 106 insertions(+), 25 deletions(-) diff --git a/libvirt/tests/cfg/controller/pcie_root_port_controller.cfg b/libvirt/tests/cfg/controller/pcie_root_port_controller.cfg index 36f74924048..4fd480ac8c4 100644 --- a/libvirt/tests/cfg/controller/pcie_root_port_controller.cfg +++ b/libvirt/tests/cfg/controller/pcie_root_port_controller.cfg @@ -1,15 +1,29 @@ - pcie_root_port_controller: type = pcie_root_port_controller start_vm = "no" + controller_type = "pci" controller_model = "pcie-root-port" controller_target = '{"chassis":1,"port":"0x8"}' + slot_equal_after_define = "yes" variants: - positive_test: status_error = "no" variants: - controllers_different_chassis_same_port: second_controller_model = "pcie-root-port" - second_controller_target = "{'chassis':2,'port':'0x8'}" + second_controller_target = "{'chassis':3,'port':'0x8'}" + index_offset = 2 + - address_slot_too_low: + check_slot = "yes" + wipe_devices = "yes" + test_define_only = "yes" + controller_address = '{"type": "pci", "domain": "0x0000", "bus": "0x00", "slot": "0x00", "function":"0x0"}' + slot_equal_after_define = "no" + - address_slot_min_value: + check_slot = "yes" + wipe_devices = "yes" + test_define_only = "yes" + controller_address = '{"type": "pci", "domain": "0x0000", "bus": "0x00", "slot": "0x03", "function":"0x0"}' - negative_test: status_error = "yes" variants: @@ -22,25 +36,27 @@ test_define_only = "yes" interface_slot_type = "hex" interface_slot = 1 - minimal_interface_dict = '{"source": {"network": "default"}}' + minimal_interface_dict = '{"source": {"network": "default"}, "model": "virtio"}' failure_message = "Invalid PCI address .* slot must be <= 0" - controllers_same_chassis_same_port: second_controller_model = "pcie-root-port" second_controller_target = "{'chassis':1,'port':'0x8'}" + index_offset = 2 - controllers_same_chassis_different_port: second_controller_model = "pcie-root-port" second_controller_target = "{'chassis':1,'port':'0x4'}" + index_offset = 2 - model_name_invalid: test_define_only = "yes" controller_model = "dmi-to-pci-bridge" - index_equals_address_bus: test_define_only = "yes" - controller_address = '{"type": "pci", "domain": "0x0000", "bus": "0x01", "slot": "0x1", "function":"0x0"}' + controller_address = '{"type": "pci", "domain": "0x0000", "slot": "0x1", "function":"0x0"}' failure_message = ".*The device at PCI address .* cannot be plugged into the PCI controller with index='.*'. It requires a controller that accepts a pcie\-root\-port.*" - index_less_than_address_bus: bus_offset = 1 test_define_only = "yes" - controller_address = '{"type": "pci", "domain": "0x0000", "bus": "0x02", "slot": "0x1", "function":"0x0"}' + controller_address = '{"type": "pci", "domain": "0x0000", "slot": "0x1", "function":"0x0"}' failure_message = ".*a PCI slot is needed to connect a PCI controller model='pcie\-root\-port', but none is available, and it cannot be automatically added.*" - controller_index_zero: test_define_only = "yes" @@ -68,3 +84,8 @@ test_define_only = "yes" controller_target = '{"chassis":"a","port":"0x8"}' failure_message = "XML error: Invalid value for attribute 'chassis' in element 'target': 'a'. Expected integer value" + - address_slot_too_high: + wipe_devices = "yes" + test_define_only = "yes" + controller_address = '{"type": "pci", "domain": "0x0000", "bus": "0x02", "slot": "0x20", "function":"0x0"}' + failure_message = "Invalid PCI address slot='0x20', must be <= 0x1F" diff --git a/libvirt/tests/src/controller/pcie_root_port_controller.py b/libvirt/tests/src/controller/pcie_root_port_controller.py index aacda0c866b..4cbad8f4310 100644 --- a/libvirt/tests/src/controller/pcie_root_port_controller.py +++ b/libvirt/tests/src/controller/pcie_root_port_controller.py @@ -17,31 +17,29 @@ def setup_test(params): :param params: Test parameters object """ + controller_type = params.get("controller_type") controller_model = params.get("controller_model") controller_target = ast.literal_eval(params.get("controller_target")) - controller_index = params.get("controller_index", 0) second_controller_model = params.get("second_controller_model") second_controller_target = ast.literal_eval( params.get("second_controller_target", "{}")) + index_offset = int(params.get("index_offset", 2)) vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(params.get("main_vm", "avocado-vt-vm1")) test_define_only = params.get("test_define_only") == "yes" - vmxml.remove_all_device_by_type("controller") - - index = 0 - contr_dict = {"type": "pci", "model": "pcie-root", "index": index} - libvirt_vmxml.modify_vm_device(vmxml, "controller", contr_dict, index) + wipe_pcie_root_ports(vmxml) if test_define_only: return - index += 1 - contr_dict = create_controller_dict(controller_model, controller_target, index) + index = 1 + contr_dict = create_controller_dict(controller_type, controller_model, + controller_target, index) libvirt_vmxml.modify_vm_device(vmxml, "controller", contr_dict, index) if second_controller_model and second_controller_target: - index += 1 - contr_dict = create_controller_dict(second_controller_model, + index += index_offset + contr_dict = create_controller_dict(controller_type, second_controller_model, second_controller_target, index) libvirt_vmxml.modify_vm_device(vmxml, "controller", contr_dict, index) @@ -59,12 +57,12 @@ def execute_test(vm, test, params): test_define_only = params.get("test_define_only") == "yes" if test_define_only: vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm.name) - check_define_vm(vmxml, params) + check_define_vm(vmxml, test, params) else: check_vm_start(vm, params) -def create_controller_dict(model, target, index, address=None): +def create_controller_dict(controller_type, model, target, index, address=None): """ Creates a dictionary for PCI controller. @@ -74,26 +72,30 @@ def create_controller_dict(model, target, index, address=None): :param address: Dict, optional, device address example: {'attrs': {'bus': 0x01}} :returns Built in dictionary, prepared to be added to VM XML """ - contr_dict = {'type': 'pci', - 'model': model, - "index": index, - 'target': target} + contr_dict = {'type': controller_type, + "index": index} + if target: + contr_dict.update({"target": target}) + if model: + contr_dict.update({"model": model}) if address: contr_dict.update({"address": address}) LOG.debug("Created controller %s", contr_dict) return contr_dict -def check_define_vm(vmxml, params): +def check_define_vm(vmxml, test, params): """ Alternate function for checking and finishing the test. Checks only if VM define action was successful instead of VM start. :param vmxml: VM XML object + :param test: Avocado test object :param params: Test parameters object """ LOG.info("Checking VM in define only mode.") model = params.get("controller_model") + controller_type = params.get("controller_type") target = params.get("controller_target") address = ast.literal_eval(params.get("controller_address", "{}")) bus_offset = int(params.get("bus_offset", 0)) @@ -102,19 +104,28 @@ def check_define_vm(vmxml, params): minimal_interface_dict = ast.literal_eval(params.get("minimal_interface_dict", "{}")) interface_slot = params.get("interface_slot", 0) interface_slot_type = params.get("interface_slot_type", "int") + check_slot = params.get("check_slot", "no") == "yes" + wipe_devices = params.get("wipe_devices", "no") == "yes" + if wipe_devices: + wipe_pcie_root_ports(vmxml) if interface_slot_type == "hex": interface_slot = hex(int(interface_slot)) index = get_controller_index(vmxml, params) - if address: + if address and "bus" not in address: address["bus"] = hex(index + bus_offset) - contr_dict = {'controller_type': 'pci', - 'controller_model': model, + slot_equal_after_define = params.get("slot_equal_after_define", "yes") == "yes" + contr_dict = {'controller_type': controller_type, "controller_index": index, 'controller_target': target, "controller_addr": str(address)} + if model: + contr_dict.update({"controller_model": model}) contr_object = libvirt.create_controller_xml(contr_dict) + if index == 0: + contr_object.index = 0 # Workaround for non-working avocado-vt vmxml.add_device(contr_object) if minimal_interface_dict: + index += 1 interface_dict = customize_interface_dict(minimal_interface_dict, interface_bus=hex(index), interface_slot=interface_slot) @@ -125,14 +136,50 @@ def check_define_vm(vmxml, params): libvirt.check_result(cmd_result, [failure_message]) else: libvirt.check_exit_status(cmd_result, status_error) + if check_slot: + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml( + params.get("main_vm", "avocado-vt-vm1")) + expected_value = address["slot"] + if not check_slot_in_controller(vmxml, index, expected_value, + slot_equal_after_define): + test.fail("Controller slot doesn't have the" + "expected value of %s.", expected_value) + + +def check_slot_in_controller(vmxml, device_index, expected_value, expected_equal=True): + """ + This function checks if address_slot value in a controller in VM XML equals + expected value or not. + + :param vmxml: VM XML object to check + :param device_index: Int, device index to check + :param expected_value: The value that is used in the check + :param expected_equal: Bool, true if expected_value should be equal to + value in xml + :returns Bool, based on the value comparison + """ + controllers = vmxml.get_devices("controller") + device = controllers[device_index] + if expected_equal: + return device.address.attrs["slot"] == expected_value + return device.address.attrs["slot"] != expected_value def get_controller_index(vmxml, params): + """ + Function that finds index for a PCIe controller and returns it + + :param vmxml: VM XML object to check + :param params: Test parameters object + :returns Index number + """ # We want to default to None so we can differentiate between None and 0 controller_index = params.get("controller_index", None) model = params.get("controller_model") - if controller_index is not None: + if controller_index == "xxx": return controller_index + if controller_index is not None: + return int(controller_index) max_indexes = libvirt_pcicontr.get_max_contr_indexes(vmxml, 'pci', model, 1) if max_indexes: return max_indexes[0] + 1 @@ -190,6 +237,19 @@ def check_vm_start(vm, params, **virsh_options): libvirt.check_exit_status(cmd_result, status_error) +def wipe_pcie_root_ports(vmxml): + """ + Function that removes all pcie-root-port devices from VM XML + + :param vmxml: VM XML object to check + """ + + vmxml.remove_all_device_by_type("controller") + index = 0 + contr_dict = {"type": "pci", "model": "pcie-root", "index": index} + libvirt_vmxml.modify_vm_device(vmxml, "controller", contr_dict, index) + + def run(test, params, env): """ Function executed by avocado. Similar to "main" function of a module.