Fix some bugs in this class.
Add new function get_vf_status add_device
Use error.context in this class.
Make it works with multi vms.
Now it also support assign pf vf together.

Signed-off-by: Feng Yang <[email protected]>
---
 virttest/test_setup.py |  196 ++++++++++++++++++++++++++++++++++--------------
 1 files changed, 139 insertions(+), 57 deletions(-)

diff --git a/virttest/test_setup.py b/virttest/test_setup.py
index f12ac97..795b9d8 100644
--- a/virttest/test_setup.py
+++ b/virttest/test_setup.py
@@ -321,11 +321,10 @@ class PciAssignable(object):
     Request PCI assignable devices on host. It will check whether to request
     PF (physical Functions) or VF (Virtual Functions).
     """
-    def __init__(self, dev_type="vf", driver=None, driver_option=None,
-                 names=None, devices_requested=None,
-                 host_set_flag=None, kvm_params=None):
+    def __init__(self,  driver=None, driver_option=None, host_set_flag=None,
+                 kvm_params=None, vf_filter_re=None, pf_filter_re=None):
         """
-        Initialize parameter 'dev_type' which could be:
+        Initialize parameter 'type' which could be:
         vf: Virtual Functions
         pf: Physical Function (actual hardware)
         mixed:  Both includes VFs and PFs
@@ -333,36 +332,36 @@ class PciAssignable(object):
         If pass through Physical NIC cards, we need to specify which devices
         to be assigned, e.g. 'eth1 eth2'.
 
-        If pass through Virtual Functions, we need to specify how many vfs
-        are going to be assigned, e.g. passthrough_count = 8 and max_vfs in
-        config file.
+        If pass through Virtual Functions, we need to specify max vfs in driver
+        e.g. max_vfs = 7 in config file.
 
-        @param dev_type: PCI device type.
+        @param type: PCI device type.
         @param driver: Kernel module for the PCI assignable device.
         @param driver_option: Module option to specify the maximum number of
                 VFs (eg 'max_vfs=7')
         @param names: Physical NIC cards correspondent network interfaces,
                 e.g.'eth1 eth2 ...'
-        @param devices_requested: Number of devices being requested.
         @param host_set_flag: Flag for if the test should setup host env:
                0: do nothing
                1: do setup env
                2: do cleanup env
                3: setup and cleanup env
         @param kvm_params: a dict for kvm module parameters default value
+        @param vf_filter_re: Regex used to filter vf from lspci.
+        @param pf_filter_re: Regex used to filter pf from lspci.
         """
-        self.type = dev_type
+        self.type_list = []
         self.driver = driver
         self.driver_option = driver_option
-        if names:
-            self.name_list = names.split()
-        if devices_requested:
-            self.devices_requested = int(devices_requested)
-        else:
-            self.devices_requested = None
+        self.name_list = []
+        self.devices_requested = 0
+        self.dev_unbind_drivers = {}
+        self.dev_drivers = {}
+        self.vf_filter_re = vf_filter_re
+        self.pf_filter_re = pf_filter_re
         if host_set_flag is not None:
-            self.setup = host_set_flag & 1 == 1
-            self.cleanup = host_set_flag & 2 == 2
+            self.setup = int(host_set_flag) & 1 == 1
+            self.cleanup = int(host_set_flag) & 2 == 2
         else:
             self.setup = False
             self.cleanup = False
@@ -373,6 +372,20 @@ class PciAssignable(object):
                 if "allow_unsafe_assigned_interrupts" in i:
                     self.auai_path = i
 
+
+    def add_device(self, device_type="vf", name=None):
+        """
+        Add device type and name to class.
+
+        @param device_type: vf/pf device is added.
+        @param name:  Device name is need.
+        """
+        self.type_list.append(device_type)
+        if name is not None:
+            self.name_list.append(name)
+        self.devices_requested += 1
+
+
     def _get_pf_pci_id(self, name, search_str):
         """
         Get the PF PCI ID according to name.
@@ -392,6 +405,7 @@ class PciAssignable(object):
         return pci_ids[nic_id]
 
 
