Esempio n. 1
0
 def setup_hostdev():
     """
     Setup test environment for hostdev
     """
     pf_pci = utils_sriov.get_pf_pci()
     sriov_base.setup_vf(pf_pci, params)
     vf_pci = utils_misc.wait_for(lambda: utils_sriov.get_vf_pci_id(pf_pci),
                                  30, 5)
     pci_to_addr = utils_sriov.pci_to_addr(vf_pci)
     if params.get('iface_dict'):
         params.update({'iface_dict': params.get('iface_dict') % pci_to_addr})
     elif params.get('hostdev_dict'):
         del pci_to_addr['type']
         params.update(
             {'hostdev_dict': params.get('hostdev_dict') % pci_to_addr})
Esempio n. 2
0
def run(test, params, env):
    """
    Test interfaces attached from network
    """
    def test_at_dt():
        """
        Test attach-detach interfaces
        """
        if not pf_status:
            logging.info("Set pf state to down.")
            pf_iface_obj = utils_net.Interface(pf_name)
            pf_iface_obj.down()

        logging.info("Define network - %s.", params.get("net_name"))
        create_network(params)

        logging.debug("Remove VM's interface devices.")
        libvirt_vmxml.remove_vm_devices_by_type(vm, 'interface')
        vm.start()
        vm_session = vm.wait_for_serial_login(timeout=240)

        logging.info("Hotplug an interface to VM.")
        iface_dict = {
            "model": "virtio",
            "source": {
                'network': params.get("net_name")
            }
        }
        iface = create_iface(iface_dict)
        res = virsh.attach_device(vm_name, iface.xml, debug=True)
        libvirt.check_exit_status(res, status_error)
        if not pf_status:
            logging.info("Set pf state to up then check again.")
            pf_iface_obj.up()
            virsh.attach_device(vm_name,
                                iface.xml,
                                debug=True,
                                ignore_status=False)
        libvirt_vmxml.check_guest_xml(vm.name, params["net_name"])
        sriov_base.check_vm_network_accessed(vm_session)

    def test_connection():
        """
        Test network connections

        1. Create a network
        2. Attach the interfaces and check network connections
        3. Check the network connections after detaching ifaces, restarting
            libvirtd and destroying the VM
        """
        vf_no = int(params.get("vf_no", "4"))
        net_name = params.get("net_name")
        iface_type = params.get("iface_type")

        logging.info("Define network - %s.", net_name)
        create_network(params)
        libvirt_vmxml.remove_vm_devices_by_type(vm, 'interface')
        libvirt_pcicontr.reset_pci_num(vm_name)
        vm.start()
        vm.wait_for_serial_login(timeout=240)

        logging.info("Attach 4 interfaces to the guest.")
        opts = ' '.join(
            ["network", net_name,
             params.get('attach_extra_opts', "")])
        for i in range(vf_no):
            virsh.attach_interface(vm_name,
                                   option=opts,
                                   debug=True,
                                   ignore_status=False)
            libvirt_network.check_network_connection(net_name, i + 1)

        logging.info("Try to attach one more interface.")
        res = virsh.attach_interface(vm_name, option=opts, debug=True)
        libvirt.check_exit_status(res, True)

        logging.info("Detach an interface.")
        vm_ifaces = [
            iface for iface in vm_xml.VMXML.new_from_dumpxml(
                vm_name).devices.by_device_tag("interface")
        ]
        mac_addr = vm_ifaces[0].get_mac_address()
        opts = ' '.join([iface_type, "--mac %s" % mac_addr])
        virsh.detach_interface(vm_name,
                               option=opts,
                               debug=True,
                               wait_for_event=True,
                               ignore_status=False)
        libvirt_network.check_network_connection(net_name, vf_no - 1)

        logging.info(
            "Restart libvirtd service and check the network connection.")
        utils_libvirtd.Libvirtd().restart()
        libvirt_network.check_network_connection(net_name, vf_no - 1)
        logging.info("Destroy the VM and check the network connection.")
        vm.destroy(gracefully=False)
        libvirt_network.check_network_connection(net_name, 0)

    test_case = params.get("test_case", "")
    run_test = eval("test_%s" % test_case)
    status_error = "yes" == params.get("status_error", "no")

    vm_name = params.get("main_vm", "avocado-vt-vm1")
    vm = env.get_vm(vm_name)
    pf_pci = utils_sriov.get_pf_pci()
    if not pf_pci:
        test.cancel("NO available pf found.")
    sriov_base.setup_vf(pf_pci, params)

    vf_pci = utils_sriov.get_vf_pci_id(pf_pci)
    params['vf_iface'] = utils_sriov.get_iface_name(vf_pci)
    pf_status = "active" == params.get("pf_status", "active")
    pf_name = utils_sriov.get_pf_info_by_pci(pf_pci).get('iface')
    params['pf_name'] = pf_name
    vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name)
    orig_config_xml = vmxml.copy()

    try:
        run_test()

    finally:
        logging.info("Recover test enviroment.")
        if not pf_status:
            pf_iface_obj = utils_net.Interface(pf_name)
            pf_iface_obj.up()
        sriov_base.recover_vf(pf_pci, params)
        if vm.is_alive():
            vm.destroy(gracefully=False)
        orig_config_xml.sync()
        libvirt_network.create_or_del_network(
            {"net_name": params.get("net_name")}, True)
Esempio n. 3
0
def run(test, params, env):
    """
    Nodedev related test.
    """
    def check_driver_from_xml(dev_name, driver_type='vfio-pci',
                              status_error=False):
        """
        Check driver of a device from nodedev XML

        :param dev_name: Name of a device(eg. pci_0000_05_00_1)
        :param driver_type: Type of a device
        :param status_error: Whether the driver should be same with 'driver_type'
        :raise: TestFail if not match
        """
        dev_xml = nodedev_xml.NodedevXML.new_from_dumpxml(dev_name)
        if status_error == (dev_xml.driver_name != driver_type):
            test.fail("The driver %s should%s be '%s'."
                      % (dev_xml.driver_name, ' not' if status_error else '',
                         driver_type))

    def nodedev_test(dev_name, status_error=False, no_reset=False):
        """
        Execute virsh nodedev-* commands

        :param dev_name: Name of a device(eg. pci_0000_05_00_1)
        :param status_error: Whether the command should be failed
        :param no_reset: Whether reset nodedev
        """
        if not no_reset:
            res = virsh.nodedev_reset(dev_name, debug=True)
            libvirt.check_exit_status(res, status_error)
        res = virsh.nodedev_detach(dev_name, debug=True)
        libvirt.check_exit_status(res, status_error)
        res = virsh.nodedev_reattach(dev_name, debug=True)
        libvirt.check_exit_status(res, status_error)

    def check_hostdev_device(vm_name):
        """
        Check hostdev device from VM's XML

        :param vm_name: VM's name
        :raise: TestFail if the hoodev device is not found
        """
        vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name)
        check_hostdev = vm_xml.VMXML.new_from_dumpxml(vm_name)\
            .devices.by_device_tag('hostdev')
        if not check_hostdev:
            test.fail("The hostdev device does not exist: %s."
                      % check_hostdev)

    def check_hostdev_iface(vm_name):
        """
        Check hostdev interface in VM

        :param vm_name: Name of VM
        :raise: TestFail if not found
        """
        vm_ifaces = [iface.get_type_name() for iface in vm_xml.VMXML.
                     new_from_dumpxml(vm_name).devices.
                     by_device_tag("interface")]
        if 'hostdev' not in vm_ifaces:
            test.fail("hostdev interface does not exist: %s." % vm_ifaces)

    def compare_vf_mac(pf_name, exp_vf_mac):
        """
        Compare the current vf's mac address with exp_vf_mac

        :param pf_name: The PF's
        :param exp_vf_mac: The expected vf's mac address
        :raise: TestFail if not match
        """
        logging.debug("VF's mac should be %s.", exp_vf_mac)
        vf_mac_act = utils_sriov.get_vf_mac(pf_name, is_admin=False)
        if exp_vf_mac != vf_mac_act:
            test.fail("MAC address changed from '%s' to '%s' after reattaching "
                      "vf." % (exp_vf_mac, vf_mac_act))

    def test_pf():
        """
        Reattach/reset/detach a pci device when it is used in guest

        1) Detach/Reset/reattach the device
        2) Add the device to VM
        3) Start the VM
        4) Check driver of the device
        5) Detach/Reset/reattach the device again
        """
        dev_name = utils_sriov.get_device_name(pf_pci)
        check_driver_from_xml(dev_name)
        nodedev_test(dev_name)
        add_hostdev_device(vm_name, pf_pci)
        vm.start()
        check_hostdev_device(vm_name)
        check_driver_from_xml(dev_name, status_error=True)
        nodedev_test(dev_name, True)

    def test_vf():
        """
        Detach/Reattach a vf when it is used in guest

        1) Detach/reattach the device
        2) Add the device to VM
        3) Start the VM
        4) Check driver of the device
        5) Detach/reattach the device again
        """
        logging.info("Initialize the vfs.")
        sriov_base.setup_vf(pf_pci, params)
        vf_pci = utils_sriov.get_vf_pci_id(pf_pci)
        pf_name = utils_sriov.get_pf_info_by_pci(pf_pci).get('iface')
        vf_mac = utils_sriov.get_vf_mac(pf_name, is_admin=False)
        logging.debug("VF's mac: %s.", vf_mac)

        logging.info("Check the vf's driver, it should not be vfio-pci.")
        dev_name = utils_sriov.get_device_name(vf_pci)
        check_driver_from_xml(dev_name)

        logging.info("Detach and reattach the device and check vf's mac.")
        nodedev_test(dev_name, no_reset=True)
        compare_vf_mac(pf_name, vf_mac)

        logging.info("Cold-plug the device into the VM.")
        add_hostdev_iface(vm, vf_pci)
        vm.start()
        check_hostdev_iface(vm.name)

        logging.info("Check the device info. It should be vfio-pci.")
        check_driver_from_xml(dev_name, status_error=True)
        nodedev_test(dev_name, True)

        logging.info("Destroy the vm, and check the vf's mac is recovered.")
        vm.destroy(gracefully=False)
        compare_vf_mac(pf_name, vf_mac)

    test_case = params.get("test_case", "")
    run_test = eval("test_%s" % test_case)

    vm_name = params.get("main_vm", "avocado-vt-vm1")
    vm = env.get_vm(vm_name)

    pf_pci = utils_sriov.get_pf_pci()
    if not pf_pci:
        test.cancel("NO available pf found.")

    vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name)
    orig_config_xml = vmxml.copy()

    try:
        run_test()

    finally:
        logging.info("Recover test environment.")
        if vm.is_alive():
            vm.destroy(gracefully=False)
        orig_config_xml.sync()
        sriov_base.recover_vf(pf_pci, params)
