+ pids[node['host']] = DUTSetup.get_vpp_pid(node)
+ return pids
+
+ @staticmethod
+ def crypto_device_verify(node, crypto_type, numvfs, force_init=False):
+ """Verify if Crypto QAT device virtual functions are initialized on all
+ DUTs. If parameter force initialization is set to True, then try to
+ initialize or remove VFs on QAT.
+
+ :param node: DUT node.
+ :crypto_type: Crypto device type - HW_DH895xcc or HW_C3xxx.
+ :param numvfs: Number of VFs to initialize, 0 - disable the VFs.
+ :param force_init: If True then try to initialize to specific value.
+ :type node: dict
+ :type crypto_type: string
+ :type numvfs: int
+ :type force_init: bool
+ :returns: nothing
+ :raises RuntimeError: If QAT VFs are not created and force init is set
+ to False.
+ """
+ pci_addr = Topology.get_cryptodev(node)
+ sriov_numvfs = DUTSetup.get_sriov_numvfs(node, pci_addr)
+
+ if sriov_numvfs != numvfs:
+ if force_init:
+ # QAT is not initialized and we want to initialize with numvfs
+ DUTSetup.crypto_device_init(node, crypto_type, numvfs)
+ else:
+ raise RuntimeError('QAT device failed to create VFs on {host}'.
+ format(host=node['host']))
+
+ @staticmethod
+ def crypto_device_init(node, crypto_type, numvfs):
+ """Init Crypto QAT device virtual functions on DUT.
+
+ :param node: DUT node.
+ :crypto_type: Crypto device type - HW_DH895xcc or HW_C3xxx.
+ :param numvfs: Number of VFs to initialize, 0 - disable the VFs.
+ :type node: dict
+ :type crypto_type: string
+ :type numvfs: int
+ :returns: nothing
+ :raises RuntimeError: If failed to stop VPP or QAT failed to initialize.
+ """
+ if crypto_type == "HW_DH895xcc":
+ kernel_mod = "qat_dh895xcc"
+ kernel_drv = "dh895xcc"
+ elif crypto_type == "HW_C3xxx":
+ kernel_mod = "qat_c3xxx"
+ kernel_drv = "c3xxx"
+ else:
+ raise RuntimeError('Unsupported crypto device type on {host}'.
+ format(host=node['host']))
+
+ pci_addr = Topology.get_cryptodev(node)
+
+ # QAT device must be re-bound to kernel driver before initialization.
+ DUTSetup.verify_kernel_module(node, kernel_mod, force_load=True)
+
+ # Stop VPP to prevent deadlock.
+ DUTSetup.stop_service(node, Constants.VPP_UNIT)
+
+ current_driver = DUTSetup.get_pci_dev_driver(
+ node, pci_addr.replace(':', r'\:'))
+ if current_driver is not None:
+ DUTSetup.pci_driver_unbind(node, pci_addr)
+
+ # Bind to kernel driver.
+ DUTSetup.pci_driver_bind(node, pci_addr, kernel_drv)
+
+ # Initialize QAT VFs.
+ if numvfs > 0:
+ DUTSetup.set_sriov_numvfs(node, pci_addr, numvfs)
+
+ @staticmethod
+ def get_virtfn_pci_addr(node, pf_pci_addr, vf_id):
+ """Get PCI address of Virtual Function.
+
+ :param node: DUT node.
+ :param pf_pci_addr: Physical Function PCI address.
+ :param vf_id: Virtual Function number.
+ :type node: dict
+ :type pf_pci_addr: str
+ :type vf_id: int
+ :returns: Virtual Function PCI address.
+ :rtype: int
+ :raises RuntimeError: If failed to get Virtual Function PCI address.
+ """
+ command = "sh -c "\
+ "'basename $(readlink /sys/bus/pci/devices/{pci}/virtfn{vf_id})'".\
+ format(pci=pf_pci_addr, vf_id=vf_id)
+ message = 'Failed to get virtual function PCI address.'
+
+ stdout, _ = exec_cmd_no_error(node, command, timeout=30, sudo=True,
+ message=message)
+
+ return stdout.strip()
+
+ @staticmethod
+ def get_sriov_numvfs(node, pf_pci_addr):
+ """Get number of SR-IOV VFs.
+
+ :param node: DUT node.
+ :param pf_pci_addr: Physical Function PCI device address.
+ :type node: dict
+ :type pf_pci_addr: str
+ :returns: Number of VFs.
+ :rtype: int
+ :raises RuntimeError: If PCI device is not SR-IOV capable.
+ """
+ command = 'cat /sys/bus/pci/devices/{pci}/sriov_numvfs'.\
+ format(pci=pf_pci_addr.replace(':', r'\:'))
+ message = 'PCI device {pci} is not a SR-IOV device.'.\
+ format(pci=pf_pci_addr)
+
+ for _ in range(3):
+ stdout, _ = exec_cmd_no_error(node, command, timeout=30, sudo=True,
+ message=message)
+ try:
+ sriov_numvfs = int(stdout)
+ except ValueError:
+ logger.trace('Reading sriov_numvfs info failed on {host}'.
+ format(host=node['host']))
+ else:
+ return sriov_numvfs
+
+ @staticmethod
+ def set_sriov_numvfs(node, pf_pci_addr, numvfs=0):
+ """Init or reset SR-IOV virtual functions by setting its number on PCI
+ device on DUT. Setting to zero removes all VFs.
+
+ :param node: DUT node.
+ :param pf_pci_addr: Physical Function PCI device address.
+ :param numvfs: Number of VFs to initialize, 0 - removes the VFs.
+ :type node: dict
+ :type pf_pci_addr: str
+ :type numvfs: int
+ :raises RuntimeError: Failed to create VFs on PCI.
+ """
+ command = "sh -c "\
+ "'echo {num} | tee /sys/bus/pci/devices/{pci}/sriov_numvfs'".\
+ format(num=numvfs, pci=pf_pci_addr.replace(':', r'\:'))
+ message = 'Failed to create {num} VFs on {pci} device on {host}'.\
+ format(num=numvfs, pci=pf_pci_addr, host=node['host'])
+
+ exec_cmd_no_error(node, command, timeout=120, sudo=True,
+ message=message)
+
+ @staticmethod
+ def pci_driver_unbind(node, pci_addr):
+ """Unbind PCI device from current driver on node.
+
+ :param node: DUT node.
+ :param pci_addr: PCI device address.
+ :type node: dict
+ :type pci_addr: str
+ :raises RuntimeError: If PCI device unbind failed.
+ """
+ command = "sh -c "\
+ "'echo {pci} | tee /sys/bus/pci/devices/{pcie}/driver/unbind'".\
+ format(pci=pci_addr, pcie=pci_addr.replace(':', r'\:'))
+ message = 'Failed to unbind PCI device {pci} on {host}'.\
+ format(pci=pci_addr, host=node['host'])
+
+ exec_cmd_no_error(node, command, timeout=120, sudo=True,
+ message=message)
+
+ @staticmethod
+ def pci_driver_bind(node, pci_addr, driver):
+ """Bind PCI device to driver on node.
+
+ :param node: DUT node.
+ :param pci_addr: PCI device address.
+ :param driver: Driver to bind.
+ :type node: dict
+ :type pci_addr: str
+ :type driver: str
+ :raises RuntimeError: If PCI device bind failed.
+ """
+ message = 'Failed to bind PCI device {pci} to {driver} on host {host}'.\
+ format(pci=pci_addr, driver=driver, host=node['host'])
+
+ command = "sh -c "\
+ "'echo {driver} | tee /sys/bus/pci/devices/{pci}/driver_override'".\
+ format(driver=driver, pci=pci_addr.replace(':', r'\:'))
+
+ exec_cmd_no_error(node, command, timeout=120, sudo=True,
+ message=message)
+
+ command = "sh -c "\
+ "'echo {pci} | tee /sys/bus/pci/drivers/{driver}/bind'".\
+ format(pci=pci_addr, driver=driver)
+
+ exec_cmd_no_error(node, command, timeout=120, sudo=True,
+ message=message)
+
+ command = "sh -c "\
+ "'echo | tee /sys/bus/pci/devices/{pci}/driver_override'".\
+ format(pci=pci_addr.replace(':', r'\:'))
+
+ exec_cmd_no_error(node, command, timeout=120, sudo=True,
+ message=message)
+
+ @staticmethod
+ def pci_vf_driver_unbind(node, pf_pci_addr, vf_id):
+ """Unbind Virtual Function from driver on node.
+
+ :param node: DUT node.
+ :param pf_pci_addr: PCI device address.
+ :param vf_id: Virtual Function ID.
+ :type node: dict
+ :type pf_pci_addr: str
+ :type vf_id: int
+ :raises RuntimeError: If Virtual Function unbind failed.
+ """
+ vf_pci_addr = DUTSetup.get_virtfn_pci_addr(node, pf_pci_addr, vf_id)
+ vf_path = "/sys/bus/pci/devices/{pf_pci_addr}/virtfn{vf_id}".\
+ format(pf_pci_addr=pf_pci_addr.replace(':', r'\:'), vf_id=vf_id)
+
+ command = "sh -c "\
+ "'echo {vf_pci_addr} | tee {vf_path}/driver/unbind'".\
+ format(vf_pci_addr=vf_pci_addr, vf_path=vf_path)
+
+ message = 'Failed to unbind VF {vf_pci_addr} to on {host}'.\
+ format(vf_pci_addr=vf_pci_addr, host=node['host'])
+
+ exec_cmd_no_error(node, command, timeout=120, sudo=True,
+ message=message)
+
+ @staticmethod
+ def pci_vf_driver_bind(node, pf_pci_addr, vf_id, driver):
+ """Bind Virtual Function to driver on node.
+
+ :param node: DUT node.
+ :param pf_pci_addr: PCI device address.
+ :param vf_id: Virtual Function ID.
+ :param driver: Driver to bind.
+ :type node: dict
+ :type pf_pci_addr: str
+ :type vf_id: int
+ :type driver: str
+ :raises RuntimeError: If PCI device bind failed.
+ """
+ vf_pci_addr = DUTSetup.get_virtfn_pci_addr(node, pf_pci_addr, vf_id)
+ vf_path = "/sys/bus/pci/devices/{pf_pci_addr}/virtfn{vf_id}".\
+ format(pf_pci_addr=pf_pci_addr.replace(':', r'\:'), vf_id=vf_id)
+
+ message = 'Failed to bind VF {vf_pci_addr} to {driver} on {host}'.\
+ format(vf_pci_addr=vf_pci_addr, driver=driver, host=node['host'])
+
+ command = "sh -c "\
+ "'echo {driver} | tee {vf_path}/driver_override'".\
+ format(driver=driver, vf_path=vf_path)
+
+ exec_cmd_no_error(node, command, timeout=120, sudo=True,
+ message=message)
+
+ command = "sh -c "\
+ "'echo {vf_pci_addr} | tee /sys/bus/pci/drivers/{driver}/bind'".\
+ format(vf_pci_addr=vf_pci_addr, driver=driver)
+
+ exec_cmd_no_error(node, command, timeout=120, sudo=True,
+ message=message)
+
+ command = "sh -c "\
+ "'echo | tee {vf_path}/driver_override'".\
+ format(vf_path=vf_path)
+
+ exec_cmd_no_error(node, command, timeout=120, sudo=True,
+ message=message)
+
+ @staticmethod
+ def get_pci_dev_driver(node, pci_addr):
+ """Get current PCI device driver on node.
+
+ .. note::
+ # lspci -vmmks 0000:00:05.0
+ Slot: 00:05.0
+ Class: Ethernet controller
+ Vendor: Red Hat, Inc
+ Device: Virtio network device
+ SVendor: Red Hat, Inc
+ SDevice: Device 0001
+ PhySlot: 5
+ Driver: virtio-pci
+
+ :param node: DUT node.
+ :param pci_addr: PCI device address.
+ :type node: dict
+ :type pci_addr: str
+ :returns: Driver or None
+ :raises RuntimeError: If PCI rescan or lspci command execution failed.
+ :raises RuntimeError: If it is not possible to get the interface driver
+ information from the node.
+ """
+ ssh = SSH()
+ ssh.connect(node)
+
+ for i in range(3):
+ logger.trace('Try number {0}: Get PCI device driver'.format(i))
+
+ cmd = 'lspci -vmmks {0}'.format(pci_addr)
+ ret_code, stdout, _ = ssh.exec_command(cmd)
+ if int(ret_code):
+ raise RuntimeError("'{0}' failed on '{1}'"
+ .format(cmd, node['host']))
+
+ for line in stdout.splitlines():
+ if not line:
+ continue
+ name = None
+ value = None
+ try:
+ name, value = line.split("\t", 1)
+ except ValueError:
+ if name == "Driver:":
+ return None
+ if name == 'Driver:':
+ return value
+
+ if i < 2:
+ logger.trace('Driver for PCI device {} not found, executing '
+ 'pci rescan and retrying'.format(pci_addr))
+ cmd = 'sh -c "echo 1 > /sys/bus/pci/rescan"'
+ ret_code, _, _ = ssh.exec_command_sudo(cmd)