+    @error.context_aware
     def _release_dev(self, pci_id):
         """
         Release a single PCI device.
@@ -403,23 +417,46 @@ class PciAssignable(object):
         vendor_id = utils_misc.get_vendor_from_pci_id(pci_id)
         drv_path = os.path.join(base_dir, "devices/%s/driver" % full_id)
         if 'pci-stub' in os.readlink(drv_path):
-            cmd = "echo '%s' > %s/new_id" % (vendor_id, drv_path)
+            error.context("Release device %s to host" % pci_id, logging.info)
+            driver = self.dev_unbind_drivers[pci_id]
+            cmd = "echo '%s' > %s/new_id" % (vendor_id, driver)
+            logging.info("Run command in host: %s" % cmd)
             if os.system(cmd):
                 return False
 
             stub_path = os.path.join(base_dir, "drivers/pci-stub")
             cmd = "echo '%s' > %s/unbind" % (full_id, stub_path)
+            logging.info("Run command in host: %s" % cmd)
             if os.system(cmd):
                 return False
 
-            driver = self.dev_drivers[pci_id]
+            driver = self.dev_unbind_drivers[pci_id]
             cmd = "echo '%s' > %s/bind" % (full_id, driver)
+            logging.info("Run command in host: %s" % cmd)
             if os.system(cmd):
                 return False
-
         return True
 
 
+    def get_vf_status(self, vf_id):
+        """
+        Check whether one vf is assigned to VM.
+
+        vf_id: vf id to check.
+        @return: Return True if vf has already assinged to VM. Else
+        return false.
+        """
+        base_dir = "/sys/bus/pci"
+        tub_path = os.path.join(base_dir, "drivers/pci-stub")
+        vf_res_path = os.path.join(tub_path, "0000\:%s/resource*" % vf_id)
+        cmd = "lsof %s" % vf_res_path
+        output = utils.system_output(cmd, timeout=60, ignore_status=True)
+        if 'qemu' in output:
+            return True
+        else:
+            return False
+
+
     def get_vf_devs(self):
         """
         Catch all VFs PCI IDs.
@@ -429,8 +466,9 @@ class PciAssignable(object):
         if self.setup:
             if not self.sr_iov_setup():
                 return []
-        cmd = "lspci | awk '/Virtual Function/ {print $1}'"
-        return commands.getoutput(cmd).split()
+        self.setup = None
+        cmd = "lspci | awk '/%s/ {print $1}'" % self.vf_filter_re
+        return utils.system_output(cmd, verbose=False).split()
 
 
     def get_pf_devs(self):
