X-Git-Url: https://gerrit.fd.io/r/gitweb?p=csit.git;a=blobdiff_plain;f=resources%2Flibraries%2Fpython%2FQemuUtils.py;h=193390c46d7fd701284c3ce5f1075d33d15426b3;hp=e5f7c5905e6cca70e33b4a04329790d15da42013;hb=cc0c2870a18fb74a56410eca2d1870bddc945397;hpb=33bd6f2425ddff8e4167d36ea61b64ac81da3a65 diff --git a/resources/libraries/python/QemuUtils.py b/resources/libraries/python/QemuUtils.py index e5f7c5905e..193390c46d 100644 --- a/resources/libraries/python/QemuUtils.py +++ b/resources/libraries/python/QemuUtils.py @@ -24,6 +24,7 @@ from distutils.version import StrictVersion from robot.api import logger from resources.libraries.python.ssh import exec_cmd, exec_cmd_no_error from resources.libraries.python.Constants import Constants +from resources.libraries.python.DpdkUtil import DpdkUtil from resources.libraries.python.DUTSetup import DUTSetup from resources.libraries.python.topology import NodeType, Topology from resources.libraries.python.VppConfigGenerator import VppConfigGenerator @@ -81,7 +82,7 @@ class QemuUtils(object): # Use one instance of class per tests. ROBOT_LIBRARY_SCOPE = 'TEST CASE' - def __init__(self, node=None, qemu_id=1, smp=1, mem=512, vnf=None, + def __init__(self, node, qemu_id=1, smp=1, mem=512, vnf=None, img='/var/lib/vm/vhost-nested.img', bin_path='/usr/bin'): """Initialize QemuUtil class. @@ -101,7 +102,9 @@ class QemuUtils(object): :type bin_path: str """ self._vhost_id = 0 + self._node = node self._vm_info = { + 'host': node['host'], 'type': NodeType.VM, 'port': 10021 + qemu_id, 'serial': 4555 + qemu_id, @@ -109,8 +112,10 @@ class QemuUtils(object): 'password': 'cisco', 'interfaces': {}, } - if node: - self.qemu_set_node(node) + if node['port'] != 22: + self._vm_info['host_port'] = node['port'] + self._vm_info['host_username'] = node['username'] + self._vm_info['host_password'] = node['password'] # Input Options. self._opt = dict() self._opt['qemu_id'] = qemu_id @@ -241,8 +246,9 @@ class QemuUtils(object): format(smp=self._opt.get('smp')-1)) vpp_config.add_dpdk_dev('0000:00:06.0', '0000:00:07.0') vpp_config.add_dpdk_log_level('debug') - vpp_config.add_dpdk_no_tx_checksum_offload() - vpp_config.add_dpdk_no_multi_seg() + if not kwargs['jumbo_frames']: + vpp_config.add_dpdk_no_multi_seg() + vpp_config.add_dpdk_no_tx_checksum_offload() vpp_config.add_plugin('disable', 'default') vpp_config.add_plugin('enable', 'dpdk_plugin.so') vpp_config.apply_config(startup, restart_vpp=False) @@ -259,6 +265,59 @@ class QemuUtils(object): format(out=src.safe_substitute(**kwargs), running=running)) + def create_kernelvm_config_testpmd_io(self, **kwargs): + """Create QEMU testpmd-io command line. + + :param kwargs: Key-value pairs to construct command line parameters. + :type kwargs: dict + """ + testpmd_path = ('{path}/{arch}-native-linuxapp-gcc/app'. + format(path=Constants.QEMU_PERF_VM_DPDK, + arch=Topology.get_node_arch(self._node))) + testpmd_cmd = DpdkUtil.get_testpmd_cmdline( + eal_corelist='0-{smp}'.format(smp=self._opt.get('smp') - 1), + eal_driver=False, + eal_in_memory=True, + pmd_num_mbufs=16384, + pmd_rxq=kwargs['queues'], + pmd_txq=kwargs['queues'], + pmd_tx_offloads=False, + pmd_disable_hw_vlan=False, + pmd_max_pkt_len=9200 if kwargs['jumbo_frames'] else None, + pmd_nb_cores=str(self._opt.get('smp') - 1)) + + self._opt['vnf_bin'] = ('{testpmd_path}/{testpmd_cmd}'. + format(testpmd_path=testpmd_path, + testpmd_cmd=testpmd_cmd)) + + def create_kernelvm_config_testpmd_mac(self, **kwargs): + """Create QEMU testpmd-mac command line. + + :param kwargs: Key-value pairs to construct command line parameters. + :type kwargs: dict + """ + testpmd_path = ('{path}/{arch}-native-linuxapp-gcc/app'. + format(path=Constants.QEMU_PERF_VM_DPDK, + arch=Topology.get_node_arch(self._node))) + testpmd_cmd = DpdkUtil.get_testpmd_cmdline( + eal_corelist='0-{smp}'.format(smp=self._opt.get('smp') - 1), + eal_driver=False, + eal_in_memory=True, + pmd_num_mbufs=16384, + pmd_fwd_mode='mac', + pmd_eth_peer_0='0,{mac}'.format(mac=kwargs['vif1_mac']), + pmd_eth_peer_1='1,{mac}'.format(mac=kwargs['vif2_mac']), + pmd_rxq=kwargs['queues'], + pmd_txq=kwargs['queues'], + pmd_tx_offloads=False, + pmd_disable_hw_vlan=False, + pmd_max_pkt_len=9200 if kwargs['jumbo_frames'] else None, + pmd_nb_cores=str(self._opt.get('smp') - 1)) + + self._opt['vnf_bin'] = ('{testpmd_path}/{testpmd_cmd}'. + format(testpmd_path=testpmd_path, + testpmd_cmd=testpmd_cmd)) + def create_kernelvm_init(self, **kwargs): """Create QEMU init script. @@ -286,23 +345,14 @@ class QemuUtils(object): """ if 'vpp' in self._opt.get('vnf'): self.create_kernelvm_config_vpp(**kwargs) + elif 'testpmd_io' in self._opt.get('vnf'): + self.create_kernelvm_config_testpmd_io(**kwargs) + elif 'testpmd_mac' in self._opt.get('vnf'): + self.create_kernelvm_config_testpmd_mac(**kwargs) else: raise RuntimeError('QEMU: Unsupported VNF!') self.create_kernelvm_init(vnf_bin=self._opt.get('vnf_bin')) - def qemu_set_node(self, node): - """Set node to run QEMU on. - - :param node: Node to run QEMU on. - :type node: dict - """ - self._node = node - self._vm_info['host'] = node['host'] - if node['port'] != 22: - self._vm_info['host_port'] = node['port'] - self._vm_info['host_username'] = node['username'] - self._vm_info['host_password'] = node['password'] - def get_qemu_pids(self): """Get QEMU CPU pids. @@ -311,34 +361,40 @@ class QemuUtils(object): """ command = ("grep -rwl 'CPU' /proc/$(sudo cat {pidfile})/task/*/comm ". format(pidfile=self._temp.get('pidfile'))) - command += (r"| xargs dirname | sed -e 's/\/.*\///g'") + command += (r"| xargs dirname | sed -e 's/\/.*\///g' | uniq") stdout, _ = exec_cmd_no_error(self._node, command) return stdout.splitlines() def qemu_set_affinity(self, *host_cpus): """Set qemu affinity by getting thread PIDs via QMP and taskset to list - of CPU cores. + of CPU cores. Function tries to execute 3 times to avoid race condition + in getting thread PIDs. :param host_cpus: List of CPU cores. :type host_cpus: list """ - try: - qemu_cpus = self.get_qemu_pids() - - if len(qemu_cpus) != len(host_cpus): - raise ValueError('Host CPU count must match Qemu Thread count!') - - for qemu_cpu, host_cpu in zip(qemu_cpus, host_cpus): - command = ('taskset -pc {host_cpu} {thread}'. - format(host_cpu=host_cpu, thread=qemu_cpu)) - message = ('QEMU: Set affinity failed on {host}!'. - format(host=self._node['host'])) - exec_cmd_no_error(self._node, command, sudo=True, - message=message) - except (RuntimeError, ValueError): + for _ in range(3): + try: + qemu_cpus = self.get_qemu_pids() + + if len(qemu_cpus) != len(host_cpus): + sleep(1) + continue + for qemu_cpu, host_cpu in zip(qemu_cpus, host_cpus): + command = ('taskset -pc {host_cpu} {thread}'. + format(host_cpu=host_cpu, thread=qemu_cpu)) + message = ('QEMU: Set affinity failed on {host}!'. + format(host=self._node['host'])) + exec_cmd_no_error(self._node, command, sudo=True, + message=message) + break + except (RuntimeError, ValueError): + self.qemu_kill_all() + raise + else: self.qemu_kill_all() - raise + raise RuntimeError('Failed to set Qemu threads affinity!') def qemu_set_scheduler_policy(self): """Set scheduler policy to SCHED_RR with priority 1 for all Qemu CPU @@ -530,6 +586,8 @@ class QemuUtils(object): :param retries: Number of retries. :type retries: int """ + vpp_ver = VPPUtil.vpp_show_version(self._node) + for _ in range(retries): command = ('tail -1 {log}'.format(log=self._temp.get('log'))) stdout = None @@ -538,8 +596,11 @@ class QemuUtils(object): sleep(1) except RuntimeError: pass - if VPPUtil.vpp_show_version(self._node) in stdout: + if vpp_ver in stdout or 'Press enter to exit' in stdout: break + if 'reboot: Power down' in stdout: + raise RuntimeError('QEMU: NF failed to run on {host}!'. + format(host=self._node['host'])) else: raise RuntimeError('QEMU: Timeout, VM not booted on {host}!'. format(host=self._node['host'])) @@ -602,19 +663,15 @@ class QemuUtils(object): format(pidfile=self._temp.get('pidfile')), sudo=True) for value in self._temp.values(): + exec_cmd(self._node, 'cat {value}'.format(value=value), sudo=True) exec_cmd(self._node, 'rm -f {value}'.format(value=value), sudo=True) - def qemu_kill_all(self, node=None): - """Kill all qemu processes on DUT node if specified. - - :param node: Node to kill all QEMU processes on. - :type node: dict - """ - if node: - self.qemu_set_node(node) + def qemu_kill_all(self): + """Kill all qemu processes on DUT node if specified.""" exec_cmd(self._node, 'pkill -SIGKILL qemu', sudo=True) for value in self._temp.values(): + exec_cmd(self._node, 'cat {value}'.format(value=value), sudo=True) exec_cmd(self._node, 'rm -f {value}'.format(value=value), sudo=True) def qemu_version(self, version=None):