def run(test, params, env):
    """
    SR-IOV: managed related test.
    """
    def start_vm(vm, test_login=False, destroy_vm=False):
        """
        Start up VM

        :param vm: The vm object
        :param test_login: Whether to login VM
        :param destroy_vm: Whether to destroy VM
        """
        if vm.is_alive():
            vm.destroy()
        vm.start()
        if test_login:
            vm.wait_for_serial_login(timeout=180).close()
        if destroy_vm:
            vm.destroy()

    def create_vf_pool():
        """
        Create VF pool
        """
        net_hostdev_dict = {
            "net_name": params.get("net_name"),
            "net_forward": params.get("net_forward"),
            "vf_list_attrs": "[%s]" % utils_sriov.pci_to_addr(vf_pci)
        }
        libvirt_network.create_or_del_network(net_hostdev_dict)

    def check_vm_iface_managed(vm_name, iface_dict):
        """
        Check 'managed' in VM's iface

        :param vm_name: Name of VM
        :param iface_dict: The parameters dict
        :raise: TestFail if not match
        """
        vm_iface_managed = [
            iface.get("managed") for iface in vm_xml.VMXML.new_from_dumpxml(
                vm_name).devices.by_device_tag("interface")
        ][0]
        expr_managed = "yes" if iface_dict.get("managed",
                                               "") == "yes" else None
        if vm_iface_managed != expr_managed:
            test.fail("Unable to get the expected managed! Actual: %s, "
                      "Expected: %s." % (vm_iface_managed, expr_managed))

    def test_networks():
        """
        Start vm with VF from VF Pool with "managed=no" or default setting

        1) Create VF pool
        2) Prepare device xml and hot-plug to the guest
        3) Detach the device from host
        4) Check the driver of device
        5) Start VM
        6) Destroy vm then check the driver
        7) Reattach the device to the host and check the driver
        """
        create_vf_pool()
        libvirt_vfio.check_vfio_pci(vf_pci, status_error=True)
        iface_dict = {
            "type": "network",
            "source": "{'network': '%s'}" % params.get("net_name")
        }
        libvirt.modify_vm_iface(vm.name, "update_iface", iface_dict)
        res = virsh.start(vm.name, debug=True)
        libvirt.check_exit_status(res, True)

        virsh.nodedev_detach(dev_name, debug=True, ignore_status=False)
        libvirt_vfio.check_vfio_pci(vf_pci)
        start_vm(vm, True, True)
        libvirt_vfio.check_vfio_pci(vf_pci)
        virsh.nodedev_reattach(dev_name, debug=True, ignore_status=False)
        libvirt_vfio.check_vfio_pci(vf_pci, status_error=True)

    def test_device_hotplug():
        """
        Hotplug/unplug VF with managed='no'

        1) Prepare a running guest
        2) Check the driver of vf on host
        3) Prepare a xml with "managed=no"and attach to guest
        4) Detach the device from host
        5) Check the driver of vf on host
        6) Attach the device to guest
        7) Check the interface of the guest
        8) Detach the device from guest and check the driver
        9) Reattach the device to the host and check the driver
        """
        libvirt_vmxml.remove_vm_devices_by_type(vm, 'interface')
        start_vm(vm)
        libvirt_vfio.check_vfio_pci(vf_pci, status_error=True)
        mac_addr = utils_net.generate_mac_address_simple()
        iface_dict = eval(
            params.get('iface_dict', '{"hostdev_addr": "%s"}') %
            utils_sriov.pci_to_addr(vf_pci))
        iface = interface.Interface("hostdev")
        iface.xml = libvirt.modify_vm_iface(vm.name, "get_xml", iface_dict)
        res = virsh.attach_device(vm_name, iface.xml, debug=True)
        libvirt.check_exit_status(res, True)
        virsh.nodedev_detach(dev_name, debug=True, ignore_status=False)
        libvirt_vfio.check_vfio_pci(vf_pci)
        virsh.attach_device(vm_name,
                            iface.xml,
                            debug=True,
                            ignore_status=False)

        check_vm_iface_managed(vm_name, iface_dict)
        vm.wait_for_serial_login().close()
        virsh.detach_device(vm_name,
                            iface.xml,
                            wait_remove_event=True,
                            debug=True,
                            ignore_status=False)
        libvirt_vfio.check_vfio_pci(vf_pci)
        virsh.nodedev_reattach(dev_name, debug=True, ignore_status=False)
        libvirt_vfio.check_vfio_pci(vf_pci, status_error=True)

    test_case = params.get("test_case", "")
    run_test = eval("test_%s" % test_case)

    vm_name = params.get("main_vm", "avocado-vt-vm1")
    vm = env.get_vm(vm_name)
    pf_pci = utils_sriov.get_pf_pci()
    if not pf_pci:
        test.cancel("NO available pf found.")
    default_vf = sriov_base.setup_vf(pf_pci, params)

    vf_pci = utils_sriov.get_vf_pci_id(pf_pci)
    dev_name = utils_sriov.get_device_name(vf_pci)
    vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name)
    orig_config_xml = vmxml.copy()

    try:
        run_test()

    finally:
        logging.info("Recover test enviroment.")
        sriov_base.recover_vf(pf_pci, params, default_vf)
        if vm.is_alive():
            vm.destroy(gracefully=False)
        orig_config_xml.sync()
        libvirt_network.create_or_del_network(
            {"net_name": params.get("net_name")}, True)
        virsh.nodedev_reattach(dev_name, debug=True)
