sr_iov_hotplug.py 9.2 KB
Newer Older
L
Lucas Meneghel Rodrigues 已提交
1 2
import re
import logging
F
Feng Yang 已提交
3
from autotest.client.shared import error
4
from virttest import utils_misc, aexpect, utils_test, utils_net
F
Feng Yang 已提交
5

L
Lucas Meneghel Rodrigues 已提交
6

F
Feng Yang 已提交
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
@error.context_aware
def run_sr_iov_hotplug(test, params, env):
    """
    Test hotplug of sr-iov devices.

    (Elements between [] are configurable test parameters)
    1) Set up sr-iov test environment in host.
    2) Start VM.
    3) PCI add one/multi sr-io  deivce with (or without) repeat
    4) Compare output of monitor command 'info pci'.
    5) Compare output of guest command [reference_cmd].
    6) Verify whether pci_model is shown in [pci_find_cmd].
    7) Check whether the newly added PCI device works fine.
    8) Delete the device, verify whether could remove the sr-iov device.

L
Lucas Meneghel Rodrigues 已提交
22 23 24
    :param test:   QEMU test object.
    :param params: Dictionary with the test parameters.
    :param env:    Dictionary with test environment.
F
Feng Yang 已提交
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
    """

    def pci_add_iov(pci_num):
        pci_add_cmd = ("pci_add pci_addr=auto host host=%s,if=%s" %
                       (pa_pci_ids[pci_num], pci_model))
        if params.get("hotplug_params"):
            assign_param = params.get("hotplug_params").split()
            for param in assign_param:
                value = params.get(param)
                if value:
                    pci_add_cmd += ",%s=%s" % (param, value)

        return pci_add(pci_add_cmd)

    def pci_add(pci_add_cmd):
        error.context("Adding pci device with command 'pci_add'")
        add_output = vm.monitor.send_args_cmd(pci_add_cmd, convert=False)
L
Lucas Meneghel Rodrigues 已提交
42
        pci_info.append(['', add_output])
F
Feng Yang 已提交
43 44 45 46 47

        if not "OK domain" in add_output:
            raise error.TestFail("Add PCI device failed. "
                                 "Monitor command is: %s, Output: %r" %
                                 (pci_add_cmd, add_output))
L
Lucas Meneghel Rodrigues 已提交
48
        return vm.monitor.info("pci")
F
Feng Yang 已提交
49 50

    def check_support_device(dev):
51
        if vm.monitor.protocol == 'qmp':
F
Feng Yang 已提交
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
            devices_supported = vm.monitor.human_monitor_cmd("%s ?" % cmd_type)
        else:
            devices_supported = vm.monitor.send_args_cmd("%s ?" % cmd_type)
        # Check if the device is support in qemu
        is_support = utils_test.find_substring(devices_supported, dev)
        if not is_support:
            raise error.TestError("%s doesn't support device: %s" %
                                  (cmd_type, dev))

    def device_add_iov(pci_num):
        device_id = "%s" % pci_model + "-" + utils_misc.generate_random_id()
        pci_info.append([device_id])
        check_support_device("pci-assign")
        pci_add_cmd = ("device_add id=%s,driver=pci-assign,host=%s" %
                       (pci_info[pci_num][0], pa_pci_ids[pci_num]))
        if params.get("hotplug_params"):
            assign_param = params.get("hotplug_params").split()
            for param in assign_param:
                value = params.get(param)
                if value:
                    pci_add_cmd += ",%s=%s" % (param, value)
        return device_add(pci_num, pci_add_cmd)

    def device_add(pci_num, pci_add_cmd):
        error.context("Adding pci device with command 'device_add'")
77
        if vm.monitor.protocol == 'qmp':
F
Feng Yang 已提交
78 79 80 81 82 83 84 85 86 87 88 89 90 91
            add_output = vm.monitor.send_args_cmd(pci_add_cmd)
        else:
            add_output = vm.monitor.send_args_cmd(pci_add_cmd, convert=False)
        pci_info[pci_num].append(add_output)

        after_add = vm.monitor.info("pci")
        if pci_info[pci_num][0] not in after_add:
            logging.debug("Print info pci after add the block: %s" % after_add)
            raise error.TestFail("Add device failed. Monitor command is: %s"
                                 ". Output: %r" % (pci_add_cmd, add_output))
        return after_add

    # Hot add a pci device
    def add_device(pci_num):
92 93
        reference_cmd = params["reference_cmd"]
        find_pci_cmd = params["find_pci_cmd"]
F
Feng Yang 已提交
94 95 96 97 98 99 100
        info_pci_ref = vm.monitor.info("pci")
        reference = session.cmd_output(reference_cmd)

        try:
            # get function for adding device.
            add_fuction = local_functions["%s_iov" % cmd_type]
        except Exception:
L
Lucas Meneghel Rodrigues 已提交
101 102 103
            raise error.TestError(
                "No function for adding sr-iov dev with '%s'" %
                cmd_type)
