+ exec_cmd_no_error(node, command, timeout=30, sudo=True, message=message)
+
+ @staticmethod
+ def install_vpp_on_all_duts(nodes, vpp_pkg_dir):
+ """Install VPP on all DUT nodes. Start the VPP service in case of
+ systemd is not available or does not support autostart.
+
+ :param nodes: Nodes in the topology.
+ :param vpp_pkg_dir: Path to directory where VPP packages are stored.
+ :type nodes: dict
+ :type vpp_pkg_dir: str
+ :raises RuntimeError: If failed to remove or install VPP.
+ """
+ for node in nodes.values():
+ message = f"Failed to install VPP on host {node[u'host']}!"
+ if node[u"type"] == NodeType.DUT:
+ command = u"ln -s /dev/null /etc/sysctl.d/80-vpp.conf || true"
+ exec_cmd_no_error(node, command, sudo=True)
+
+ command = u". /etc/lsb-release; echo \"${DISTRIB_ID}\""
+ stdout, _ = exec_cmd_no_error(node, command)
+
+ if stdout.strip() == u"Ubuntu":
+ exec_cmd_no_error(
+ node, u"apt-get purge -y '*vpp*' || true",
+ timeout=120, sudo=True
+ )
+ # workaround to avoid installation of vpp-api-python
+ exec_cmd_no_error(
+ node, u"rm -f {vpp_pkg_dir}vpp-api-python.deb",
+ timeout=120, sudo=True
+ )
+ exec_cmd_no_error(
+ node, f"dpkg -i --force-all {vpp_pkg_dir}*.deb",
+ timeout=120, sudo=True, message=message
+ )
+ exec_cmd_no_error(node, u"dpkg -l | grep vpp", sudo=True)
+ if DUTSetup.running_in_container(node):
+ DUTSetup.restart_service(node, Constants.VPP_UNIT)
+ else:
+ exec_cmd_no_error(
+ node, u"yum -y remove '*vpp*' || true",
+ timeout=120, sudo=True
+ )
+ # workaround to avoid installation of vpp-api-python
+ exec_cmd_no_error(
+ node, u"rm -f {vpp_pkg_dir}vpp-api-python.rpm",
+ timeout=120, sudo=True
+ )
+ exec_cmd_no_error(
+ node, f"rpm -ivh {vpp_pkg_dir}*.rpm",
+ timeout=120, sudo=True, message=message
+ )
+ exec_cmd_no_error(node, u"rpm -qai *vpp*", sudo=True)
+ DUTSetup.restart_service(node, Constants.VPP_UNIT)
+
+ @staticmethod
+ def running_in_container(node):
+ """This method tests if topology node is running inside container.
+
+ :param node: Topology node.
+ :type node: dict
+ :returns: True if running in docker container, false if not or failed
+ to detect.
+ :rtype: bool
+ """
+ command = u"fgrep docker /proc/1/cgroup"
+ message = u"Failed to get cgroup settings."
+ try:
+ exec_cmd_no_error(
+ node, command, timeout=30, sudo=False, message=message
+ )
+ except RuntimeError:
+ return False
+ return True
+
+ @staticmethod
+ def get_docker_mergeddir(node, uuid):
+ """Get Docker overlay for MergedDir diff.
+
+ :param node: DUT node.
+ :param uuid: Docker UUID.
+ :type node: dict
+ :type uuid: str
+ :returns: Docker container MergedDir.
+ :rtype: str
+ :raises RuntimeError: If getting output failed.
+ """
+ command = f"docker inspect " \
+ f"--format='{{{{.GraphDriver.Data.MergedDir}}}}' {uuid}"
+ message = f"Failed to get directory of {uuid} on host {node[u'host']}"
+
+ stdout, _ = exec_cmd_no_error(node, command, sudo=True, message=message)
+ return stdout.strip()
+
+ @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(
+ u"grep Hugepagesize /proc/meminfo | awk '{ print $2 }'"
+ )
+ if ret_code == 0:
+ try:
+ huge_size = int(stdout)
+ except ValueError:
+ logger.trace(u"Reading huge page size information failed")
+ else:
+ break
+ else:
+ raise RuntimeError(u"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(
+ f"cat /sys/kernel/mm/hugepages/hugepages-{huge_size}kB/"
+ f"free_hugepages"
+ )
+ if ret_code == 0:
+ try:
+ huge_free = int(stdout)
+ except ValueError:
+ logger.trace(u"Reading free huge pages information failed")
+ else:
+ break
+ else:
+ raise RuntimeError(u"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