Esempio n. 5
0
def run(test, params, env):
    """
    Sriov basic test:

    1.create max vfs;
    2.Check the nodedev info;
    3.Start a guest with vf;
    4.Reboot a guest with vf;
    5.suspend/resume a guest with vf
    """
    def create_address_dict(pci_id):
        """
            Use pci_xxxx_xx_xx_x to create address dict.
        """
        device_domain = pci_id.split(':')[0]
        device_domain = "0x%s" % device_domain
        device_bus = pci_id.split(':')[1]
        device_bus = "0x%s" % device_bus
        device_slot = pci_id.split(':')[-1].split('.')[0]
        device_slot = "0x%s" % device_slot
        device_function = pci_id.split('.')[-1]
        device_function = "0x%s" % device_function
        attrs = {
            'type': 'pci',
            'domain': device_domain,
            'slot': device_slot,
            'bus': device_bus,
            'function': device_function
        }
        return attrs

    def addr_to_pci(addr):
        """
            Convert address dict to pci address: xxxxx:xx.x.
        """
        pci_domain = re.findall(r"0x(.+)", addr['domain'])[0]
        pci_bus = re.findall(r"0x(.+)", addr['bus'])[0]
        pci_slot = re.findall(r"0x(.+)", addr['slot'])[0]
        pci_function = re.findall(r"0x(.+)", addr['function'])[0]
        pci_addr = pci_domain + ":" + pci_bus + ":" + pci_slot + "." + pci_function
        return pci_addr

    def create_hostdev_interface(pci_id, managed, model):
        """
            Create hostdev type interface xml.
        """
        attrs = create_address_dict(pci_id)
        new_iface = Interface('hostdev')
        new_iface.managed = managed
        if model != "":
            new_iface.model = model
        new_iface.mac_address = utils_net.generate_mac_address_simple()
        new_iface.hostdev_address = new_iface.new_iface_address(
            **{"attrs": attrs})
        chars = string.ascii_letters + string.digits + '-_'
        alias_name = 'ua-' + ''.join(
            random.choice(chars) for _ in list(range(64)))
        new_iface.alias = {'name': alias_name}
        if vlan_id:
            new_iface.vlan = new_iface.new_vlan(**vlan_id)
        return new_iface

    def create_vfs(vf_num):
        """
            Create max vfs.
        """
        net_device = []
        net_name = []
        # cleanup env and create vfs
        cmd = "echo 0 > %s/sriov_numvfs" % pci_address
        if driver == "mlx4_core":
            cmd = "modprobe -r mlx4_en ; modprobe -r mlx4_ib ; modprobe -r mlx4_core"
        process.run(cmd, shell=True)
        pci_list = virsh.nodedev_list(cap='pci').stdout.strip().splitlines()
        net_list = virsh.nodedev_list(cap='net').stdout.strip().splitlines()
        pci_list_before = set(pci_list)
        net_list_before = set(net_list)
        cmd = "echo %d > %s/sriov_numvfs" % (vf_num, pci_address)
        if driver == "mlx4_core":
            cmd = "modprobe -v mlx4_core num_vfs=%d port_type_array=2,2 probe_vf=%d" \
                    % (vf_num, vf_num)
        test_res = process.run(cmd, shell=True)
        if test_res.exit_status != 0:
            test.fail("Fail to create vfs")

        def _vf_init_completed():
            try:
                net_list_sriov = virsh.nodedev_list(
                    cap='net').stdout.strip().splitlines()
                net_list_sriov = set(net_list_sriov)
                net_diff = list(net_list_sriov.difference(net_list_before))
                net_count = len(net_diff)
                if ((driver != "mlx4_core" and net_count != vf_num) or
                    (driver == "mlx4_core" and net_count != 2 * (vf_num + 1))):
                    net_diff = []
                    return False
                return net_diff
            except process.CmdError:
                raise test.fail(
                    "Get net list with 'virsh nodedev-list' failed\n")

        net_diff = utils_misc.wait_for(_vf_init_completed, timeout=300)
        pci_list_sriov = virsh.nodedev_list(
            cap='pci').stdout.strip().splitlines()
        pci_list_sriov = set(pci_list_sriov)
        pci_diff = list(pci_list_sriov.difference(pci_list_before))
        if not net_diff:
            test.fail("Get net list with 'virsh nodedev-list' failed\n")
        for net in net_diff:
            net = net.split('_')
            length = len(net)
            net = '_'.join(net[1:length - 6])
            mac = ':'.join(net[length - 6:])
            net_name.append(net)
        for pci_addr in pci_diff:
            temp_addr = pci_addr.split("_")
            pci_addr = ':'.join(temp_addr[1:4]) + '.' + temp_addr[4]
            vf_net_name = os.listdir("%s/%s/net" %
                                     (pci_device_dir, pci_addr))[0]
            net_device.append(vf_net_name)
        logging.debug(sorted(net_name))
        logging.debug(sorted(net_device))
        if driver != "mlx4_core" and sorted(net_name) != sorted(net_device):
            test.fail("The net name get from nodedev-list is wrong\n")

    def get_ip_by_mac(mac_addr, timeout=120):
        """
        Get interface IP address by given MAC address.
        """
        if vm.serial_console is not None:
            vm.cleanup_serial_console()
        vm.create_serial_console()
        session = vm.wait_for_serial_login(timeout=240)

        def get_ip():
            return utils_net.get_guest_ip_addr(session, mac_addr)

        try:
            ip_addr = ""
            iface_name = utils_net.get_linux_ifname(session, mac_addr)
            if iface_name is None:
                test.fail("no interface with MAC address %s found" % mac_addr)
            session.cmd("pkill -9 dhclient", ignore_all_errors=True)
            session.cmd("dhclient %s " % iface_name, ignore_all_errors=True)
            ip_addr = utils_misc.wait_for(get_ip, 20)
            logging.debug("The ip addr is %s", ip_addr)
        except Exception:
            logging.warning("Find %s with MAC address %s but no ip for it" %
                            (iface_name, mac_addr))
        finally:
            session.close()
        return ip_addr

    def create_nodedev_pci(pci_address):
        """
            Convert xxxx:xx.x to pci_xxxx_xx_xx_x.
        """
        nodedev_addr = pci_address.split(':')[0:2]
        slot_function = pci_address.split(':')[2]
        nodedev_addr.append(slot_function.split('.')[0])
        nodedev_addr.append(slot_function.split('.')[1])
        nodedev_addr.insert(0, "pci")
        nodedev_addr = "_".join(nodedev_addr)
        return nodedev_addr

    def create_network_interface(name):
        """
            Create network type interface xml.
        """
        new_iface = Interface('network')
        new_iface.source = {'network': name}
        new_iface.model = "virtio"
        new_iface.mac_address = utils_net.generate_mac_address_simple()
        if vlan_id:
            new_iface.vlan = new_iface.new_vlan(**vlan_id)
        return new_iface

    def create_hostdev_network():
        """
            Create hostdev type with vf pool network xml.
        """
        vf_addr_list = []
        netxml = network_xml.NetworkXML()
        if vf_pool_source == "vf_list":
            for vf in vf_list:
                attrs = create_address_dict(vf)
                new_vf = netxml.new_vf_address(**{'attrs': attrs})
                vf_addr_list.append(new_vf)
            netxml.driver = {'name': 'vfio'}
            netxml.forward = {"mode": "hostdev", "managed": managed}
            netxml.vf_list = vf_addr_list
        else:
            netxml.pf = {"dev": pf_name}
            netxml.forward = {"mode": "hostdev", "managed": managed}
        netxml.name = net_name
        logging.debug(netxml)
        return netxml

    def create_macvtap_network():
        """
        Create macvtap type network xml.
        """
        forward_interface_list = []
        for vf_name in vf_name_list:
            forward_interface = {'dev': vf_name}
            forward_interface_list.append(forward_interface)
        netxml = network_xml.NetworkXML()
        netxml.name = net_name
        netxml.forward = {'dev': vf_name_list[0], 'mode': 'passthrough'}
        netxml.forward_interface = forward_interface_list
        logging.debug(netxml)
        return netxml

    def do_operation():
        """
            Do operation in guest os with vf and check the os behavior after operation.
        """
        if operation == "resume_suspend":
            try:
                virsh.suspend(vm.name, debug=True, ignore_status=False)
                virsh.resume(vm.name, debug=True, ignore_statue=False)
                get_ip_by_mac(mac_addr, timeout=120)
            except process.CmdError as detail:
                err_msg = "Suspend-Resume %s with vf failed: %s" % (vm_name,
                                                                    detail)
                test.fail(err_msg)
        if operation == "reboot":
            try:
                if vm.serial_console is not None:
                    vm.cleanup_serial_console()
                    vm.create_serial_console()
                virsh.reboot(vm.name, ignore_status=False)
                get_ip_by_mac(mac_addr, timeout=120)
            except process.CmdError as detail:
                err_msg = "Reboot %s with vf failed: %s" % (vm_name, detail)
                test.fail(err_msg)
        if operation == "save":
            result = virsh.managedsave(vm_name, ignore_status=True, debug=True)
            utils_test.libvirt.check_exit_status(result, expect_error=True)

        if operation == "restart_libvirtd":
            detach_interface()
            utils_libvirtd.libvirtd_restart()
            interface = attach_interface()

    def check_info():
        """
            Check the pf or vf info after create vfs.
        """
        if info_type == "pf_info" or info_type == "vf_order":
            nodedev_pci = create_nodedev_pci(pci_address.split("/")[-1])
            xml = NodedevXML.new_from_dumpxml(nodedev_pci)
            if info_type == "pf_info":
                product_info = xml.cap.product_info
                max_count = xml.max_count
                if pci_info.find(product_info) == -1:
                    test.fail(
                        "The product_info show in nodedev-dumpxml is wrong\n")
                if int(max_count) != max_vfs:
                    test.fail(
                        "The maxCount show in nodedev-dumpxml is wrong\n")
            if info_type == "vf_order":
                vf_addr_list = xml.cap.virt_functions
                if len(vf_addr_list) != max_vfs:
                    test.fail(
                        "The num of vf list show in nodedev-dumpxml is wrong\n"
                    )
                addr_list = []
                for vf_addr in vf_addr_list:
                    addr = vf_addr.domain + ":" + vf_addr.bus + ":" + vf_addr.slot + "." + vf_addr.function
                    addr_list.append(addr)
                logging.debug(
                    "The vf addr list show in nodedev-dumpxml is %s\n",
                    addr_list)
                if sorted(addr_list) != addr_list:
                    test.fail(
                        "The vf addr list show in nodedev-dumpxml is not sorted correctly\n"
                    )
        elif info_type == "vf_info":
            vf_addr = vf_list[0]
            nodedev_pci = create_nodedev_pci(vf_addr)
            vf_xml = NodedevXML.new_from_dumpxml(nodedev_pci)
            vf_bus_slot = ':'.join(vf_addr.split(':')[1:])
            res = process.run("lspci -s %s -vv" % vf_bus_slot)
            vf_pci_info = res.stdout_text
            vf_product_info = vf_xml.cap.product_info
            if vf_pci_info.find(vf_product_info) == -1:
                test.fail(
                    "The product_info show in nodedev-dumpxml is wrong\n")
            pf_addr = vf_xml.cap.virt_functions[0]
            pf_addr_domain = re.findall(r"0x(.+)", pf_addr.domain)[0]
            pf_addr_bus = re.findall(r"0x(.+)", pf_addr.bus)[0]
            pf_addr_slot = re.findall(r"0x(.+)", pf_addr.slot)[0]
            pf_addr_function = re.findall(r"0x(.+)", pf_addr.function)[0]
            pf_pci = pf_addr_domain + ":" + pf_addr_bus + ":" + pf_addr_slot + "." + pf_addr_function
            if pf_pci != pci_id:
                test.fail(
                    "The pf address show in vf nodedev-dumpxml is wrong\n")

    def create_interface():
        """
            Call different function to create interface according to the type
        """
        new_iface = Interface('network')
        if vf_type == "vf":
            new_iface = create_hostdev_interface(vf_addr, managed, model)
        if vf_type == "vf_pool":
            netxml = create_hostdev_network()
            virsh.net_define(netxml.xml, ignore_status=True)
            if not inactive_pool:
                virsh.net_start(netxml.name)
            new_iface = create_network_interface(netxml.name)
        if vf_type == "macvtap":
            new_iface = Interface('direct')
            new_iface.source = {"dev": vf_name, "mode": "passthrough"}
            new_iface.mac_address = utils_net.generate_mac_address_simple()
            new_iface.model = "virtio"
            if vlan_id:
                new_iface.vlan = new_iface.new_vlan(**vlan_id)
        if vf_type == "macvtap_network":
            netxml = create_macvtap_network()
            result = virsh.net_define(netxml.xml, ignore_status=True)
            virsh.net_start(netxml.name)
            new_iface = create_network_interface(netxml.name)
        return new_iface

    def detach_interface():
        """
            Detach interface:

            1.Detach interface from xml;
            2.Check the live xml after detach interface;
            3.Check the vf driver after detach interface.
        """
        def _detach_completed():
            result = virsh.domiflist(vm_name, "", ignore_status=True)
            return result.stdout.find(mac_addr) == -1

        def check_addr_attrs():
            live_xml = vm_xml.VMXML.new_from_dumpxml(vm_name)
            device = live_xml.devices
            hostdev_list = device.by_device_tag("hostdev")
            for hostdev in hostdev_list:
                addr = hostdev.source.untyped_address
                hostdev_addr_attrs = {
                    "domain": addr.domain,
                    "bus": addr.bus,
                    "slot": addr.slot,
                    "function": addr.function
                }
                if hostdev_addr_attrs == vf_addr_attrs:
                    return False
            return True

        result = utils_misc.wait_for(
            lambda: virsh.detach_device(vm_name, new_iface.xml), 30, first=10)
        utils_test.libvirt.check_exit_status(result, expect_error=False)
        if vf_type == "hostdev":
            check_ret = utils_misc.wait_for(check_addr_attrs, timeout=60)
            if not check_ret:
                test.fail("The hostdev device detach failed from xml\n")
        else:
            utils_misc.wait_for(_detach_completed, timeout=60)
        live_xml = vm_xml.VMXML.new_from_dumpxml(vm_name)
        device = live_xml.devices
        logging.debug("Domain xml after detach interface:\n %s", live_xml)

        if vf_type == "vf" or vf_type == "vf_pool":
            for interface in device.by_device_tag("interface"):
                if interface.type_name == "hostdev":
                    if interface.hostdev_address.attrs == vf_addr_attrs:
                        test.fail(
                            "The hostdev interface still in the guest xml after detach\n"
                        )
                    break
            driver = os.readlink(
                os.path.join(pci_device_dir, vf_addr, "driver")).split('/')[-1]
            logging.debug("The driver after vf detached from guest is %s\n",
                          driver)
            if managed == "no":
                if driver != "vfio-pci":
                    test.fail(
                        "The vf pci driver is not vfio-pci after detached from guest with managed as no\n"
                    )
                result = virsh.nodedev_reattach(nodedev_pci_addr)
                utils_test.libvirt.check_exit_status(result,
                                                     expect_error=False)
            elif driver != origin_driver:
                test.fail(
                    "The vf pci driver is not reset to the origin driver after detach from guest: %s vs %s\n"
                    % (driver, origin_driver))
        else:
            for interface in device.by_device_tag("interface"):
                if interface.type_name == "direct":
                    if interface.source["dev"] == vf_name:
                        test.fail(
                            "The macvtap interface still exist in the guest xml after detach\n"
                        )
                    break

    def attach_interface():
        """
            Attach interface:

            1.Attach interface from xml;
            2.Check the vf driver after attach interface;
            3.Check the live xml after attach interface;
        """
        if managed == "no":
            result = virsh.nodedev_detach(nodedev_pci_addr)
            utils_test.libvirt.check_exit_status(result, expect_error=False)
        logging.debug("attach interface xml:\n %s", new_iface)
        result = virsh.attach_device(vm_name,
                                     new_iface.xml,
                                     flagstr=option,
                                     debug=True)
        utils_test.libvirt.check_exit_status(result, expect_error=False)
        if option == "--config":
            result = virsh.start(vm_name)
            utils_test.libvirt.check_exit_status(result, expect_error=False)
        # For option == "--persistent", after VM destroyed and then start, the device should still be there.
        if option == "--persistent":
            virsh.destroy(vm_name)
            result = virsh.start(vm_name, debug=True)
            utils_test.libvirt.check_exit_status(result, expect_error=False)
        live_xml = vm_xml.VMXML.new_from_dumpxml(vm_name)
        logging.debug(live_xml)

        if vf_type != "hostdev":
            get_ip_by_mac(mac_addr, timeout=60)

        device = live_xml.devices

        if vf_type == "hostdev":
            hostdev_list = device.by_device_tag("hostdev")
            if len(hostdev_list) == 0:
                test.fail("The hostdev device attach failed from xml\n")
            else:
                for hostdev in hostdev_list:
                    if hostdev.type == "pci":
                        break
                interface = hostdev

        if vf_type == "vf" or vf_type == "vf_pool":
            for interface in device.by_device_tag("interface"):
                if interface.type_name == "hostdev":
                    if interface.driver.driver_attr['name'] != 'vfio':
                        test.fail(
                            "The driver of the hostdev interface is not vfio\n"
                        )
                    break
            vf_addr_attrs = interface.hostdev_address.attrs
            pci_addr = addr_to_pci(vf_addr_attrs)
            nic_driver = os.readlink(
                os.path.join(pci_device_dir, pci_addr,
                             "driver")).split('/')[-1]
            if nic_driver != "vfio-pci":
                test.fail("The driver of the hostdev interface is not vfio\n")
        elif vf_type == "macvtap" or vf_type == "macvtap_network":
            for interface in device.by_device_tag("interface"):
                if interface.type_name == "direct":
                    if vf_type == "macvtap":
                        if interface.source["dev"] == new_iface.source["dev"]:
                            match = "yes"
                            vf_name = interface.source["dev"]
                    elif interface.source['dev'] in vf_name_list:
                        match = "yes"
                        vf_name = interface.source["dev"]
                if match != "yes":
                    test.fail(
                        "The dev name or mode of macvtap interface is wrong after attach\n"
                    )
        return interface

    def setup_controller(nic_num, controller_index, ctl_models):
        """
        Create controllers bond to numa node in the guest xml

        :param nic_num: number of nic card bond to numa node
        :param controller_index: index num used to create controllers
        :param ctl_models: controller topo for numa bond
        """
        index = controller_index
        if nic_num == 2:
            ctl_models.append('pcie-switch-upstream-port')
            ctl_models.append('pcie-switch-downstream-port')
            ctl_models.append('pcie-switch-downstream-port')
        for i in range(index):
            controller = Controller("controller")
            controller.type = "pci"
            controller.index = i
            if i == 0:
                controller.model = 'pcie-root'
            else:
                controller.model = 'pcie-root-port'
            vmxml.add_device(controller)
        set_address = False
        for model in ctl_models:
            controller = Controller("controller")
            controller.type = "pci"
            controller.index = index
            controller.model = model
            if set_address or model == "pcie-switch-upstream-port":
                attrs = {
                    'type': 'pci',
                    'domain': '0',
                    'slot': '0',
                    'bus': index - 1,
                    'function': '0'
                }
                controller.address = controller.new_controller_address(
                    **{"attrs": attrs})
                logging.debug(controller)
            if controller.model == "pcie-expander-bus":
                controller.node = "0"
                controller.target = {'busNr': '100'}
                set_address = True
            else:
                set_address = False
            logging.debug(controller)
            vmxml.add_device(controller)
            index += 1
        return index - 1

    def add_numa(vmxml):
        """
        Add numa node in the guest xml

        :param vmxml: The instance of VMXML clas
        """
        vcpu = vmxml.vcpu
        max_mem = vmxml.max_mem
        max_mem_unit = vmxml.max_mem_unit
        numa_dict = {}
        numa_dict_list = []
        # Compute the memory size for each numa node
        if vcpu == 1:
            numa_dict['id'] = '0'
            numa_dict['cpus'] = '0'
            numa_dict['memory'] = str(max_mem)
            numa_dict['unit'] = str(max_mem_unit)
            numa_dict_list.append(numa_dict)
        else:
            for index in range(2):
                numa_dict['id'] = str(index)
                numa_dict['memory'] = str(max_mem // 2)
                numa_dict['unit'] = str(max_mem_unit)
                if vcpu == 2:
                    numa_dict['cpus'] = str(index)
                else:
                    if index == 0:
                        if vcpu == 3:
                            numa_dict['cpus'] = str(index)
                        if vcpu > 3:
                            numa_dict['cpus'] = "%s-%s" % (index,
                                                           vcpu // 2 - 1)
                    else:
                        numa_dict['cpus'] = "%s-%s" % (vcpu // 2,
                                                       str(vcpu - 1))
                numa_dict_list.append(numa_dict)
                numa_dict = {}
        # Add cpu device with numa node setting in domain xml
        vmxml_cpu = vm_xml.VMCPUXML()
        vmxml_cpu.xml = "<cpu mode='host-model'><numa/></cpu>"
        vmxml_cpu.numa_cell = vmxml_cpu.dicts_to_cells(numa_dict_list)
        vmxml.cpu = vmxml_cpu

    def create_iface_list(bus_id, nic_num, vf_list):
        """
            Create hostdev interface list bond to numa node

            :param bus_id: bus_id in pci address which decides the controller attached to
            :param nic_num: number of nic card bond to numa node
            :param vf_list: sriov vf list
        """
        iface_list = []
        for num in range(nic_num):
            vf_addr = vf_list[num]
            iface = create_hostdev_interface(vf_addr, managed, model)
            bus_id -= num
            attrs = {
                'type': 'pci',
                'domain': '0',
                'slot': '0',
                'bus': bus_id,
                'function': '0'
            }
            iface.address = iface.new_iface_address(**{"attrs": attrs})
            iface_list.append(iface)
        return iface_list

    def check_guestos(iface_list):
        """
            Check whether vf bond to numa node can get ip successfully in guest os

            :param iface_list: hostdev interface list
        """
        for iface in iface_list:
            mac_addr = iface.mac_address
            get_ip_by_mac(mac_addr, timeout=60)

    def check_numa(vf_driver):
        """
        Check whether vf bond to correct numa node in guest os

        :param vf_driver: vf driver
        """
        if vm.serial_console:
            vm.cleanup_serial_console()
        vm.create_serial_console()
        session = vm.wait_for_serial_login(timeout=240)
        vf_pci = "/sys/bus/pci/drivers/%s" % vf_driver
        vf_dir = session.cmd_output("ls -d %s/00*" %
                                    vf_pci).strip().split('\n')
        for vf in vf_dir:
            numa_node = session.cmd_output('cat %s/numa_node' %
                                           vf).strip().split('\n')[-1]
            logging.debug("The vf is attached to numa node %s\n", numa_node)
            if numa_node != "0":
                test.fail("The vf is not attached to numa node 0\n")
        session.close()

    def remove_devices(vmxml, device_type):
        """
        Remove all addresses for all devices who has one.

        :param vm_xml: The VM XML to be modified
        :param device_type: The device type for removing

        :return: True if success, otherwise, False
        """
        if device_type not in ['address', 'usb']:
            return
        type_dict = {'address': '/devices/*/address', 'usb': '/devices/*'}
        try:
            for elem in vmxml.xmltreefile.findall(type_dict[device_type]):
                if device_type == 'usb':
                    if elem.get('bus') == 'usb':
                        vmxml.xmltreefile.remove(elem)
                else:
                    vmxml.xmltreefile.remove(elem)
        except (AttributeError, TypeError) as details:
            test.error("Fail to remove '%s': %s" % (device_type, details))
        vmxml.xmltreefile.write()

    vm_name = params.get("main_vm", "avocado-vt-vm1")
    vm = env.get_vm(params["main_vm"])
    machine_type = params.get("machine_type", "pc")
    operation = params.get("operation")
    status_error = params.get("status_error", "no") == "yes"
    model = params.get("model", "")
    managed = params.get("managed", "yes")
    attach = params.get("attach", "")
    option = params.get("option", "")
    vf_type = params.get("vf_type", "")
    dev_type = params.get("dev_type", "")
    info_check = params.get("info_check", "no")
    info_type = params.get("info_type", "")
    vf_pool_source = params.get("vf_pool_source", "vf_list")
    loop_times = int(params.get("loop_times", "1"))
    start_vm = "yes" == params.get("start_vm", "yes")
    including_pf = "yes" == params.get("including_pf", "no")
    max_vfs_attached = "yes" == params.get("max_vfs_attached", "no")
    inactive_pool = "yes" == params.get("inactive_pool", "no")
    duplicate_vf = "yes" == params.get("duplicate_vf", "no")
    expected_error = params.get("error_msg", "")
    nic_num = int(params.get("nic_num", "1"))
    nfv = params.get("nfv", "no") == "yes"
    ctl_models = params.get("ctl_models", "").split(' ')
    controller_index = int(params.get("controller_index", "12"))
    vlan_id = eval(params.get("vlan_id", "None"))
    trunk = params.get("trunk", "no") == "yes"

    vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name)
    backup_xml = vmxml.copy()
    vmxml.remove_all_device_by_type('interface')
    vmxml.sync()
    if max_vfs_attached:
        controller_devices = vmxml.get_devices("controller")
        pci_bridge_controllers = []
        for device in controller_devices:
            logging.debug(device)
            if device.type == 'pci' and device.model == "pci-bridge":
                pci_bridge_controllers.append(device)
        if not pci_bridge_controllers and machine_type != 'q35':
            pci_bridge_controller = Controller("controller")
            pci_bridge_controller.type = "pci"
            pci_bridge_controller.index = "1"
            pci_bridge_controller.model = "pci-bridge"
            vmxml.add_device(pci_bridge_controller)
            vmxml.sync()

    if start_vm:
        if not vm.is_dead():
            vm.destroy()
        vm.start()
        if vm.serial_console is not None:
            vm.cleanup_serial_console()
        vm.create_serial_console()
        session = vm.wait_for_serial_login(timeout=240)
        session.close()
    else:
        if not vm.is_dead():
            vm.destroy()

    pci_device_dir = "/sys/bus/pci/devices"
    pci_address = ""
    driver = ""
    net_name = "test-net"

    # Prepare interface xml
    try:
        pci_id = utils_sriov.get_pf_pci()
        if not pci_id:
            test.cancel("NO available pf found.")
        pci_info = utils_sriov.get_pf_info_by_pci(pci_id)
        pf_name = pci_info.get('iface')
        driver = pci_info.get('driver')
        pci_address = os.path.join("/sys/bus/pci/drivers", driver, pci_id)
        bus_slot = ':'.join(pci_id.split(':')[1:])
        if not utils_package.package_install('pciutils'):
            test.error('Failed to install "pciutils" which provides '
                       'command "lspci"')
        pci_info = process.run("lspci -s %s -vv" % bus_slot).stdout_text
        logging.debug("The pci info of the sriov card is:\n %s", pci_info)
        max_vfs = int(re.findall(r"Total VFs: (.+?),", pci_info)[0]) - 1
        if info_check == 'yes' or max_vfs < 32:
            vf_num = max_vfs
            create_vfs(vf_num)
        else:
            vf_num = int(max_vfs // 2 + 1)
            create_vfs(vf_num)

        vf_list = []
        vf_name_list = []
        vf_mac_list = []

        for i in range(vf_num):
            vf = os.readlink("%s/virtfn%s" % (pci_address, str(i)))
            vf = os.path.split(vf)[1]
            vf_list.append(vf)
            vf_name = os.listdir('%s/%s/net' % (pci_device_dir, vf))[0]
            with open('%s/%s/net/%s/address' % (pci_device_dir, vf, vf_name),
                      'r') as f:
                vf_mac = f.readline().strip()
            vf_name_list.append(vf_name)
            vf_mac_list.append(vf_mac)

        if attach == "yes" and not nfv:
            vf_addr = vf_list[0]
            if dev_type:
                mac_addr = vf_mac_list[0]
                new_iface = utils_test.libvirt.create_hostdev_xml(
                    vf_addr, managed=managed)
            else:
                new_iface = create_interface()
                mac_addr = new_iface.mac_address
            if inactive_pool or trunk:
                result = virsh.attach_device(vm_name,
                                             file_opt=new_iface.xml,
                                             flagstr=option,
                                             ignore_status=True,
                                             debug=True)
                utils_test.libvirt.check_result(result, expected_error)
            else:
                nodedev_pci_addr = create_nodedev_pci(vf_addr)
                origin_driver = os.readlink(
                    os.path.join(pci_device_dir, vf_addr,
                                 "driver")).split('/')[-1]
                logging.debug(
                    "The driver of vf before attaching to guest is %s\n",
                    origin_driver)
                count = 0
                while count < loop_times:
                    interface = attach_interface()
                    if vf_type in ["vf", "vf_pool"]:
                        vf_addr_attrs = interface.hostdev_address.attrs
                    if vf_type == "hostdev":
                        addr = interface.source.untyped_address
                        vf_addr_attrs = {
                            "domain": addr.domain,
                            "bus": addr.bus,
                            "slot": addr.slot,
                            "function": addr.function
                        }
                    if operation != "":
                        do_operation()
                    detach_interface()
                    count += 1
                if max_vfs_attached:
                    interface_list = []
                    # Get max index of all pcie-root-port
                    pcie_ctls = vmxml.get_controllers('pci', 'pcie-root-port')
                    pcie_indexes = [
                        int(port.get('index')) for port in pcie_ctls
                    ]

                    def _add_pcie_root_port(index):
                        """
                        Add pcie root port with given index
                        :param index: index of port that is going to be added
                        :return:
                        """
                        pcie_root_port = Controller("controller")
                        pcie_root_port.type = "pci"
                        pcie_root_port.index = index
                        pcie_root_port.model = "pcie-root-port"
                        vmxml.add_device(pcie_root_port)
                        vmxml.sync()

                    for i in range(len(vf_list)):
                        _add_pcie_root_port(max(pcie_indexes) + 1 + i)
                    vm.start()
                    for vf_addr in vf_list:
                        new_iface = create_interface()
                        mac_addr = new_iface.mac_address
                        nodedev_pci_addr = create_nodedev_pci(vf_addr)
                        attach_interface()
                        interface_list.append(new_iface)
                    count = 0
                    for new_iface in interface_list:
                        vf_addr = vf_list[count]
                        vf_addr_attrs = new_iface.hostdev_address.attrs
                        detach_interface()
                        count += 1
        if info_check == "yes":
            check_info()
        if including_pf:
            vf_list = []
            pf_addr = pci_id
            vf_list.append(pf_addr)
            netxml = create_hostdev_network()
            result = virsh.net_define(netxml.xml,
                                      ignore_status=True,
                                      debug=True)
            utils_test.libvirt.check_result(result, expected_error)
        if duplicate_vf:
            vf_list.append(vf_list[0])
            netxml = create_hostdev_network()
            result = virsh.net_define(netxml.xml,
                                      ignore_status=True,
                                      debug=True)
            utils_test.libvirt.check_result(result, expected_error)
            result = virsh.net_create(netxml.xml,
                                      ignore_status=True,
                                      debug=True)
            utils_test.libvirt.check_result(result, expected_error)
        if nfv:
            vf_driver = os.readlink(
                os.path.join(pci_device_dir, vf_list[0],
                             "driver")).split('/')[-1]
            vmxml.remove_all_device_by_type('controller')
            remove_devices(vmxml, 'address')
            remove_devices(vmxml, 'usb')
            osxml = vmxml.os
            if "i440fx" in vmxml.os.machine:
                osxml.machine = "q35"
                vmxml.os = osxml
            add_numa(vmxml)
            bus_id = setup_controller(nic_num, controller_index, ctl_models)
            vmxml.sync()
            logging.debug(vmxml)
            iface_list = create_iface_list(bus_id, nic_num, vf_list)
            for iface in iface_list:
                txt = process.run("cat %s" % iface.xml, shell=True).stdout_text
                logging.debug("iface_xml for attach device is %s" % txt)
                result = virsh.attach_device(vm_name,
                                             file_opt=iface.xml,
                                             flagstr=option,
                                             ignore_status=True,
                                             debug=True)
                utils_test.libvirt.check_exit_status(result,
                                                     expect_error=False)
            result = virsh.start(vm_name, debug=True)
            utils_test.libvirt.check_exit_status(result, expect_error=False)
            live_xml = vm_xml.VMXML.new_from_dumpxml(vm_name)
            logging.debug(live_xml)
            check_guestos(iface_list)
            check_numa(vf_driver)
    finally:
        if vm.is_alive():
            vm.destroy(gracefully=False)
        backup_xml.sync()
        if driver == "mlx4_core":
            # Reload mlx4 driver to default setting
            process.run(
                "modprobe -r mlx4_en ; modprobe -r mlx4_ib ; modprobe -r mlx4_core",
                shell=True)
            process.run(
                "modprobe mlx4_core; modprobe mlx4_ib;  modprobe mlx4_en",
                shell=True)
        else:
            process.run("echo 0 > %s/sriov_numvfs" % pci_address, shell=True)
        if vf_type == "vf_pool" or vf_type == "macvtap_network":
            virsh.net_destroy(net_name)
            virsh.net_undefine(net_name, ignore_status=True)
def run(test, params, env):
    """
    Test when the PCI configuration file is in read-only mode
    """
    def test_vf_hotplug():
        """
        Hot-plug VF to VM

        """
        logging.info("Preparing a running guest...")
        libvirt_vmxml.remove_vm_devices_by_type(vm, 'interface')
        vm.start()
        vm_session = vm.wait_for_serial_login(timeout=180)

        logging.info("Attaching VF to the guest...")
        mac_addr = utils_net.generate_mac_address_simple()
        iface_dict = eval(
            params.get('iface_dict', '{"hostdev_addr": "%s"}') %
            utils_sriov.pci_to_addr(vf_pci))
        iface = interface.Interface("hostdev")
        iface.xml = libvirt.modify_vm_iface(vm.name, "get_xml", iface_dict)
        virsh.attach_device(vm_name,
                            iface.xml,
                            debug=True,
                            ignore_status=False)

        logging.info("Checking VF in the guest...")
        vm_iface_types = [
            iface.get_type_name() for iface in vm_xml.VMXML.new_from_dumpxml(
                vm_name).devices.by_device_tag("interface")
        ]
        if 'hostdev' not in vm_iface_types:
            test.fail('Unable to get hostdev interface!')
        if cmd_in_vm:
            if not utils_misc.wait_for(
                    lambda: not vm_session.cmd_status(cmd_in_vm), 30, 10):
                test.fail("Can not get the Virtual Function info on vm!")
        vm_session.close()

    libvirt_version.is_libvirt_feature_supported(params)

    test_case = params.get("test_case", "")
    run_test = eval("test_%s" % test_case)
    cmd_in_vm = params.get("cmd_in_vm")

    vm_name = params.get("main_vm", "avocado-vt-vm1")
    vm = env.get_vm(vm_name)
    pf_pci = utils_sriov.get_pf_pci()
    if not pf_pci:
        test.cancel("NO available pf found.")
    default_vf = sriov_base.setup_vf(pf_pci, params)
    vf_pci = utils_sriov.get_vf_pci_id(pf_pci)
    dev_name = utils_sriov.get_device_name(vf_pci)

    vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name)
    orig_config_xml = vmxml.copy()
    libvirtd = utils_libvirtd.Libvirtd('virtqemud')
    try:
        virsh.nodedev_detach(dev_name, debug=True, ignore_status=False)
        logging.info("Re-mounting sysfs with ro mode...")
        utils_misc.mount('/sys', '', None, 'remount,ro')
        libvirtd.restart()
        run_test()
    finally:
        logging.info("Recover test enviroment.")
        utils_misc.mount('/sys', '', None, 'remount,rw')
        sriov_base.recover_vf(pf_pci, params, default_vf)
        if vm.is_alive():
            vm.destroy(gracefully=False)
        orig_config_xml.sync()
        virsh.nodedev_reattach(dev_name, debug=True)
Esempio n. 7
0
def run(test, params, env):
    """
    Sriov net failover related test.
    """
    def setup_hotplug_hostdev_iface_with_teaming():
        logging.info("Create hostdev network.")
        net_hostdev_fwd = params.get("net_hostdev_fwd",
                                     '{"mode": "hostdev", "managed": "yes"}')
        net_hostdev_dict = {
            "net_name": net_hostdev_name,
            "net_forward": net_hostdev_fwd,
            "net_forward_pf": '{"dev": "%s"}' % pf_name
        }
        libvirt_network.create_or_del_network(net_hostdev_dict)

        logging.info("Clear up VM interface.")
        libvirt_vmxml.remove_vm_devices_by_type(vm, 'interface')
        iface = interface.Interface("network")
        iface.xml = create_bridge_iface_xml(vm, mac_addr, params)
        virsh.attach_device(vm_name,
                            iface.xml,
                            flagstr='--persistent',
                            debug=True,
                            ignore_status=False)
        vm.start()
        vm.wait_for_serial_login(timeout=180).close()

    def teardown_hotplug_hostdev_iface_with_teaming():
        logging.info("Delete hostdev network.")
        net_hostdev_dict = {"net_name": net_hostdev_name}
        libvirt_network.create_or_del_network(net_hostdev_dict, is_del=True)

    def test_hotplug_hostdev_iface_with_teaming():
        logging.info("Attach a hostdev interface.")
        hostdev_iface_xml = create_hostdev_iface_xml(vm, mac_addr, params)
        virsh.attach_device(vm_name,
                            hostdev_iface_xml,
                            debug=True,
                            ignore_status=False)
        check_ifaces(vm_name, expected_ifaces={"bridge", "hostdev"})

        vm_session = vm.wait_for_serial_login(timeout=240)
        ping_ip = get_ping_dest(vm_session, mac_addr)
        check_vm_network_accessed(vm_session,
                                  ping_dest=ping_ip,
                                  tcpdump_iface=bridge_name,
                                  tcpdump_status_error=True)

        logging.info("Detach the hostdev interface.")
        hostdev_iface = interface.Interface("network")
        for ifc in vm_xml.VMXML.new_from_dumpxml(
                vm_name).devices.by_device_tag("interface"):
            if ifc.type_name == "hostdev":
                ifc.del_address()
                hostdev_iface = ifc
        virsh.detach_device(vm_name,
                            hostdev_iface.xml,
                            wait_remove_event=True,
                            debug=True,
                            ignore_status=False)
        check_ifaces(vm_name, expected_ifaces={"hostdev"}, status_error=True)

        check_vm_network_accessed(vm_session,
                                  2,
                                  ping_dest=ping_ip,
                                  tcpdump_iface=bridge_name,
                                  tcpdump_status_error=False)

        libvirt_vfio.check_vfio_pci(vf_pci, status_error=True)
        logging.info("Re-attach the hostdev interface.")
        virsh.attach_device(vm_name,
                            hostdev_iface.xml,
                            debug=True,
                            ignore_status=False)
        check_vm_network_accessed(vm_session,
                                  ping_dest=ping_ip,
                                  tcpdump_iface=bridge_name,
                                  tcpdump_status_error=True)

    def setup_hotplug_hostdev_device_with_teaming():
        libvirt_vmxml.remove_vm_devices_by_type(vm, 'interface')
        vm.start()
        vm.wait_for_serial_login(timeout=240).close()

    def test_hotplug_hostdev_device_with_teaming():
        default_vf_mac = utils_sriov.get_vf_mac(pf_name)
        utils_sriov.set_vf_mac(pf_name, mac_addr)
        logging.info("Attach the bridge interface.")
        brg_iface_xml = create_bridge_iface_xml(vm, mac_addr, params)
        virsh.attach_device(vm_name,
                            brg_iface_xml,
                            debug=True,
                            ignore_status=False)
        # Wait for 10s before attaching the hostdev device
        time.sleep(10)
        logging.info("Attach the hostdev device.")
        hostdev_dev = libvirt.create_hostdev_xml(vf_pci,
                                                 teaming=hostdev_teaming_dict)
        virsh.attach_device(vm_name,
                            hostdev_dev.xml,
                            debug=True,
                            ignore_status=False)
        vm_session = vm.wait_for_serial_login(timeout=240)
        ping_ip = get_ping_dest(vm_session, mac_addr)
        check_vm_network_accessed(vm_session,
                                  ping_dest=ping_ip,
                                  tcpdump_iface=bridge_name,
                                  tcpdump_status_error=True)
        logging.info("Detach the hostdev device.")
        virsh.detach_device(vm_name,
                            hostdev_dev.xml,
                            wait_remove_event=True,
                            debug=True,
                            ignore_status=False)
        logging.debug("Recover vf's mac to %s.", default_vf_mac)
        utils_sriov.set_vf_mac(pf_name, default_vf_mac)

        check_hostdev = vm_xml.VMXML.new_from_dumpxml(vm_name)\
            .devices.by_device_tag('hostdev')
        if check_hostdev:
            test.fail("The hostdev device exists after detaching %s." %
                      check_hostdev)
        libvirt_vfio.check_vfio_pci(vf_pci, status_error=True)
        check_vm_network_accessed(vm_session,
                                  2,
                                  ping_dest=ping_ip,
                                  tcpdump_iface=bridge_name,
                                  tcpdump_status_error=False)

    def setup_save_restore_hostdev_device_with_teaming():
        logging.info("Start a VM with bridge iface and hostdev device.")
        libvirt_vmxml.remove_vm_devices_by_type(vm, 'interface')
        vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name)
        iface = interface.Interface("network")
        iface.xml = create_bridge_iface_xml(vm, mac_addr, params)
        vmxml.add_device(iface)

        hostdev_dev = libvirt.create_hostdev_xml(vf_pci,
                                                 teaming=hostdev_teaming_dict)
        vmxml.add_device(hostdev_dev)
        vmxml.sync()
        vm.start()
        utils_sriov.set_vf_mac(pf_name, mac_addr)
        vm.wait_for_serial_login(timeout=240).close()

    def test_save_restore_hostdev_device_with_teaming():
        logging.info("Save/restore VM.")
        save_file = os.path.join(data_dir.get_tmp_dir(), "save_file")
        virsh.save(vm_name,
                   save_file,
                   debug=True,
                   ignore_status=False,
                   timeout=10)
        if not libvirt.check_vm_state(vm_name, "shut off"):
            test.fail("The guest should be down after executing 'virsh save'.")
        virsh.restore(save_file, debug=True, ignore_status=False)
        if not libvirt.check_vm_state(vm_name, "running"):
            test.fail(
                "The guest should be running after executing 'virsh restore'.")
        vm.cleanup_serial_console()
        vm.create_serial_console()
        vm_session = vm.wait_for_serial_login()
        ping_ip = get_ping_dest(vm_session, mac_addr)
        check_vm_network_accessed(vm_session,
                                  ping_dest=ping_ip,
                                  tcpdump_iface=bridge_name,
                                  tcpdump_status_error=True)
        logging.info("Detach the hostdev device.")
        hostdev_dev = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name).devices.\
            by_device_tag("hostdev")
        virsh.detach_device(vm_name,
                            hostdev_dev.xml,
                            wait_remove_event=True,
                            debug=True,
                            ignore_status=False)
        check_hostdev = vm_xml.VMXML.new_from_dumpxml(vm_name)\
            .devices.by_device_tag('hostdev')
        if check_hostdev:
            test.fail("The hostdev device exists after detaching %s." %
                      check_hostdev)

        check_vm_network_accessed(vm_session,
                                  2,
                                  ping_dest=ping_ip,
                                  tcpdump_iface=bridge_name,
                                  tcpdump_status_error=False)
        logging.info("Attach the hostdev device.")
        virsh.attach_device(vm_name,
                            hostdev_dev.xml,
                            debug=True,
                            ignore_status=False)
        check_vm_network_accessed(vm_session,
                                  ping_dest=ping_ip,
                                  tcpdump_iface=bridge_name,
                                  tcpdump_status_error=True)

    def setup_save_restore_hostdev_iface_with_teaming():
        logging.info("Create hostdev network.")
        net_hostdev_fwd = params.get("net_hostdev_fwd",
                                     '{"mode": "hostdev", "managed": "yes"}')
        net_hostdev_dict = {
            "net_name": net_hostdev_name,
            "net_forward": net_hostdev_fwd,
            "net_forward_pf": '{"dev": "%s"}' % pf_name
        }
        libvirt_network.create_or_del_network(net_hostdev_dict)
        libvirt_vmxml.remove_vm_devices_by_type(vm, 'interface')
        vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name)
        iface = interface.Interface("network")
        iface.xml = create_bridge_iface_xml(vm, mac_addr, params)
        vmxml.add_device(iface)
        iface.xml = create_hostdev_iface_xml(vm, mac_addr, params)
        vmxml.add_device(iface)
        vmxml.sync()
        logging.debug("VMXML after updating ifaces: %s.",
                      vm_xml.VMXML.new_from_dumpxml(vm_name))
        vm.start()
        vm_session = vm.wait_for_serial_login(timeout=240)
        ping_ip = get_ping_dest(vm_session, mac_addr)
        check_vm_network_accessed(vm_session,
                                  ping_dest=ping_ip,
                                  tcpdump_iface=bridge_name,
                                  tcpdump_status_error=True)

    def teardown_save_restore_hostdev_iface_with_teaming():
        teardown_hotplug_hostdev_iface_with_teaming()

    def test_save_restore_hostdev_iface_with_teaming():
        logging.info("Save/restore VM.")
        save_file = os.path.join(data_dir.get_tmp_dir(), "save_file")
        virsh.save(vm_name,
                   save_file,
                   debug=True,
                   ignore_status=False,
                   timeout=10)
        if not libvirt.check_vm_state(vm_name, "shut off"):
            test.fail("The guest should be down after executing 'virsh save'.")
        virsh.restore(save_file, debug=True, ignore_status=False)
        if not libvirt.check_vm_state(vm_name, "running"):
            test.fail(
                "The guest should be running after executing 'virsh restore'.")

        vm.cleanup_serial_console()
        vm.create_serial_console()
        vm_session = vm.wait_for_serial_login(timeout=240)
        ping_ip = get_ping_dest(vm_session, mac_addr, False)
        logging.debug(ping_ip)
        check_vm_network_accessed(vm_session,
                                  ping_dest=ping_ip,
                                  tcpdump_iface=bridge_name,
                                  tcpdump_status_error=True)

    def check_vm_iface_num(session, exp_num=3):
        """
        Check he number of interfaces

        :param session: The session to the guest
        :param exp_num: The expected number
        :return: True when interfaces' number is equal to exp_num
        """
        p_iface = utils_net.get_remote_host_net_ifs(session)[0]
        logging.debug("Ifaces in VM: %s", p_iface)

        return len(p_iface) == exp_num

    def check_vm_network_accessed(vm_session,
                                  expected_iface_no=3,
                                  ping_dest="8.8.8.8",
                                  timeout=30,
                                  tcpdump_iface=None,
                                  tcpdump_status_error=False):
        """
        Test VM's network by checking ifaces' number and the accessibility

        :param vm_session: The session object to the guest
        :param expected_iface_no: The expected number of ifaces
        :param ping_dest: The destination to be ping
        :param timeout: The timeout of the checking
        :param tcpdump_iface: The interface to check
        :param tcpdump_status_error: Whether the tcpdump's output should include
            the string "ICMP echo request"
        :raise: test.fail when ifaces' number is incorrect or ping fails.
        """
        if not utils_misc.wait_for(
                lambda: check_vm_iface_num(vm_session, expected_iface_no),
                first=3,
                timeout=timeout):
            test.fail("%d interfaces should be found on the vm." %
                      expected_iface_no)
        if tcpdump_iface:
            cmd = "tcpdump  -i %s icmp" % tcpdump_iface
            tcpdump_session = aexpect.ShellSession('bash')
            tcpdump_session.sendline(cmd)

        if not utils_misc.wait_for(
                lambda: not utils_test.ping(ping_dest,
                                            count=3,
                                            timeout=5,
                                            output_func=logging.debug,
                                            session=vm_session)[0],
                first=5,
                timeout=timeout):
            test.fail("Failed to ping %s." % ping_dest)
        if tcpdump_iface:
            output = tcpdump_session.get_stripped_output()
            logging.debug("tcpdump's output: %s.", output)
            pat_str = "ICMP echo request"
            if re.search(pat_str, output):
                if tcpdump_status_error:
                    test.fail(
                        "Get incorrect tcpdump output: {}, it should not "
                        "include '{}'.".format(output, pat_str))
            else:
                if not tcpdump_status_error:
                    test.fail("Get incorrect tcpdump output: {}, it should "
                              "include '{}'.".format(output, pat_str))

    def get_ping_dest(vm_session, mac_addr, restart_network=True):
        """
        Get an ip address to ping

        :param vm_session: The session object to the guest
        :param mac_addr: mac address of given interface
        :param restart_network:  Whether to restart guest's network
        :return: ip address
        """
        if restart_network:
            utils_misc.cmd_status_output("dhclient -r; sleep 5; dhclient",
                                         shell=True,
                                         session=vm_session)
        vm_iface_info = utils_net.get_linux_iface_info(
            mac_addr, vm_session)['addr_info'][0]['local']
        return re.sub('\d+$', '1', vm_iface_info)

    def create_bridge_iface_xml(vm, mac_addr, params):
        """
        Create xml of bridge interface

        :param vm: The vm object
        :param mac_address: The mac address
        :param params: Dictionary with the test parameters
        :return: The interface xml
        """
        net_bridge_name = params.get("net_bridge_name", "host-bridge")
        iface_bridge_dict = {
            "type": "network",
            "source": "{'network': '%s'}" % net_bridge_name,
            "mac": mac_addr,
            "model": "virtio",
            "teaming": '{"type":"persistent"}',
            "alias": '{"name": "ua-backup0"}'
        }
        return libvirt.modify_vm_iface(vm.name, "get_xml", iface_bridge_dict)

    def create_hostdev_iface_xml(vm, mac_addr, params):
        """
        Create xml of hostdev interface

        :param vm: The vm object
        :param mac_address: The mac address
        :param params: Dictionary with the test parameters
        :return: The interface xml
        """
        net_hostdev_name = params.get("net_hostdev_name", "hostdev-net")
        hostdev_iface_dict = {
            "type": "network",
            "source": "{'network': '%s'}" % net_hostdev_name,
            "mac": mac_addr,
            "teaming": '{"type":"transient", "persistent": "ua-backup0"}'
        }
        return libvirt.modify_vm_iface(vm.name, "get_xml", hostdev_iface_dict,
                                       4)

    def check_ifaces(vm_name,
                     expected_ifaces={"bridge", "hostdev"},
                     status_error=False):
        """
        Check VM's interfaces

        :param vm_name: The name of VM
        :param expected_ifaces: The expected interfaces
        :param status_error: Whether the ifaces should be same with the expected_ifaces
        :raise: test.fail if the interface(s) is(are) as expected
        """
        if not expected_ifaces:
            return
        else:
            expected_ifaces = set(expected_ifaces)
        vm_ifaces = [
            iface for iface in vm_xml.VMXML.new_from_dumpxml(
                vm_name).devices.by_device_tag("interface")
        ]
        ifaces_net = {iface.get_type_name() for iface in vm_ifaces}
        if expected_ifaces.issubset(ifaces_net) == status_error:
            test.fail(
                "Unable to get expected interface. The interface %s "
                "should%s be %s." %
                (ifaces_net, ' not' if status_error else '', expected_ifaces))
        else:
            logging.debug("{}Found iface(s) as expected: {}.".format(
                'Not ' if status_error else '', expected_ifaces))

    test_case = params.get("test_case", "")
    run_test = eval("test_%s" % test_case)
    setup_test = eval("setup_%s" % test_case) if "setup_%s" % test_case in \
        locals() else "setup_%s" % test_case
    teardown_test = eval("teardown_%s" % test_case) if "teardown_%s" % \
        test_case in locals() else "teardown_%s" % test_case
    vm_name = params.get("main_vm", "avocado-vt-vm1")
    vm = env.get_vm(params["main_vm"])

    driver = params.get("driver", "ixgbe")
    bridge_name = params.get("bridge_name", "br0")
    net_bridge_name = params.get("net_bridge_name", "host-bridge")
    net_bridge_fwd = params.get("net_bridge_fwd", '{"mode": "bridge"}')
    net_hostdev_name = params.get("net_hostdev_name", "hostdev-net")
    bridge_name = params.get("bridge_name", "br0")
    hostdev_teaming_dict = params.get("hostdev_device_teaming_dict", '{}')

    default_vf = 0
    try:
        vf_no = int(params.get("vf_no", "4"))
    except ValueError as e:
        test.error(e)

    libvirt_version.is_libvirt_feature_supported(params)

    mac_addr = utils_net.generate_mac_address_simple()
    pf_pci = utils_sriov.get_pf_pci()
    if not pf_pci:
        test.cancel("NO available pf found.")
    pf_name = utils_sriov.get_pf_info_by_pci(pf_pci).get('iface')
    brg_dict = {'pf_name': pf_name, 'bridge_name': bridge_name}
    bridge_dict = {
        "net_name": net_bridge_name,
        "net_forward": net_bridge_fwd,
        "net_bridge": '{"name": "%s"}' % bridge_name
    }
    pf_pci_path = utils_misc.get_pci_path(pf_pci)
    cmd = "cat %s/sriov_numvfs" % (pf_pci_path)
    default_vf = process.run(cmd, shell=True, verbose=True).stdout_text

    new_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name)
    orig_config_xml = new_xml.copy()

    try:
        if not utils_sriov.set_vf(pf_pci_path, vf_no):
            test.error("Failed to set vf.")
        utils_sriov.add_or_del_connection(brg_dict, is_del=False)
        libvirt_network.create_or_del_network(bridge_dict)

        vf_pci = utils_sriov.get_vf_pci_id(pf_pci)
        exec_function(setup_test)
        run_test()

    finally:
        logging.info("Recover test enviroment.")
        utils_sriov.add_or_del_connection(brg_dict, is_del=True)
        libvirt_network.create_or_del_network(bridge_dict, is_del=True)
        if 'pf_pci_path' in locals() and default_vf != vf_no:
            utils_sriov.set_vf(pf_pci_path, default_vf)

        if vm.is_alive():
            vm.destroy(gracefully=False)

        try:
            orig_config_xml.sync()
        except:
            # FIXME: Workaround for 'save'/'managedsave' hanging issue
            utils_libvirtd.Libvirtd().restart()
            orig_config_xml.sync()

        exec_function(teardown_test)
