def set_proc_scheduling_rr(node, pid, priority=1): """Set real-time scheduling of a process to SCHED_RR with priority for specified PID. :param node: Node where to apply scheduling changes. :param pid: Process ID. :param priority: Realtime priority in range 1-99. Default is 1. :type node: dict :type pid: int :type priority: int :raises ValueError: Parameters out of allowed ranges. :raises RuntimeError: Failed to set policy for PID. """ ssh = SSH() ssh.connect(node) if pid < 1: raise ValueError(u"SCHED_RR: PID must be higher then 1.") if 1 <= priority <= 99: cmd = f"chrt -r -p {priority} {pid}" ret, _, _ = ssh.exec_command_sudo(cmd) if ret != 0: raise RuntimeError( f"SCHED_RR: Failed to set policy for PID {pid}.") else: raise ValueError(u"SCHED_RR: Priority must be in range 1-99.")
def stop_honeycomb_on_duts(*nodes): """Stop the Honeycomb service on specified DUT nodes. This keyword stops the Honeycomb service on specified nodes. It just stops the Honeycomb and does not check its shutdown state. Use the keyword "Check Honeycomb Shutdown State" to check if Honeycomb has stopped. :param nodes: List of nodes to stop Honeycomb on. :type nodes: list :raises HoneycombError: If Honeycomb failed to stop. """ cmd = "sudo service honeycomb stop" errors = [] for node in nodes: if node['type'] == NodeType.DUT: logger.console( "\nShutting down Honeycomb service on node {0}".format( node["host"])) ssh = SSH() ssh.connect(node) (ret_code, _, _) = ssh.exec_command_sudo(cmd) if int(ret_code) != 0: errors.append(node['host']) else: logger.info( "Stopping the Honeycomb service on node {0} is " "in progress ...".format(node['host'])) if errors: raise HoneycombError( 'Node(s) {0} failed to stop Honeycomb.'.format(errors))
def clear_persisted_honeycomb_config(*nodes): """Remove configuration data persisted from last Honeycomb session. Default configuration will be used instead. :param nodes: List of DUTs to execute on. :type nodes: list :raises HoneycombError: If persisted configuration could not be removed. """ cmd = "rm -rf {}/*".format(Const.REMOTE_HC_PERSIST) for node in nodes: if node['type'] == NodeType.DUT: ssh = SSH() ssh.connect(node) (ret_code, _, stderr) = ssh.exec_command_sudo(cmd) if ret_code != 0: if "No such file or directory" not in stderr: raise HoneycombError( 'Could not clear persisted ' 'configuration on node {0}, {1}'.format( node['host'], stderr)) else: logger.info("Persistence data was not present on node" " {0}".format(node['host'])) else: logger.info("Persistence files removed on node {0}".format( node['host']))
def install_odl_features(node, path, *features): """Install required features on a running ODL client. :param node: Honeycomb node. :param path: Path to ODL client on node. :param features: Optional, list of additional features to install. :type node: dict :type path: str :type features: list """ ssh = SSH() ssh.connect(node) cmd = "{path}/*karaf*/bin/client -u karaf feature:install " \ "odl-restconf-all " \ "odl-netconf-connector-all " \ "odl-netconf-topology".format(path=path) for feature in features: cmd += " {0}".format(feature) ret_code, _, _ = ssh.exec_command_sudo(cmd, timeout=250) if int(ret_code) != 0: raise HoneycombError("Feature install did not succeed.")
def stop_odl_client(node, path): """Stop ODL client service on the specified node. :param node: Node to start ODL client on. :param path: Path to ODL client. :type node: dict :type path: str :raises HoneycombError: If ODL client fails to stop. """ ssh = SSH() ssh.connect(node) cmd = "{0}/*karaf*/bin/stop".format(path) ssh = SSH() ssh.connect(node) ret_code, _, _ = ssh.exec_command_sudo(cmd) if int(ret_code) != 0: logger.debug("ODL Client refused to shut down.") cmd = "pkill -f 'karaf'" (ret_code, _, _) = ssh.exec_command_sudo(cmd) if int(ret_code) != 0: raise HoneycombError('Node {0} failed to stop ODL.'.format( node['host'])) logger.info("ODL client service stopped.")
def configure_restconf_binding_address(node): """Configure Honeycomb to accept restconf requests from all IP addresses. IP version is determined by node data. :param node: Information about a DUT node. :type node: dict :raises HoneycombError: If the configuration could not be changed. """ find = "restconf-binding-address" try: IPv6Address(unicode(node["host"])) # if management IP of the node is in IPv6 format replace = '\\"restconf-binding-address\\": \\"0::0\\",' except (AttributeError, AddressValueError): replace = '\\"restconf-binding-address\\": \\"0.0.0.0\\",' argument = '"/{0}/c\\ {1}"'.format(find, replace) path = "{0}/config/restconf.json".format(Const.REMOTE_HC_DIR) command = "sed -i {0} {1}".format(argument, path) ssh = SSH() ssh.connect(node) (ret_code, _, stderr) = ssh.exec_command_sudo(command) if ret_code != 0: raise HoneycombError("Failed to modify configuration on " "node {0}, {1}".format(node, stderr))
def start_honeycomb_on_duts(*nodes): """Start Honeycomb on specified DUT nodes. This keyword starts the Honeycomb service on specified DUTs. The keyword just starts the Honeycomb and does not check its startup state. Use the keyword "Check Honeycomb Startup State" to check if the Honeycomb is up and running. Honeycomb must be installed in "/opt" directory, otherwise the start will fail. :param nodes: List of nodes to start Honeycomb on. :type nodes: list :raises HoneycombError: If Honeycomb fails to start. """ HoneycombSetup.print_environment(nodes) cmd = "sudo service honeycomb start" for node in nodes: if node['type'] == NodeType.DUT: logger.console( "\n(re)Starting Honeycomb service on node {0}".format( node["host"])) ssh = SSH() ssh.connect(node) (ret_code, _, _) = ssh.exec_command_sudo(cmd) if int(ret_code) != 0: raise HoneycombError( 'Node {0} failed to start Honeycomb.'.format( node['host'])) else: logger.info( "Starting the Honeycomb service on node {0} is " "in progress ...".format(node['host']))
def restart_vpp_in_container(self): """Restart vpp service inside a container.""" ssh = SSH() ssh.connect(self._node) self.lxc_attach('service vpp restart')
def vpp_ip_probe(node, interface, addr, if_type="key"): """Run ip probe on VPP node. :param node: VPP node. :param interface: Interface key or name. :param addr: IPv4/IPv6 address. :param if_type: Interface type :type node: dict :type interface: str :type addr: str :type if_type: str :raises ValueError: If the if_type is unknown. :raises Exception: If vpp probe fails. """ ssh = SSH() ssh.connect(node) if if_type == "key": iface_name = Topology.get_interface_name(node, interface) elif if_type == "name": iface_name = interface else: raise ValueError("if_type unknown: {0}".format(if_type)) cmd = "{c}".format(c=Constants.VAT_BIN_NAME) cmd_input = 'exec ip probe {dev} {ip}'.format(dev=iface_name, ip=addr) (ret_code, _, _) = ssh.exec_command_sudo(cmd, cmd_input) if int(ret_code) != 0: raise Exception('VPP ip probe {dev} {ip} failed on {h}'.format( dev=iface_name, ip=addr, h=node['host']))
def _lxc_cgroup(self, state_object, value=''): """Manage the control group associated with a container. :param state_object: Specify the state object name. :param value: Specify the value to assign to the state object. If empty, then action is GET, otherwise is action SET. :type state_object: str :type value: str :raises RuntimeError: If failed to get/set for state of a container. """ ssh = SSH() ssh.connect(self._node) ret, _, _ = ssh.exec_command_sudo( 'lxc-cgroup --name {0} {1} {2}'.format(self._container_name, state_object, value)) if int(ret) != 0: if value: raise RuntimeError( 'Failed to set {0} of LXC container {1}.'.format( state_object, self._container_name)) else: raise RuntimeError( 'Failed to get {0} of LXC container {1}.'.format( state_object, self._container_name))
def lxc_attach(self, command): """Start a process inside a running container. Runs the specified command inside the container specified by name. The container has to be running already. :param command: Command to run inside container. :type command: str :raises RuntimeError: If container is not running. :raises RuntimeError: If failed to run the command. """ env_var = '--keep-env {0}'\ .format(' '.join('--set-var %s' % var for var in self._env_vars)) ssh = SSH() ssh.connect(self._node) if not self.is_container_running(): raise RuntimeError('LXC {0} is not running.'.format( self._container_name)) ret, _, _ = ssh.exec_command_lxc(lxc_cmd=command, lxc_name=self._container_name, lxc_params=env_var, timeout=180) if int(ret) != 0: raise RuntimeError( 'Failed to run "{0}" on LXC container {1}.'.format( command, self._container_name))
def install_sfc_test(node): """Prepare the NSH SFC test envrionment. :param node: Dictionary created from topology :type node: dict :returns: nothing """ logger.console('Install the NSH SFC on {0}'.format(node['host'])) if_name_list = Topology.get_node_interfaces(node) ssh = SSH() ssh.connect(node) (ret_code, _, stderr) = ssh.exec_command( 'cd {0}/tests/nsh_sfc/sfc_scripts/ && ./install_sfc.sh {1} {2}' .format(con.REMOTE_FW_DIR, if_name_list[0], if_name_list[1]), \ timeout=600) if ret_code != 0: logger.error('Install the NSH SFC error: {0}'.format(stderr)) raise RuntimeError('Install the NSH SFC failed') else: logger.console('Install the NSH SFC on {0} success!'. format(node['host']))
def get_cpu_layout_from_all_nodes(nodes): """Retrieve cpu layout from all nodes, assuming all nodes are Linux nodes. :param nodes: DICT__nodes from Topology.DICT__nodes. :type nodes: dict :raises RuntimeError: If the ssh command "lscpu -p" fails. """ ssh = SSH() for node in nodes.values(): ssh.connect(node) cmd = "lscpu -p" ret, stdout, stderr = ssh.exec_command(cmd) # parsing of "lscpu -p" output: # # CPU,Core,Socket,Node,,L1d,L1i,L2,L3 # 0,0,0,0,,0,0,0,0 # 1,1,0,0,,1,1,1,0 if ret != 0: raise RuntimeError( "Failed to execute ssh command, ret: {} err: {}".format( ret, stderr)) node['cpuinfo'] = list() for line in stdout.split("\n"): if len(line) > 0 and line[0] != "#": node['cpuinfo'].append( [CpuUtils.__str2int(x) for x in line.split(",")])
def extract_tarball_at_node(tarball, node): """Extract tarball at given node. Extracts tarball using tar on given node to specific CSIT location. :param tarball: Path to tarball to upload. :param node: Dictionary created from topology. :type tarball: str :type node: dict :returns: nothing :raises RuntimeError: When failed to unpack tarball. """ logger.console('Extracting tarball to {0} on {1}'.format( con.REMOTE_FW_DIR, node['host'])) ssh = SSH() ssh.connect(node) (ret_code, _, _) = ssh.exec_command( 'sudo rm -rf {1}; mkdir {1} ; tar -zxf {0} -C {1}; rm -f {0}'.format( tarball, con.REMOTE_FW_DIR), timeout=30) if ret_code != 0: raise RuntimeError('Failed to extract {0} at node {1}'.format( tarball, node['host'])) logger.console('Extracting tarball to {0} on {1} done'.format( con.REMOTE_FW_DIR, node['host']))
def kernel_module_verify(node, 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 node. :param module: Module to verify. :param force_load: If True then try to load module. :type node: dict :type module: str :type force_init: bool :returns: nothing :raises RuntimeError: If module is not loaded or failed to load. """ ssh = SSH() ssh.connect(node) cmd = 'grep -w {} /proc/modules'.format(module) ret_code, _, _ = ssh.exec_command(cmd) if int(ret_code) != 0: if force_load: # Module is not loaded and we want to load it DUTSetup.kernel_module_load(node, module) else: raise RuntimeError('Kernel module {} is not loaded on host: '\ '{}'.format(module, node['host']))
def initialize_dpdk_environment(dut_node, dut_if1, dut_if2): """ Initialize the DPDK test environment on the dut_node. Load the module uio and igb_uio, then bind the test NIC to the igb_uio. :param dut_node: Will init the DPDK on this node. :param dut_if1: DUT interface name. :param dut_if2: DUT interface name. :type dut_node: dict :type dut_if1: str :type dut_if2: str :returns: none :raises RuntimeError: If it fails to bind the interfaces to igb_uio. """ pci_address1 = Topology.get_interface_pci_addr(dut_node, dut_if1) pci_address2 = Topology.get_interface_pci_addr(dut_node, dut_if2) ssh = SSH() ssh.connect(dut_node) cmd = 'cd {0}/tests/dpdk/dpdk_scripts/ && sudo ./init_dpdk.sh {1} {2}' \ .format(con.REMOTE_FW_DIR, pci_address1, pci_address2) (ret_code, _, _) = ssh.exec_command(cmd, timeout=600) if ret_code != 0: raise RuntimeError('Failed to bind the interfaces to igb_uio at ' 'node {0}'.format(dut_node['host']))
def restart_honeycomb_on_dut(node): """Restart Honeycomb on specified DUT nodes. This keyword restarts the Honeycomb service on specified DUTs. Use the keyword "Check Honeycomb Startup State" to check if the Honeycomb is up and running. :param node: Node to restart Honeycomb on. :type node: dict :raises HoneycombError: If Honeycomb fails to start. """ logger.console("\n(re)Starting Honeycomb service on node {0}".format( node["host"])) cmd = "sudo service honeycomb restart" ssh = SSH() ssh.connect(node) (ret_code, _, _) = ssh.exec_command_sudo(cmd) if int(ret_code) != 0: raise HoneycombError( 'Node {0} failed to restart Honeycomb.'.format(node['host'])) else: logger.info( "Honeycomb service restart is in progress on node {0}".format( node['host']))
def cleanup_dpdk_environment(dut_node, dut_if1, dut_if2): """ Cleanup the DPDK test environment on the DUT node. Unbind the NIC from the igb_uio and bind them to the kernel driver. :param dut_node: Will cleanup the DPDK on this node. :param dut_if1: DUT interface name. :param dut_if2: DUT interface name. :type dut_node: dict :type dut_if1: str :type dut_if2: str :returns: none :raises RuntimeError: If it fails to cleanup the dpdk. """ pci_address1 = Topology.get_interface_pci_addr(dut_node, dut_if1) if1_driver = Topology.get_interface_driver(dut_node, dut_if1) pci_address2 = Topology.get_interface_pci_addr(dut_node, dut_if2) if2_driver = Topology.get_interface_driver(dut_node, dut_if2) ssh = SSH() ssh.connect(dut_node) cmd = 'cd {0}/tests/dpdk/dpdk_scripts/ && sudo ./cleanup_dpdk.sh ' \ '{1} {2} {3} {4}'.format(con.REMOTE_FW_DIR, if1_driver, pci_address1, if2_driver, pci_address2) (ret_code, _, _) = ssh.exec_command(cmd, timeout=600) if ret_code != 0: raise RuntimeError('Failed to cleanup the dpdk at node {0}'.format( dut_node['host']))
def copy_odl_client(node, odl_name, src_path, dst_path): """Copy ODL Client from source path to destination path. :param node: Honeycomb node. :param odl_name: Name of ODL client version to use. :param src_path: Source Path where to find ODl client. :param dst_path: Destination path. :type node: dict :type odl_name: str :type src_path: str :type dst_path: str :raises HoneycombError: If the operation fails. """ ssh = SSH() ssh.connect(node) cmd = "sudo rm -rf {dst}/*karaf_{odl_name} && " \ "cp -r {src}/*karaf_{odl_name}* {dst}".format( src=src_path, odl_name=odl_name, dst=dst_path) ret_code, _, _ = ssh.exec_command_sudo(cmd, timeout=180) if int(ret_code) != 0: raise HoneycombError( "Failed to copy ODL client on node {0}".format(node["host"]))
def initialize_dpdk_environment(dut_node, dut_if1, dut_if2): """ Initialize the DPDK test environment on the dut_node. Load the module uio and igb_uio, then bind the test NIC to the igb_uio. :param dut_node: Will init the DPDK on this node. :param dut_if1: DUT interface name. :param dut_if2: DUT interface name. :type dut_node: dict :type dut_if1: str :type dut_if2: str :raises RuntimeError: If it fails to bind the interfaces to igb_uio. """ if dut_node['type'] == NodeType.DUT: pci_address1 = Topology.get_interface_pci_addr(dut_node, dut_if1) pci_address2 = Topology.get_interface_pci_addr(dut_node, dut_if2) ssh = SSH() ssh.connect(dut_node) arch = Topology.get_node_arch(dut_node) cmd = '{fwdir}/tests/dpdk/dpdk_scripts/init_dpdk.sh '\ '{pci1} {pci2} {arch}'.format(fwdir=Constants.REMOTE_FW_DIR, pci1=pci_address1, pci2=pci_address2, arch=arch) ret_code, _, _ = ssh.exec_command_sudo(cmd, timeout=600) if ret_code != 0: raise RuntimeError('Failed to bind the interfaces to igb_uio ' 'at node {name}'.\ format(name=dut_node['host']))
def setup_odl_client(node, path): """Start ODL client on the specified node. Karaf should be located in the provided path, and VPP and Honeycomb should already be running, otherwise the start will fail. :param node: Node to start ODL client on. :param path: Path to ODL client on node. :type node: dict :type path: str :raises HoneycombError: If Honeycomb fails to start. """ logger.console("\nStarting ODL client ...") ssh = SSH() ssh.connect(node) cmd = "{path}/*karaf*/bin/start clean".format(path=path) ret_code, _, _ = ssh.exec_command_sudo(cmd) if int(ret_code) != 0: raise HoneycombError('Node {0} failed to start ODL.'.format( node['host'])) else: logger.info("Starting the ODL client on node {0} is " "in progress ...".format(node['host']))
def cleanup_dpdk_environment(dut_node, dut_if1, dut_if2): """ Cleanup the DPDK test environment on the DUT node. Unbind the NIC from the igb_uio and bind them to the kernel driver. :param dut_node: Will cleanup the DPDK on this node. :param dut_if1: DUT interface name. :param dut_if2: DUT interface name. :type dut_node: dict :type dut_if1: str :type dut_if2: str :raises RuntimeError: If it fails to cleanup the dpdk. """ if dut_node['type'] == NodeType.DUT: pci_address1 = Topology.get_interface_pci_addr(dut_node, dut_if1) if1_driver = Topology.get_interface_driver(dut_node, dut_if1) pci_address2 = Topology.get_interface_pci_addr(dut_node, dut_if2) if2_driver = Topology.get_interface_driver(dut_node, dut_if2) ssh = SSH() ssh.connect(dut_node) cmd = '{fwdir}/tests/dpdk/dpdk_scripts/cleanup_dpdk.sh ' \ '{drv1} {pci1} {drv2} {pci2}'.\ format(fwdir=Constants.REMOTE_FW_DIR, drv1=if1_driver, pci1=pci_address1, drv2=if2_driver, pci2=pci_address2) ret_code, _, _ = ssh.exec_command_sudo(cmd, timeout=600) if ret_code != 0: raise RuntimeError( 'Failed to cleanup the dpdk at node {name}'.format( name=dut_node['host']))
def check_odl_shutdown_state(node): """Check the status of ODL client shutdown. :param node: Honeycomb node. :type node: dict :returns: True when ODL is stopped. :rtype: bool :raises HoneycombError: When the response is not code 200: OK. """ cmd = "pgrep -f karaf" path = HcUtil.read_path_from_url_file( "odl_client/odl_netconf_connector") try: HTTPRequest.get(node, path, timeout=10, enable_logging=False) raise HoneycombError("ODL client is still running.") except HTTPRequestError: logger.debug("Connection refused, checking process state....") ssh = SSH() ssh.connect(node) ret_code, _, _ = ssh.exec_command(cmd) if ret_code == 0: raise HoneycombError("ODL client is still running.") return True
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
def __init__(self): """Initializer.""" self.template = """#!/bin/sh - STATUS=100 while [ $STATUS -eq 100 ] do {java_call} -jar $(dirname $0)/{jar_filename} STATUS=$? echo "Honeycomb exited with status: $STATUS" if [ $STATUS -eq 100 ] then echo "Restarting..." fi done """ self.java_call = "{scheduler} {affinity} java{jit_mode}{params}" self.scheduler = "" self.core_affinity = "" self.jit_mode = "" self.params = "" self.numa = "" self.config = "" self.ssh = SSH()
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
def ipv6_ping(src_node, dst_addr, count=3, data_size=56, timeout=1): """IPv6 ping. :param src_node: Node where ping run. :param dst_addr: Destination IPv6 address. :param count: Number of echo requests. (Optional) :param data_size: Number of the data bytes. (Optional) :param timeout: Time to wait for a response, in seconds. (Optional) :type src_node: dict :type dst_addr: str :type count: int :type data_size: int :type timeout: int :return: Number of lost packets. :rtype: int """ ssh = SSH() ssh.connect(src_node) cmd = "ping6 -c {c} -s {s} -W {W} {dst}".format(c=count, s=data_size, W=timeout, dst=dst_addr) (_, stdout, _) = ssh.exec_command(cmd) regex = re.compile(r'(\d+) packets transmitted, (\d+) received') match = regex.search(stdout) sent, received = match.groups() packet_lost = int(sent) - int(received) return packet_lost
def crypto_device_init(node, numvfs): """Init Crypto QAT device virtual functions on DUT. :param node: DUT node. :param numvfs: Number of VFs to initialize, 0 - disable the VFs. :type node: dict :type numvfs: int :returns: nothing :raises RuntimeError: If QAT failed to initialize. """ ssh = SSH() ssh.connect(node) cryptodev = Topology.get_cryptodev(node) # QAT device must be bind to kernel driver before initialization DUTSetup.pci_driver_unbind(node, cryptodev) DUTSetup.pci_driver_bind(node, cryptodev, "dh895xcc") # Initialize QAT VFs ret_code, _, _ = ssh.exec_command( "sudo sh -c 'echo {} | tee /sys/bus/pci/devices/{}/sriov_numvfs'". format(numvfs, cryptodev.replace(':', r'\:'))) if int(ret_code) != 0: raise RuntimeError('Failed to initialize {} VFs on QAT device on ' 'host: {}'.format(numvfs, node['host']))
def iface_update_numa_node(node): """For all interfaces from topology file update numa node based on information from the node. :param node: Node from topology. :type node: dict :returns: Nothing. :raises ValueError: If numa node ia less than 0. :raises RuntimeError: If update of numa node failes. """ ssh = SSH() for if_key in Topology.get_node_interfaces(node): if_pci = Topology.get_interface_pci_addr(node, if_key) ssh.connect(node) cmd = "cat /sys/bus/pci/devices/{}/numa_node".format(if_pci) for _ in range(3): (ret, out, _) = ssh.exec_command(cmd) if ret == 0: try: numa_node = int(out) if numa_node < 0: raise ValueError except ValueError: logger.trace('Reading numa location failed for: {0}'\ .format(if_pci)) else: Topology.set_interface_numa_node(node, if_key, numa_node) break else: raise RuntimeError('Update numa node failed for: {0}'\ .format(if_pci))
def set_vpp_scheduling_rr(node): """Set real-time scheduling attributes of VPP worker threads to SCHED_RR with priority 1. :param node: DUT node with running VPP. :type node: dict :raises RuntimeError: Failed to retrieve PID for VPP worker threads. """ ssh = SSH() ssh.connect(node) cmd = u"cat /proc/`pidof vpp`/task/*/stat | grep -i vpp_wk" \ u" | awk '{print $1}'" for _ in range(3): ret, out, _ = ssh.exec_command_sudo(cmd) if ret == 0: try: if not out: raise ValueError except ValueError: print(u"Reading VPP worker thread PID failed.") else: for pid in out.split(u"\n"): if pid and pid[0] != u"#": SchedUtils.set_proc_scheduling_rr(node, int(pid)) break else: raise RuntimeError( u"Failed to retrieve PID for VPP worker threads.")