X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;ds=sidebyside;f=resources%2Flibraries%2Fpython%2FDUTSetup.py;h=632e9ea073923e814d44b700c8783cd3bbc99066;hb=92d4e47bfbca31e10c44dee7f74da4c6fd9e6e4c;hp=9c78cfe6aa73e5245d812163109251197d5d8156;hpb=4c6fe5602edcbd9857a846e5b13a21d5c671a2c8;p=csit.git diff --git a/resources/libraries/python/DUTSetup.py b/resources/libraries/python/DUTSetup.py index 9c78cfe6aa..632e9ea073 100644 --- a/resources/libraries/python/DUTSetup.py +++ b/resources/libraries/python/DUTSetup.py @@ -385,24 +385,31 @@ class DUTSetup(object): 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 {0}: Get interface driver'.format(i)) - cmd = 'sh -c "echo 1 > /sys/bus/pci/rescan"' - ret_code, _, _ = ssh.exec_command_sudo(cmd) - if int(ret_code) != 0: - raise RuntimeError("'{0}' failed on '{1}'" - .format(cmd, node['host'])) - + 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) != 0: @@ -421,24 +428,31 @@ class DUTSetup(object): return None if name == 'Driver:': return value - else: - return None + + 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) + if int(ret_code) != 0: + raise RuntimeError("'{0}' failed on '{1}'" + .format(cmd, node['host'])) + + return None @staticmethod def kernel_module_verify(node, module, force_load=False): - """Verify if kernel module is loaded on all DUTs. If parameter force + """Verify if kernel module is loaded on node. If parameter force load is set to True, then try to load the modules. - :param node: DUT node. + :param node: Node. :param module: Module to verify. :param force_load: If True then try to load module. :type node: dict :type module: str :type force_load: bool - :returns: nothing :raises RuntimeError: If module is not loaded or failed to load. """ - ssh = SSH() ssh.connect(node) @@ -453,6 +467,35 @@ class DUTSetup(object): raise RuntimeError('Kernel module {0} is not loaded on host ' '{1}'.format(module, node['host'])) + @staticmethod + def kernel_module_verify_on_all_duts(nodes, module, force_load=False): + """Verify if kernel module is loaded on all DUTs. If parameter force + load is set to True, then try to load the modules. + + :param node: DUT nodes. + :param module: Module to verify. + :param force_load: If True then try to load module. + :type node: dict + :type module: str + :type force_load: bool + """ + for node in nodes.values(): + if node['type'] == NodeType.DUT: + DUTSetup.kernel_module_verify(node, module, force_load) + + @staticmethod + def verify_uio_driver_on_all_duts(nodes): + """Verify if uio driver kernel module is loaded on all DUTs. If module + is not present it will try to load it. + + :param node: DUT nodes. + :type node: dict + """ + for node in nodes.values(): + if node['type'] == NodeType.DUT: + uio_driver = Topology.get_uio_driver(node) + DUTSetup.kernel_module_verify(node, uio_driver, force_load=True) + @staticmethod def kernel_module_load(node, module): """Load kernel module on node. @@ -600,3 +643,169 @@ class DUTSetup(object): DUTSetup.vpp_show_version_verbose(node) DUTSetup.vpp_show_interfaces(node) + + @staticmethod + def get_huge_page_size(node): + """Get default size of huge pages in system. + + :param node: Node in the topology. + :type node: dict + :returns: Default size of free huge pages in system. + :rtype: int + :raises RuntimeError: If reading failed for three times. + """ + ssh = SSH() + ssh.connect(node) + + for _ in range(3): + ret_code, stdout, _ = ssh.exec_command_sudo( + "grep Hugepagesize /proc/meminfo | awk '{ print $2 }'") + if ret_code == 0: + try: + huge_size = int(stdout) + except ValueError: + logger.trace('Reading huge page size information failed') + else: + break + else: + raise RuntimeError('Getting huge page size information failed.') + return huge_size + + @staticmethod + def get_huge_page_free(node, huge_size): + """Get number of free huge pages in system. + + :param node: Node in the topology. + :param huge_size: Size of hugepages. + :type node: dict + :type huge_size: int + :returns: Number of free huge pages in system. + :rtype: int + :raises RuntimeError: If reading failed for three times. + """ + # TODO: add numa aware option + ssh = SSH() + ssh.connect(node) + + for _ in range(3): + ret_code, stdout, _ = ssh.exec_command_sudo( + 'cat /sys/kernel/mm/hugepages/hugepages-{0}kB/free_hugepages'. + format(huge_size)) + if ret_code == 0: + try: + huge_free = int(stdout) + except ValueError: + logger.trace('Reading free huge pages information failed') + else: + break + else: + raise RuntimeError('Getting free huge pages information failed.') + return huge_free + + @staticmethod + def get_huge_page_total(node, huge_size): + """Get total number of huge pages in system. + + :param node: Node in the topology. + :param huge_size: Size of hugepages. + :type node: dict + :type huge_size: int + + :returns: Total number of huge pages in system. + :rtype: int + :raises RuntimeError: If reading failed for three times. + """ + # TODO: add numa aware option + ssh = SSH() + ssh.connect(node) + + for _ in range(3): + ret_code, stdout, _ = ssh.exec_command_sudo( + 'cat /sys/kernel/mm/hugepages/hugepages-{0}kB/nr_hugepages'. + format(huge_size)) + if ret_code == 0: + try: + huge_total = int(stdout) + except ValueError: + logger.trace('Reading total huge pages information failed') + else: + break + else: + raise RuntimeError('Getting total huge pages information failed.') + return huge_total + + @staticmethod + def check_huge_page(node, huge_mnt, mem_size, allocate=False): + """Check if there is enough HugePages in system. If allocate is set to + true, try to allocate more HugePages. + + :param node: Node in the topology. + :param huge_mnt: HugePage mount point. + :param mem_size: Requested memory in MB. + :param allocate: Whether to allocate more memory if not enough. + :type node: dict + :type huge_mnt: str + :type mem_size: str + :type allocate: bool + + :raises RuntimeError: Mounting hugetlbfs failed or not enough HugePages + or increasing map count failed. + """ + # TODO: split function into smaller parts. + ssh = SSH() + ssh.connect(node) + + # Get huge pages information + huge_size = DUTSetup.get_huge_page_size(node) + huge_free = DUTSetup.get_huge_page_free(node, huge_size) + huge_total = DUTSetup.get_huge_page_total(node, huge_size) + + # Check if memory reqested is available on host + if (mem_size * 1024) > (huge_free * huge_size): + # If we want to allocate hugepage dynamically + if allocate: + mem_needed = (mem_size * 1024) - (huge_free * huge_size) + huge_to_allocate = ((mem_needed / huge_size) * 2) + huge_total + max_map_count = huge_to_allocate*4 + # Increase maximum number of memory map areas a process may have + ret_code, _, _ = ssh.exec_command_sudo( + 'echo "{0}" | sudo tee /proc/sys/vm/max_map_count'. + format(max_map_count)) + if int(ret_code) != 0: + raise RuntimeError('Increase map count failed on {host}'. + format(host=node['host'])) + # Increase hugepage count + ret_code, _, _ = ssh.exec_command_sudo( + 'echo "{0}" | sudo tee /proc/sys/vm/nr_hugepages'. + format(huge_to_allocate)) + if int(ret_code) != 0: + raise RuntimeError('Mount huge pages failed on {host}'. + format(host=node['host'])) + # If we do not want to allocate dynamicaly end with error + else: + raise RuntimeError('Not enough free huge pages: {0}, {1} MB'. + format(huge_free, huge_free * huge_size)) + # Check if huge pages mount point exist + has_huge_mnt = False + ret_code, stdout, _ = ssh.exec_command('cat /proc/mounts') + if int(ret_code) == 0: + for line in stdout.splitlines(): + # Try to find something like: + # none /mnt/huge hugetlbfs rw,relatime,pagesize=2048k 0 0 + mount = line.split() + if mount[2] == 'hugetlbfs' and mount[1] == huge_mnt: + has_huge_mnt = True + break + # If huge page mount point not exist create one + if not has_huge_mnt: + ret_code, _, _ = ssh.exec_command_sudo( + 'mkdir -p {mnt}'.format(mnt=huge_mnt)) + if int(ret_code) != 0: + raise RuntimeError('Create mount dir failed on {host}'. + format(host=node['host'])) + ret_code, _, _ = ssh.exec_command_sudo( + 'mount -t hugetlbfs -o pagesize=2048k none {mnt}'. + format(mnt=huge_mnt)) + if int(ret_code) != 0: + raise RuntimeError('Mount huge pages failed on {host}'. + format(host=node['host']))