Esempio n. 8
0
 def teardown_hostdev():
     """
     Cleanup VF setting for hostdev test
     """
     sriov_base.recover_vf(utils_sriov.get_pf_pci(), params, 0)
Esempio n. 9
0
def run(test, params, env):
    """
    Test VFs when PF is down
    """
    def setup_default():
        """
        Default setup
        """
        test.log.info("Set pf state to down.")
        pf_iface_obj = utils_net.Interface(pf_name)
        pf_iface_obj.down()

    def teardown_default():
        """
        Default cleanup
        """
        pf_iface_obj = utils_net.Interface(pf_name)
        pf_iface_obj.up()

    def test_at_dt():
        """
        Test attach-detach interfaces
        """
        options = '' if vm.is_alive() else '--config'
        iface_dict = eval(params.get('iface_dict')
                          % utils_sriov.pci_to_addr(vf_pci))
        iface = interface_base.create_iface('hostdev', iface_dict)
        result = virsh.attach_device(vm_name, iface.xml,
                                     flagstr=options, debug=True)
        if not start_vm:
            result = virsh.start(vm.name, debug=True)
        libvirt.check_exit_status(result, status_error)
        if error_msg:
            libvirt.check_result(result, error_msg)

    test_case = params.get("test_case", "")
    run_test = eval("test_%s" % test_case)
    start_vm = "yes" == params.get("start_vm")
    status_error = "yes" == params.get("status_error", "no")
    error_msg = params.get("error_msg")

    vm_name = params.get("main_vm", "avocado-vt-vm1")
    vm = env.get_vm(vm_name)
    pf_pci = utils_sriov.get_pf_pci()
    if not pf_pci:
        test.cancel("NO available pf found.")
    sriov_base.setup_vf(pf_pci, params)

    vf_pci = utils_sriov.get_vf_pci_id(pf_pci)
    pf_name = utils_sriov.get_pf_info_by_pci(pf_pci).get('iface')

    setup_test = eval("setup_%s" % test_case) if "setup_%s" % test_case in \
        locals() else setup_default
    teardown_test = eval("teardown_%s" % test_case) if "teardown_%s" % \
        test_case in locals() else teardown_default
    vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name)
    orig_config_xml = vmxml.copy()

    try:
        setup_test()
        run_test()

    finally:
        test.log.info("Recover test enviroment.")
        orig_config_xml.sync()
        teardown_test()