F
Feng Yang 已提交
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
        after_add = None
        if add_fuction:
            # Do add pci device.
            after_add = add_fuction(pci_num)

        try:
            # Define a helper function to compare the output
            def _new_shown():
                o = session.cmd_output(reference_cmd)
                return o != reference

            # Define a helper function to catch PCI device string
            def _find_pci():
                o = session.cmd_output(find_pci_cmd)
                if re.search(match_string, o, re.IGNORECASE):
                    return True
                else:
                    return False

            error.context("Start checking new added device")
            # Compare the output of 'info pci'
            if after_add == info_pci_ref:
                raise error.TestFail("No new PCI device shown after executing "
                                     "monitor command: 'info pci'")

129
            secs = int(params["wait_secs_for_hook_up"])
F
Feng Yang 已提交
130 131 132 133 134 135 136 137 138 139 140
            if not utils_misc.wait_for(_new_shown, test_timeout, secs, 3):
                raise error.TestFail("No new device shown in output of command "
                                     "executed inside the guest: %s" %
                                     reference_cmd)

            if not utils_misc.wait_for(_find_pci, test_timeout, 3, 3):
                raise error.TestFail("New add sr-iov device not found in guest. "
                                     "Command was: %s" % find_pci_cmd)

            # Test the newly added device
            try:
L
Lucas Meneghel Rodrigues 已提交
141
                session.cmd(params["pci_test_cmd"] % (pci_num + 1))
F
Feng Yang 已提交
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
            except aexpect.ShellError, e:
                raise error.TestFail("Check for sr-iov device failed after PCI "
                                     "hotplug. Output: %r" % e.output)

        except Exception:
            pci_del(pci_num, ignore_failure=True)
            raise

    # Hot delete a pci device
    def pci_del(pci_num, ignore_failure=False):
        def _device_removed():
            after_del = vm.monitor.info("pci")
            return after_del != before_del

        before_del = vm.monitor.info("pci")
        if cmd_type == "pci_add":
            slot_id = "0" + pci_info[pci_num][1].split(",")[2].split()[1]
            cmd = "pci_del pci_addr=%s" % slot_id
            vm.monitor.send_args_cmd(cmd, convert=False)
        elif cmd_type == "device_add":
            cmd = "device_del id=%s" % pci_info[pci_num][0]
            vm.monitor.send_args_cmd(cmd)

        if (not utils_misc.wait_for(_device_removed, test_timeout, 0, 1)
L
Lucas Meneghel Rodrigues 已提交
166
                and not ignore_failure):
F
Feng Yang 已提交
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
            raise error.TestFail("Failed to hot remove PCI device: %s. "
                                 "Monitor command: %s" %
                                 (pci_model, cmd))

    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()
    timeout = int(params.get("login_timeout", 360))
    session = vm.wait_for_login(timeout=timeout)

    test_timeout = int(params.get("test_timeout", 360))
    # Test if it is nic or block
    pci_num_range = int(params.get("pci_num", 1))
    rp_times = int(params.get("repeat_times", 1))
    pci_model = params.get("pci_model", "pci-assign")
    # Need udpate match_string if you use a card other than 82576
    match_string = params.get("match_string", "82576")
183 184 185 186 187 188 189 190 191 192
    devices = []
    device_type = params.get("hotplug_device_type", "vf")
    for i in xrange(pci_num_range):
        device = {}
        device["type"] = device_type
        device['mac'] = utils_net.generate_mac_address_simple()
        if params.get("device_name"):
            device["name"] = params.get("device_name")
        devices.append(device)

F
Feng Yang 已提交
193
    if vm.pci_assignable is not None:
194
        pa_pci_ids = vm.pci_assignable.request_devs(devices)
F
Feng Yang 已提交
195 196 197 198

    # Modprobe the module if specified in config file
    module = params.get("modprobe_module")
    if module:
L
Lucas Meneghel Rodrigues 已提交
199
        error.context("modprobe the module %s" % module, logging.info)
F
Feng Yang 已提交
200 201 202
        session.cmd("modprobe %s" % module)

    # Probe qemu to verify what is the supported syntax for PCI hotplug
203
    if vm.monitor.protocol == 'qmp':
F
Feng Yang 已提交
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
        cmd_o = vm.monitor.info("commands")
    else:
        cmd_o = vm.monitor.send_args_cmd("help")

    cmd_type = utils_test.find_substring(str(cmd_o), "device_add", "pci_add")
    if not cmd_o:
        raise error.TestError("Unknow version of qemu")

    local_functions = locals()

    for j in range(rp_times):
        # pci_info is a list of list.
        # each element 'i' has 4 members:
        # pci_info[i][0] == device id, only used for device_add
        # pci_info[i][1] == output of device add command
        pci_info = []
        for pci_num in xrange(pci_num_range):
            msg = "Start hot-adding %sth pci device, repeat %d" % (pci_num + 1,
L
Lucas Meneghel Rodrigues 已提交
222
                                                                   j + 1)
F
Feng Yang 已提交
223 224 225 226 227 228 229
            error.context(msg, logging.info)
            add_device(pci_num)
        for pci_num in xrange(pci_num_range):
            msg = "start hot-deleting %sth pci device repeat %d" % (pci_num + 1,
                                                                    j + 1)
            error.context(msg, logging.info)
            pci_del(-(pci_num + 1))