@@ -441,28 +479,56 @@ class PciAssignable(object):
         """
         pf_ids = []
         for name in self.name_list:
-            pf_id = self._get_pf_pci_id(name, "Ethernet")
+            pf_id = self._get_pf_pci_id(name, "%s" % self.pf_filter_re)
             if not pf_id:
                 continue
             pf_ids.append(pf_id)
         return pf_ids
 
 
-    def get_devs(self, count):
+    def get_devs(self, count, type_list=None):
         """
         Check out all devices' PCI IDs according to their name.
 
         @param count: count number of PCI devices needed for pass through
         @return: a list of all devices' PCI IDs
         """
-        if self.type == "vf":
-            vf_ids = self.get_vf_devs()
-        elif self.type == "pf":
-            vf_ids = self.get_pf_devs()
-        elif self.type == "mixed":
-            vf_ids = self.get_vf_devs()
-            vf_ids.extend(self.get_pf_devs())
-        return vf_ids[0:count]
+        base_dir = "/sys/bus/pci"
+        if type_list is None:
+            type_list = self.type_list
+        vf_ids = self.get_vf_devs()
+        pf_ids = self.get_pf_devs()
+        vf_d = []
+        for pf_id in pf_ids:
+            for vf_id in vf_ids:
+                if vf_id[:2] == pf_id[:2] and\
+                    (int(vf_id[-1]) & 1 == int(pf_id[-1])):
+                    vf_d.append(vf_id)
+        for vf_id in vf_ids:
+            if self.get_vf_status(vf_id):
+                vf_d.append(vf_id)
+        for vf in vf_d:
+            vf_ids.remove(vf)
+        dev_ids = []
+        for i in range(count):
+            if type_list:
+                try:
+                    d_type = type_list[i]
+                except IndexError:
+                    d_type = "vf"
+            if d_type == "vf":
+                vf_id = vf_ids.pop(0)
+                dev_ids.append(vf_id)
+                self.dev_unbind_drivers[vf_id] = os.path.join(base_dir,
+                                                 "drivers/%svf" % self.driver)
+            elif d_type == "pf":
+                pf_id = pf_ids.pop(0)
+                dev_ids.append(pf_id)
+                self.dev_unbind_drivers[pf_id] = os.path.join(base_dir,
+                                                 "drivers/%s" % self.driver)
+        if len(dev_ids) != count:
+            logging.error("Did not get enough PCI Device")
+        return dev_ids
 
 
     def get_vfs_count(self):
@@ -472,8 +538,8 @@ class PciAssignable(object):
         # FIXME: Need to think out a method of identify which
         # 'virtual function' belongs to which physical card considering
         # that if the host has more than one 82576 card. PCI_ID?
-        cmd = "lspci | grep 'Virtual Function' | wc -l"
-        return int(commands.getoutput(cmd))
+        cmd = "lspci | grep '%s' | wc -l" % self.vf_filter_re
+        return int(utils.system_output(cmd, verbose=False))
 
 
     def check_vfs_count(self):
@@ -499,7 +565,7 @@ class PciAssignable(object):
             return True
         return False
 
-
+    @error.context_aware
     def sr_iov_setup(self):
         """
         Ensure the PCI device is working in sr_iov mode.
@@ -510,9 +576,11 @@ class PciAssignable(object):
         @return: True, if the setup was completed successfuly, False otherwise.
         """
         # Check if the host support interrupt remapping
+        error.context("Set up host env for PCI assign test", logging.info)
         kvm_re_probe = False
         o = utils.system_output("cat /var/log/dmesg")
         ecap = re.findall("ecap\s+(.\w+)", o)
+
         if ecap and int(ecap[0], 16) & 8 == 0:
             if self.kvm_params is not None:
                 if self.auai_path and self.kvm_params[self.auai_path] == "N":
@@ -531,7 +599,7 @@ class PciAssignable(object):
                         if self.kvm_params[i] == "Y":
                             params_name = os.path.split(i)[1]
                             cmd += " %s=1" % params_name
-            logging.info("Loading kvm with: %s" % cmd)
+            error.context("Loading kvm with: %s" % cmd, logging.info)
 
             try:
                 utils.system(cmd)
@@ -552,14 +620,15 @@ class PciAssignable(object):
         # Re-probe driver with proper number of VFs
         if re_probe:
             cmd = "modprobe %s %s" % (self.driver, self.driver_option)
-            logging.info("Loading the driver '%s' with option '%s'",
-                         self.driver, self.driver_option)
+            error.context("Loading the driver '%s' with command '%s'" %\
+                          (self.driver, cmd), logging.info)
             s, o = commands.getstatusoutput(cmd)
             utils.system("/etc/init.d/network restart", ignore_status=True)
             if s:
                 return False
             return True
 
+
     def sr_iov_cleanup(self):
         """
         Clean up the sriov setup