Esempio n. 10
0
def run(test, params, env):
    """
    Test hostdev attach/detach
    """
    def setup_default():
        """
        Default setup
        """
        test.log.info("TEST_SETUP: Clear up VM interface(s).")
        libvirt_vmxml.remove_vm_devices_by_type(vm, 'interface')

    def teardown_default():
        """
        Default cleanup
        """
        test.log.info("TEST_TEARDOWN: Recover test enviroment.")
        orig_config_xml.sync()
        sriov_base.recover_vf(pf_pci, params, 0)

    def exec_test(vm, hostdev_dict, params):
        """
        Execute basic test

        :param vm: VM object
        :param hostdev_dict: Hostdev attrs
        :param params: Test parameters
        """
        start_vm = "yes" == params.get("start_vm")
        options = '' if vm.is_alive() else '--config'
        status_error = "yes" == params.get("status_error", "no")
        error_msg = params.get("error_msg")

        host_dev = create_dev(params, hostdev_dict)
        test.log.debug("Hostdev XML: %s.", host_dev)
        test.log.info("TEST_STEP1: Attach hostdev interface.")
        result = virsh.attach_device(vm_name,
                                     host_dev.xml,
                                     flagstr=options,
                                     debug=True)
        libvirt.check_exit_status(result, status_error)
        if error_msg:
            libvirt.check_result(result, error_msg)
        if status_error:
            return
        if not start_vm:
            vm.start()
            vm.wait_for_serial_login(timeout=240).close()

        test.log.info("TEST_STEP2: Check VM XML.")
        device_type = "interface" if params.get(
            'hostdev_iface_dict') else 'hostdev'
        check_points.comp_hostdev_xml(vm, device_type, hostdev_dict)

    def test_unassigned_address():
        """
        Cold/Hot plug hostdev interface with 'unassigned' address type
        """
        hostdev_dict = get_hostdev_dict(vf_pci, params)
        exec_test(vm, hostdev_dict, params)
        if params.get("status_error") == "yes":
            return
        test.log.info("Check if the VM is not using VF.")
        libvirt_vfio.check_vfio_pci(vf_pci)

        vm.cleanup_serial_console()
        vm.create_serial_console()
        vm_session = vm.wait_for_serial_login(timeout=240)
        p_iface = utils_net.get_remote_host_net_ifs(vm_session)[0]
        if p_iface:
            test.fail("There should be no interface, but got %s." % p_iface)

    def test_duplicated_cust_alias():
        """
        Hotplug hostdev interface with duplicate custom alias
        """
        vm.cleanup_serial_console()
        vm.create_serial_console()
        vm.wait_for_serial_login(timeout=240).close()
        alias_name = 'ua-' + str(uuid.uuid4())
        hostdev_dict = eval(
            params.get('hostdev_iface_dict') %
            (utils_sriov.pci_to_addr(vf_pci), alias_name))
        exec_test(vm, hostdev_dict, params)

        host_dev = vm_xml.VMXML.new_from_dumpxml(vm.name)\
            .devices.by_device_tag("interface")[0]
        test.log.info("TEST_STEP3: Hotplug another hostdev interface with the"
                      "same alias name")
        vf2_pci = utils_sriov.get_vf_pci_id(pf_pci, vf_index=1)
        hostdev_dict['hostdev_address']['attrs'] = utils_sriov.pci_to_addr(
            vf2_pci)
        host_dev2 = interface_base.create_iface('hostdev', hostdev_dict)
        result = virsh.attach_device(vm_name, host_dev2.xml, debug=True)
        libvirt.check_exit_status(result, True)

        test.log.info("TEST_STEP4: Detach the first hostdev interface.")
        virsh.detach_device(vm_name,
                            host_dev.xml,
                            wait_for_event=True,
                            debug=True,
                            ignore_status=False)

        test.log.info("TEST_STEP5: Attach the second hostdev interface again.")
        virsh.attach_device(vm_name,
                            host_dev2.xml,
                            debug=True,
                            ignore_status=False)
        check_points.comp_hostdev_xml(vm, "interface", hostdev_dict)

    libvirt_version.is_libvirt_feature_supported(params)

    test_case = params.get("test_case", "")
    run_test = eval("test_%s" % test_case)

    vm_name = params.get("main_vm", "avocado-vt-vm1")
    vm = env.get_vm(vm_name)
    pf_pci = utils_sriov.get_pf_pci()
    if not pf_pci:
        test.cancel("NO available pf found.")
    sriov_base.setup_vf(pf_pci, params)

    vf_pci = utils_sriov.get_vf_pci_id(pf_pci)

    setup_test = eval("setup_%s" % test_case) if "setup_%s" % test_case in \
        locals() else setup_default
    teardown_test = eval("teardown_%s" % test_case) if "teardown_%s" % \
        test_case in locals() else teardown_default
    vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name)
    orig_config_xml = vmxml.copy()

    try:
        test.log.info("TEST_CASE: %s",
                      run_test.__doc__.lstrip().split('\n\n')[0])
        setup_test()
        run_test()

    finally:
        teardown_test()
Esempio n. 11
0
def run(test, params, env):
    """
    Test interfaces attached from network
    """
    def setup_default():
        """
        Default setup
        """
        pass

    def teardown_default():
        """
        Default cleanup
        """
        pass

    def setup_max_vfs():
        """
        Setup for max_vfs case

        1. Check test environment
        2. Enable VFs
        3. Create networks
        """
        if not utils_misc.compare_qemu_version(4, 0, 0, False):
            test.cancel("This test is supported from qemu-kvm 4.0.0.")
        if len(pf_info) < 2:
            test.cancel("This test requires at least 2 PFs.")

        pf_id_list = get_pf_id_list(pf_info, driver)
        for pf_pci in pf_id_list:
            sriov_base.recover_vf(pf_pci, params)
            sriov_base.setup_vf(pf_pci, params)

        net_info = get_net_dict(pf_info)
        for pf_dev, net_name in net_info.items():
            create_network(net_name, pf_dev, params)

    def teardown_max_vfs():
        """
        Teardown for max_vfs case

        1. Disable VFs
        2. Clean up networks
        """
        pf_id_list = get_pf_id_list(pf_info, driver)
        for pf_pci in pf_id_list:
            sriov_base.recover_vf(pf_pci, params, timeout=240)
        net_info = get_net_dict(pf_info)
        for pf_dev in net_info:
            libvirt_network.create_or_del_network(
                {"net_name": net_info[pf_dev]}, True)

    def test_max_vfs():
        """
        Hotplug MAX VFs to guest

        1. Start vm with 64 vfio interfaces
        2. Check networks
        3. Try to hot plug the 65th hostdev interface
        4. Destroy vm and cold plug 1 hostdev interface
        """
        net_info = get_net_dict(pf_info)
        vf_no = int(params.get("vf_no", "63"))

        logging.debug("Remove VM's interface devices.")
        libvirt_vmxml.remove_vm_devices_by_type(vm, 'interface')
        compare_vm_iface(test, get_vm_iface_num(vm_name), 0)

        logging.info("Cold plug 64 interfaces to VM.")
        opts = "network %s --config" % list(net_info.values())[0]
        for i in range(vf_no):
            virsh.attach_interface(vm_name,
                                   opts,
                                   debug=True,
                                   ignore_status=False)
        net_name_2 = list(net_info.values())[1]
        opts = "network %s --config" % net_name_2
        virsh.attach_interface(vm_name, opts, debug=True, ignore_status=False)
        compare_vm_iface(test, get_vm_iface_num(vm_name), vf_no + 1)

        logging.info("Start VM and check networks.")
        vm.start()
        vm_session = vm.wait_for_serial_login(timeout=240)
        res = vm_session.cmd_status_output(
            'lspci |grep Ether')[1].strip().splitlines()
        compare_vm_iface(test, len(res), vf_no + 1)

        logging.info("Hot Plug the 65th iface.")
        opts_hotplug = "network %s" % net_name_2
        res = virsh.attach_interface(vm_name, opts_hotplug)
        libvirt.check_exit_status(res, True)

        logging.info("Destroy vm and cold plug the 65th hostdev interface.")
        vm.destroy()
        virsh.attach_interface(vm_name, opts, ignore_status=False)

        compare_vm_iface(test, get_vm_iface_num(vm_name), vf_no + 2)
        res = virsh.start(vm_name, debug=True)
        libvirt.check_exit_status(res, True)

    def get_net_dict(pf_info):
        """
        Get network dict from pfs info

        :param pf_info: PFs info
        :return: Network parameters
        """
        pf_id_list = get_pf_id_list(pf_info, driver)
        return dict(
            zip([utils_sriov.get_iface_name(pf_pci) for pf_pci in pf_id_list],
                ['hostdevnet' + str(x) for x in range(len(pf_id_list))]))

    def compare_vm_iface(test, vm_iface_num, expr_no):
        """
        Compare the number of VM interfaces with the expected number

        :param test: test object
        :param vm_iface_num: The number of vm interface
        :param expr_no: Expected number of ifaces
        """
        if expr_no != vm_iface_num:
            test.fail("The number of vm ifaces is incorrect! Expected: %d, "
                      "Actual: %d." % (expr_no, vm_iface_num))
        else:
            logging.debug("The number of VM ifaces is %d.", vm_iface_num)

    test_case = params.get("test_case", "")
    run_test = eval("test_%s" % test_case)
    setup_test = eval("setup_%s" % test_case) if "setup_%s" % test_case in \
        locals() else setup_default
    teardown_test = eval("teardown_%s" % test_case) if "teardown_%s" % \
        test_case in locals() else teardown_default

    pf_info = utils_sriov.get_pf_info()
    pf_pci = utils_sriov.get_pf_pci()
    driver = utils_sriov.get_pf_info_by_pci(pf_pci).get('driver')

    vm_name = params.get("main_vm", "avocado-vt-vm1")
    vm = env.get_vm(vm_name)

    vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name)
    orig_config_xml = vmxml.copy()

    try:
        setup_test()
        run_test()

    finally:
        logging.info("Recover test enviroment.")
        if vm.is_alive():
            vm.destroy(gracefully=False)
        orig_config_xml.sync()
        teardown_test()