@@ -570,6 +639,7 @@ class PciAssignable(object):
         @return: True, if the setup was completed successfuly, False otherwise.
         """
         # Check if the host support interrupt remapping
+        error.context("Clean up host env after PCI assign test", logging.info)
         kvm_re_probe = False
         if self.kvm_params is not None:
             if (self.auai_path and
@@ -589,18 +659,22 @@ class PciAssignable(object):
                     if self.kvm_params[i] == "Y":
                         params_name = os.path.split(i)[1]
                         cmd += " %s=1" % params_name
-            logging.info("Loading kvm with: %s" % cmd)
+            logging.info("Loading kvm with command: %s" % cmd)
 
             try:
                 utils.system(cmd)
             except Exception:
                 logging.debug("Failed to reload kvm")
-            utils.system("modprobe %s" % kvm_arch)
+            cmd = "modprobe %s" % kvm_arch
+            logging.info("Loading %s with command: %s" % (kvm_arch, cmd))
+            utils.system(cmd)
 
         re_probe = False
-        s = commands.getstatus('lsmod | grep %s' % self.driver)
+        s, o = commands.getstatusoutput('lsmod | grep %s' % self.driver)
         if s:
-            os.system("modprobe -r %s" % self.driver)
+            cmd = "modprobe -r %s" % self.driver
+            logging.info("Running host command: %s" % cmd)
+            os.system(cmd)
             re_probe = True
         else:
             return True
@@ -608,29 +682,35 @@ class PciAssignable(object):
         # Re-probe driver with proper number of VFs
         if re_probe:
             cmd = "modprobe %s" % self.driver
-            logging.info("Loading the driver '%s' without option", self.driver)
-            s = commands.getstatus(cmd)
+            msg = "Loading the driver '%s' without option" % self.driver
+            error.context(msg, logging.info)
+            s, o = commands.getstatusoutput(cmd)
             utils.system("/etc/init.d/network restart", ignore_status=True)
             if s:
                 return False
             return True
-    def request_devs(self):
+
+
+    def request_devs(self, count=None):
         """
         Implement setup process: unbind the PCI device and then bind it
         to the pci-stub driver.
 
+        @param count: count number of PCI devices needed for pass through
+
         @return: a list of successfully requested devices' PCI IDs.
         """
+        if count is None:
+            count = self.devices_requested
         base_dir = "/sys/bus/pci"
         stub_path = os.path.join(base_dir, "drivers/pci-stub")
 
-        self.pci_ids = self.get_devs(self.devices_requested)
-        logging.debug("The following pci_ids were found: %s", self.pci_ids)
+        pci_ids = self.get_devs(count)
+        logging.info("The following pci_ids were found: %s", pci_ids)
         requested_pci_ids = []
-        self.dev_drivers = {}
 
         # Setup all devices specified for assignment to guest
-        for pci_id in self.pci_ids:
+        for pci_id in pci_ids:
             full_id = utils_misc.get_full_pci_id(pci_id)
             if not full_id:
                 continue
@@ -641,7 +721,7 @@ class PciAssignable(object):
 
             # Judge whether the device driver has been binded to stub
             if not self.is_binded_to_stub(full_id):
-                logging.debug("Binding device %s to stub", full_id)
+                error.context("Bind device %s to stub" % full_id, logging.info)
                 vendor_id = utils_misc.get_vendor_from_pci_id(pci_id)
                 stub_new_id = os.path.join(stub_path, 'new_id')
                 unbind_dev = os.path.join(drv_path, 'unbind')
@@ -651,12 +731,12 @@ class PciAssignable(object):
                                        (full_id, unbind_dev),
                                        (full_id, stub_bind)]
 
-                for content, filename in info_write_to_files:
+                for content, file in info_write_to_files:
                     try:
-                        utils.open_write_close(filename, content)
+                        utils.open_write_close(file, content)
                     except IOError:
                         logging.debug("Failed to write %s to file %s", content,
-                                      filename)
+                                      file)
                         continue
 
                 if not self.is_binded_to_stub(full_id):
@@ -665,10 +745,10 @@ class PciAssignable(object):
             else:
                 logging.debug("Device %s already binded to stub", pci_id)
             requested_pci_ids.append(pci_id)
-        self.pci_ids = requested_pci_ids
-        return self.pci_ids
+        return requested_pci_ids
 
 
+    @error.context_aware
     def release_devs(self):
         """
         Release all PCI devices currently assigned to VMs back to the
@@ -681,7 +761,9 @@ class PciAssignable(object):
                 else:
                     logging.info("Released device %s successfully", pci_id)
             if self.cleanup:
-                logging.info("Clean up host env for PCI assign test")
                 self.sr_iov_cleanup()
+                self.type_list = []
+                self.devices_requested = 0
+                self.dev_unbind_drivers = {}
         except Exception:
             return
-- 
1.7.1

_______________________________________________
Autotest-kernel mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/autotest-kernel

Reply via email to