diff options
-rwxr-xr-x | conf/01_testcases.conf | 8 | ||||
-rw-r--r-- | conf/02_vswitch.conf | 2 | ||||
-rw-r--r-- | conf/integration/01_testcases.conf | 40 | ||||
-rw-r--r-- | core/vnf_controller.py | 9 | ||||
-rw-r--r-- | core/vswitch_controller_pvp.py | 2 | ||||
-rw-r--r-- | core/vswitch_controller_pvvp.py | 2 | ||||
-rwxr-xr-x | docs/configguide/installation.rst | 39 | ||||
-rwxr-xr-x | src/dpdk/Makefile | 4 | ||||
-rw-r--r-- | src/ovs/daemon.py | 17 | ||||
-rwxr-xr-x | src/qemu/Makefile | 8 | ||||
-rw-r--r-- | testcases/testcase.py | 4 | ||||
-rw-r--r-- | tools/pkt_gen/trafficgen/trafficgenhelper.py | 2 | ||||
-rwxr-xr-x | tools/pkt_gen/xena/xena.py | 2 | ||||
-rw-r--r-- | tools/systeminfo.py | 8 | ||||
-rw-r--r-- | tools/tasks.py | 63 | ||||
-rw-r--r-- | vnfs/qemu/qemu.py | 28 | ||||
-rw-r--r-- | vnfs/vnf/vnf.py | 9 | ||||
-rwxr-xr-x | vsperf | 2 | ||||
-rw-r--r-- | vswitches/ovs.py | 2 |
19 files changed, 181 insertions, 70 deletions
diff --git a/conf/01_testcases.conf b/conf/01_testcases.conf index 148171fd..23a3ae57 100755 --- a/conf/01_testcases.conf +++ b/conf/01_testcases.conf @@ -28,10 +28,12 @@ # "Frame Modification": "vlan" # One of the supported frame modifications: # # vlan, mpls, mac, dscp, ttl, ip_addr, # # ip_port. -# "biDirectional": [true|false], # Specifies if generated traffic will be -# # full-duplex (true) or half-duplex (false) +# "biDirectional": ["True"|"False"] +# # Specifies if generated traffic will be +# # full-duplex (True) or half-duplex (False) # # It can be overridden by cli option bidirectional. -# # Default value is "false". +# # Default value is "False". Must be of type +# # string. # "MultiStream": 0-65535 # Optional. Defines number of flows simulated # # by traffic generator. Value 0 disables # # MultiStream feature diff --git a/conf/02_vswitch.conf b/conf/02_vswitch.conf index d36d1786..67f96991 100644 --- a/conf/02_vswitch.conf +++ b/conf/02_vswitch.conf @@ -71,7 +71,7 @@ VHOST_USER_SOCKS = ['/tmp/dpdkvhostuser0', '/tmp/dpdkvhostuser1', # hardware configuration, like cpu numbering and NUMA. VSWITCHD_DPDK_ARGS = ['-c', '0x4', '-n', '4', '--socket-mem 1024,0'] -VSWITCHD_VANILLA_ARGS = ['--pidfile'] +VSWITCHD_VANILLA_ARGS = [] # use full module path to load module matching OVS version built from the source VSWITCH_VANILLA_KERNEL_MODULES = ['libcrc32c', 'ip_tunnel', 'vxlan', 'gre', 'nf_conntrack', 'nf_defrag_ipv4', 'nf_defrag_ipv6', os.path.join(OVS_DIR_VANILLA, 'datapath/linux/openvswitch.ko')] diff --git a/conf/integration/01_testcases.conf b/conf/integration/01_testcases.conf index e9257ae0..2edbe08b 100644 --- a/conf/integration/01_testcases.conf +++ b/conf/integration/01_testcases.conf @@ -136,7 +136,7 @@ INTEGRATION_TESTS = [ "Name": "overlay_p2p_tput", "Traffic Type": "rfc2544", "Deployment": "op2p", - "biDirectional": False, + "biDirectional": 'False', "Tunnel Type": SUPPORTED_TUNNELING_PROTO[0], "Tunnel Operation": "encapsulation", "Description": "Overlay Encapsulation Throughput RFC2544 Test", @@ -145,7 +145,7 @@ INTEGRATION_TESTS = [ "Name": "overlay_p2p_cont", "Traffic Type": "continuous", "Deployment": "op2p", - "biDirectional": False, + "biDirectional": 'False', "Tunnel Type": SUPPORTED_TUNNELING_PROTO[0], "Tunnel Operation": "encapsulation", "Description": "Overlay Encapsulation Continuous Stream", @@ -154,7 +154,7 @@ INTEGRATION_TESTS = [ "Name": "overlay_p2p_decap_tput", "Traffic Type": "rfc2544", "Deployment": "op2p", - "biDirectional": False, + "biDirectional": 'False', "Tunnel Type": SUPPORTED_TUNNELING_PROTO[0], "Tunnel Operation": "decapsulation", "Description": "Overlay Decapsulation Throughput RFC2544 Test", @@ -163,7 +163,7 @@ INTEGRATION_TESTS = [ "Name": "overlay_p2p_decap_cont", "Traffic Type": "continuous", "Deployment": "op2p", - "biDirectional": False, + "biDirectional": 'False', "Tunnel Type": SUPPORTED_TUNNELING_PROTO[0], "Tunnel Operation": "decapsulation", "Description": "Overlay Decapsulation Continuous Stream", @@ -264,7 +264,7 @@ INTEGRATION_TESTS = [ "Description": "vSwitch - configure switch and execute RFC2544 throughput test", "TestSteps": STEP_VSWITCH_P2P_FLOWS_INIT + [ - ['trafficgen', 'send_traffic', {'traffic_type' : 'throughput', 'bidir' : True}], + ['trafficgen', 'send_traffic', {'traffic_type' : 'throughput', 'bidir' : 'True'}], ] + STEP_VSWITCH_P2P_FLOWS_FINIT }, @@ -274,7 +274,7 @@ INTEGRATION_TESTS = [ "Description": "vSwitch - configure switch and execute RFC2544 back2back test", "TestSteps": STEP_VSWITCH_P2P_FLOWS_INIT + [ - ['trafficgen', 'send_traffic', {'traffic_type' : 'back2back', 'bidir' : True}], + ['trafficgen', 'send_traffic', {'traffic_type' : 'back2back', 'bidir' : 'True'}], ] + STEP_VSWITCH_P2P_FLOWS_FINIT }, @@ -284,7 +284,7 @@ INTEGRATION_TESTS = [ "Description": "vSwitch - configure switch and execute continuous stream test", "TestSteps": STEP_VSWITCH_P2P_FLOWS_INIT + [ - ['trafficgen', 'send_traffic', {'traffic_type' : 'continuous', 'bidir' : True}], + ['trafficgen', 'send_traffic', {'traffic_type' : 'continuous', 'bidir' : 'True'}], ] + STEP_VSWITCH_P2P_FLOWS_FINIT }, @@ -306,7 +306,7 @@ INTEGRATION_TESTS = [ "TestSteps": STEP_VSWITCH_PVP_FLOWS_INIT + [ ['vnf', 'start'], - ['trafficgen', 'send_traffic', {'traffic_type' : 'throughput', 'bidir' : True}], + ['trafficgen', 'send_traffic', {'traffic_type' : 'throughput', 'bidir' : 'True'}], ['vnf', 'stop'], ] + STEP_VSWITCH_PVP_FLOWS_FINIT @@ -318,7 +318,7 @@ INTEGRATION_TESTS = [ "TestSteps": STEP_VSWITCH_PVP_FLOWS_INIT + [ ['vnf', 'start'], - ['trafficgen', 'send_traffic', {'traffic_type' : 'back2back', 'bidir' : True}], + ['trafficgen', 'send_traffic', {'traffic_type' : 'back2back', 'bidir' : 'True'}], ['vnf', 'stop'], ] + STEP_VSWITCH_PVP_FLOWS_FINIT @@ -330,7 +330,7 @@ INTEGRATION_TESTS = [ "TestSteps": STEP_VSWITCH_PVP_FLOWS_INIT + [ ['vnf', 'start'], - ['trafficgen', 'send_traffic', {'traffic_type' : 'continuous', 'bidir' : True}], + ['trafficgen', 'send_traffic', {'traffic_type' : 'continuous', 'bidir' : 'True'}], ['vnf', 'stop'], ] + STEP_VSWITCH_PVP_FLOWS_FINIT @@ -342,9 +342,9 @@ INTEGRATION_TESTS = [ "TestSteps": STEP_VSWITCH_PVP_FLOWS_INIT + [ ['vnf', 'start'], - ['trafficgen', 'send_traffic', {'traffic_type' : 'throughput', 'bidir' : True}], - ['trafficgen', 'send_traffic', {'traffic_type' : 'back2back', 'bidir' : True}], - ['trafficgen', 'send_traffic', {'traffic_type' : 'continuous', 'bidir' : True}], + ['trafficgen', 'send_traffic', {'traffic_type' : 'throughput', 'bidir' : 'True'}], + ['trafficgen', 'send_traffic', {'traffic_type' : 'back2back', 'bidir' : 'True'}], + ['trafficgen', 'send_traffic', {'traffic_type' : 'continuous', 'bidir' : 'True'}], ['vnf', 'stop'], ] + STEP_VSWITCH_PVP_FLOWS_FINIT @@ -370,7 +370,7 @@ INTEGRATION_TESTS = [ [ ['vnf1', 'start'], ['vnf2', 'start'], - ['trafficgen', 'send_traffic', {'traffic_type' : 'throughput', 'bidir' : True}], + ['trafficgen', 'send_traffic', {'traffic_type' : 'throughput', 'bidir' : 'True'}], ['vnf1', 'stop'], ['vnf2', 'stop'], ] + @@ -384,7 +384,7 @@ INTEGRATION_TESTS = [ [ ['vnf1', 'start'], ['vnf2', 'start'], - ['trafficgen', 'send_traffic', {'traffic_type' : 'back2back', 'bidir' : True}], + ['trafficgen', 'send_traffic', {'traffic_type' : 'back2back', 'bidir' : 'True'}], ['vnf1', 'stop'], ['vnf2', 'stop'], ] + @@ -398,7 +398,7 @@ INTEGRATION_TESTS = [ [ ['vnf1', 'start'], ['vnf2', 'start'], - ['trafficgen', 'send_traffic', {'traffic_type' : 'continuous', 'bidir' : True}], + ['trafficgen', 'send_traffic', {'traffic_type' : 'continuous', 'bidir' : 'True'}], ['vnf1', 'stop'], ['vnf2', 'stop'], ] + @@ -412,9 +412,9 @@ INTEGRATION_TESTS = [ [ ['vnf1', 'start'], ['vnf2', 'start'], - ['trafficgen', 'send_traffic', {'traffic_type' : 'throughput', 'bidir' : True}], - ['trafficgen', 'send_traffic', {'traffic_type' : 'back2back', 'bidir' : True}], - ['trafficgen', 'send_traffic', {'traffic_type' : 'continuous', 'bidir' : True}], + ['trafficgen', 'send_traffic', {'traffic_type' : 'throughput', 'bidir' : 'True'}], + ['trafficgen', 'send_traffic', {'traffic_type' : 'back2back', 'bidir' : 'True'}], + ['trafficgen', 'send_traffic', {'traffic_type' : 'continuous', 'bidir' : 'True'}], ['vnf1', 'stop'], ['vnf2', 'stop'], ] + @@ -434,7 +434,7 @@ INTEGRATION_TESTS = [ # "TestSteps": STEP_VSWITCH_PVP_FLOWS_INIT + # [ # ['vnf', 'start'], -# ['trafficgen', 'send_traffic', {'traffic_type' : 'continuous', 'bidir' : True}], +# ['trafficgen', 'send_traffic', {'traffic_type' : 'continuous', 'bidir' : 'True'}], # ['vnf', 'stop'], # ] + # STEP_VSWITCH_PVP_FLOWS_FINIT diff --git a/core/vnf_controller.py b/core/vnf_controller.py index 39a63044..8800ccaf 100644 --- a/core/vnf_controller.py +++ b/core/vnf_controller.py @@ -15,6 +15,7 @@ """ import logging +import pexpect from vnfs.vnf.vnf import IVnf class VnfController(object): @@ -68,8 +69,12 @@ class VnfController(object): """ self._logger.debug('start ' + str(len(self._vnfs)) + ' VNF[s] with ' + ' '.join(map(str, self._vnfs))) - for vnf in self._vnfs: - vnf.start() + try: + for vnf in self._vnfs: + vnf.start() + except pexpect.TIMEOUT: + self.stop() + raise def stop(self): """Stops all VNFs set-up by __init__. diff --git a/core/vswitch_controller_pvp.py b/core/vswitch_controller_pvp.py index 0c98cc7f..a4f61961 100644 --- a/core/vswitch_controller_pvp.py +++ b/core/vswitch_controller_pvp.py @@ -77,7 +77,7 @@ class VswitchControllerPVP(IVswitchController): self._vswitch.add_flow(bridge, flow1) self._vswitch.add_flow(bridge, flow2) - if self._traffic['bidir']: + if self._traffic['bidir'] == 'True': flow3 = add_ports_to_flow(flow_template, phy2_number, vport2_number) flow4 = add_ports_to_flow(flow_template, vport1_number, diff --git a/core/vswitch_controller_pvvp.py b/core/vswitch_controller_pvvp.py index c79ad9a3..729aca3f 100644 --- a/core/vswitch_controller_pvvp.py +++ b/core/vswitch_controller_pvvp.py @@ -82,7 +82,7 @@ class VswitchControllerPVVP(IVswitchController): self._vswitch.add_flow(bridge, flow2) self._vswitch.add_flow(bridge, flow3) - if self._traffic['bidir']: + if self._traffic['bidir'] == 'True': flow4 = add_ports_to_flow(flow_template, phy2_number, vport4_number) flow5 = add_ports_to_flow(flow_template, vport3_number, diff --git a/docs/configguide/installation.rst b/docs/configguide/installation.rst index 354979b0..d6161b9a 100755 --- a/docs/configguide/installation.rst +++ b/docs/configguide/installation.rst @@ -119,3 +119,42 @@ running any of the above. For example: .. _virtualenv: https://virtualenv.readthedocs.org/en/latest/ .. _vloop-vnf-ubuntu-14.04_20160303: http://artifacts.opnfv.org/vswitchperf/vnf/vloop-vnf-ubuntu-14.04_20160303.qcow2 .. _vloop-vnf-ubuntu-14.04_20151216: http://artifacts.opnfv.org/vswitchperf/vnf/vloop-vnf-ubuntu-14.04_20151216.qcow2 + +Hugepage Configuration +---------------------- + +Systems running vsperf with either dpdk and/or tests with guests must configure +hugepage amounts to support running these configurations. It is recommended +to configure 1GB hugepages as the pagesize. + +The amount of hugepages needed depends on your configuration files in vsperf. +Each guest image requires 4096 by default according to the default settings in +the ``04_vnf.conf`` file. + +.. code:: bash + + GUEST_MEMORY = ['4096', '4096'] + +The dpdk startup parameters also require an amount of hugepages depending on +your configuration in the ``02_vswitch.conf`` file. + +.. code:: bash + + VSWITCHD_DPDK_ARGS = ['-c', '0x4', '-n', '4', '--socket-mem 1024,1024'] + +With the --socket-mem argument set to use 1 hugepage on the specified sockets as +seen above, the configuration will need 9 hugepages total to run all tests +within vsperf if the pagesize is set correctly to 1GB. + +Depending on your OS selection configuration of hugepages may vary. Please refer +to your OS documentation to set hugepages correctly. It is recommended to set +the required amount of hugepages to be allocated by default on reboots. + +Information on hugepage requirements for dpdk can be found at +http://dpdk.org/doc/guides/linux_gsg/sys_reqs.html + +You can review your hugepage amounts by executing the following command + +.. code:: bash + + cat /proc/meminfo | grep Huge diff --git a/src/dpdk/Makefile b/src/dpdk/Makefile index 25ec3f12..e21e7999 100755 --- a/src/dpdk/Makefile +++ b/src/dpdk/Makefile @@ -29,7 +29,6 @@ ifndef VHOST_USER endif WORK_DIR = dpdk TAG_DONE_FLAG = $(WORK_DIR)/.$(DPDK_TAG).tag.done -DPDK_VANILLA = ../../src_vanilla/dpdk DPDK_CUSE = ../../src_cuse/dpdk # the name has been changed from version to version @@ -70,7 +69,6 @@ clean: $(AT)cd $(WORK_DIR) && git clean -xfd *.o clobber: $(AT)rm -rf $(WORK_DIR) - $(AT)rm -rf $(DPDK_VANILLA) $(AT)rm -rf $(DPDK_CUSE) # distclean is for developer who would like to keep the @@ -86,8 +84,6 @@ sanity: $(WORK_DIR): $(AT)git clone $(DPDK_URL) - $(AT)mkdir -p $(DPDK_VANILLA) - $(AT)cp -rf ./* $(DPDK_VANILLA) $(AT)mkdir -p $(DPDK_CUSE) $(AT)cp -rf ./* $(DPDK_CUSE) diff --git a/src/ovs/daemon.py b/src/ovs/daemon.py index 089bc7a4..f9b037b2 100644 --- a/src/ovs/daemon.py +++ b/src/ovs/daemon.py @@ -38,6 +38,7 @@ class VSwitchd(tasks.Process): _ovsdb_pid = None _logfile = _LOG_FILE_VSWITCHD _ovsdb_pidfile_path = os.path.join(settings.getValue('LOG_DIR'), "ovsdb_pidfile.pid") + _vswitchd_pidfile_path = os.path.join(settings.getValue('LOG_DIR'), "vswitchd_pidfile.pid") _proc_name = 'ovs-vswitchd' def __init__(self, timeout=30, vswitchd_args=None, expected_cmd=None): @@ -55,7 +56,10 @@ class VSwitchd(tasks.Process): vswitchd_args = vswitchd_args or [] ovs_vswitchd_bin = os.path.join( settings.getValue('OVS_DIR'), 'vswitchd', 'ovs-vswitchd') - self._cmd = ['sudo', '-E', ovs_vswitchd_bin] + vswitchd_args + sep = ['--'] if '--dpdk' in vswitchd_args else [] + self._cmd = ['sudo', '-E', ovs_vswitchd_bin] + vswitchd_args + sep + \ + ['--pidfile=' + self._vswitchd_pidfile_path, '--overwrite-pidfile', + '--log-file=' + self._logfile] # startup/shutdown @@ -77,15 +81,19 @@ class VSwitchd(tasks.Process): self._kill_ovsdb() raise exc - def kill(self, signal='-15', sleep=2): + def kill(self, signal='-15', sleep=10): """Kill ``ovs-vswitchd`` instance if it is alive. :returns: None """ self._logger.info('Killing ovs-vswitchd...') + with open(self._vswitchd_pidfile_path, "r") as pidfile: + vswitchd_pid = pidfile.read().strip() + tasks.terminate_task(vswitchd_pid, logger=self._logger) - self._kill_ovsdb() + self._kill_ovsdb() # ovsdb must be killed after vswitchd + # just for case, that sudo envelope has not terminated super(VSwitchd, self).kill(signal, sleep) # helper functions @@ -144,8 +152,7 @@ class VSwitchd(tasks.Process): self._logger.info("Killing ovsdb with pid: " + ovsdb_pid) if ovsdb_pid: - tasks.run_task(['sudo', 'kill', '-15', str(ovsdb_pid)], - self._logger, 'Killing ovsdb-server...') + tasks.terminate_task(ovsdb_pid, logger=self._logger) @staticmethod def get_db_sock_path(): diff --git a/src/qemu/Makefile b/src/qemu/Makefile index 4603b273..1bf8a8d0 100755 --- a/src/qemu/Makefile +++ b/src/qemu/Makefile @@ -28,8 +28,6 @@ INSTALL_TARGET = force_make force_install CONFIG_CMD = CONFIG_CMD += ./configure CONFIG_CMD += --target-list="x86_64-softmmu" -QEMU_VANILLA = ../../src_vanilla/qemu -QEMU_CUSE = ../../src_cuse/qemu all: force_make @@ -55,8 +53,6 @@ clean: $(AT)cd $(WORK_DIR) && git clean -xfd *.o clobber: $(AT)rm -rf $(WORK_DIR) - $(AT)rm -rf $(QEMU_VANILLA) - $(AT)rm -rf $(QEMU_CUSE) # distclean is for developer who would like to keep the # clone git repo, saving time to fetch again from url @@ -73,10 +69,6 @@ $(WORK_DIR)/configure: $(TAG_DONE_FLAG) $(WORK_DIR): $(AT)git clone $(QEMU_URL) - $(AT)mkdir -p $(QEMU_VANILLA) - $(AT)cp -rf ./* $(QEMU_VANILLA) - $(AT)mkdir -p $(QEMU_CUSE) - $(AT)cp -rf ./* $(QEMU_CUSE) $(TAG_DONE_FLAG): $(WORK_DIR) $(AT)cd $(WORK_DIR); git checkout $(QEMU_TAG) diff --git a/testcases/testcase.py b/testcases/testcase.py index f7908af9..5b9ead69 100644 --- a/testcases/testcase.py +++ b/testcases/testcase.py @@ -82,6 +82,10 @@ class TestCase(object): bidirectional = cfg.get('biDirectional', TRAFFIC_DEFAULTS['bidir']) bidirectional = get_test_param('bidirectional', bidirectional) + if not isinstance(bidirectional, str): + raise TypeError( + 'Bi-dir value must be of type string in testcase configuration') + bidirectional = bidirectional.title() # Keep things consistent traffic_type = cfg.get('Traffic Type', TRAFFIC_DEFAULTS['traffic_type']) traffic_type = get_test_param('traffic_type', traffic_type) diff --git a/tools/pkt_gen/trafficgen/trafficgenhelper.py b/tools/pkt_gen/trafficgen/trafficgenhelper.py index 0a240579..90c77b09 100644 --- a/tools/pkt_gen/trafficgen/trafficgenhelper.py +++ b/tools/pkt_gen/trafficgen/trafficgenhelper.py @@ -23,7 +23,7 @@ CMD_PREFIX = 'gencmd : ' TRAFFIC_DEFAULTS = { 'traffic_type' : 'rfc2544', 'frame_rate' : 100, - 'bidir' : False, + 'bidir' : 'False', # will be passed as string in title format to tgen 'multistream' : 0, 'stream_type' : 'L4', 'pre_installed_flows' : 'No', # used by vswitch implementation diff --git a/tools/pkt_gen/xena/xena.py b/tools/pkt_gen/xena/xena.py index 67ac5652..d29fc362 100755 --- a/tools/pkt_gen/xena/xena.py +++ b/tools/pkt_gen/xena/xena.py @@ -182,7 +182,7 @@ class Xena(ITrafficGenerator): flows=self._params['traffic']['multistream'], multistream_layer=self._params['traffic']['stream_type']) # set duplex mode - if bool(self._params['traffic']['bidir']): + if self._params['traffic']['bidir'] == "True": j_file.set_topology_mesh() else: j_file.set_topology_blocks() diff --git a/tools/systeminfo.py b/tools/systeminfo.py index ba490946..9d8eb5cb 100644 --- a/tools/systeminfo.py +++ b/tools/systeminfo.py @@ -168,6 +168,14 @@ def get_pid(proc_name_str): """ return get_pids([proc_name_str]) +def pid_isalive(pid): + """ Checks if given PID is alive + + :param pid: PID of the process + :returns: True if given process is running, False otherwise + """ + return os.path.isdir('/proc/' + str(pid)) + # This function uses long switch per purpose, so let us suppress pylint warning too-many-branches # pylint: disable=R0912 def get_version(app_name): diff --git a/tools/tasks.py b/tools/tasks.py index 90b7e553..dda5217d 100644 --- a/tools/tasks.py +++ b/tools/tasks.py @@ -26,6 +26,7 @@ import locale import time from conf import settings +from tools import systeminfo CMD_PREFIX = 'cmd : ' @@ -150,6 +151,55 @@ def run_interactive_task(cmd, logger, msg): return child +def terminate_task_subtree(pid, signal='-15', sleep=10, logger=None): + """Terminate given process and all its children + + Function will sent given signal to the process. In case + that process will not terminate within given sleep interval + and signal was not SIGKILL, then process will be killed by SIGKILL. + After that function will check if all children of the process + are terminated and if not the same terminating procedure is applied + on any living child (only one level of children is considered). + + :param pid: Process ID to terminate + :param signal: Signal to be sent to the process + :param sleep: Maximum delay in seconds after signal is sent + :param logger: Logger to write details to + """ + try: + output = subprocess.check_output("pgrep -P " + str(pid), shell=True).decode().rstrip('\n') + except subprocess.CalledProcessError: + output = "" + + terminate_task(pid, signal, sleep, logger) + + # just for case children were kept alive + children = output.split('\n') + for child in children: + terminate_task(child, signal, sleep, logger) + +def terminate_task(pid, signal='-15', sleep=10, logger=None): + """Terminate process with given pid + + Function will sent given signal to the process. In case + that process will not terminate within given sleep interval + and signal was not SIGKILL, then process will be killed by SIGKILL. + + :param pid: Process ID to terminate + :param signal: Signal to be sent to the process + :param sleep: Maximum delay in seconds after signal is sent + :param logger: Logger to write details to + """ + if systeminfo.pid_isalive(pid): + run_task(['sudo', 'kill', signal, str(pid)], logger) + logger.debug('Wait for process %s to terminate after signal %s', pid, signal) + for dummy in range(sleep): + time.sleep(1) + if not systeminfo.pid_isalive(pid): + break + + if signal.lstrip('-').upper() not in ('9', 'KILL', 'SIGKILL') and systeminfo.pid_isalive(pid): + terminate_task(pid, '-9', sleep, logger) class Process(object): """Control an instance of a long-running process. @@ -242,17 +292,14 @@ class Process(object): self.kill() raise exc - def kill(self, signal='-15', sleep=2): + def kill(self, signal='-15', sleep=10): """Kill process instance if it is alive. :param signal: signal to be sent to the process :param sleep: delay in seconds after signal is sent """ - if self._child and self._child.isalive(): - run_task(['sudo', 'kill', signal, str(self._child.pid)], - self._logger) - self._logger.debug('Wait for process to terminate') - time.sleep(sleep) + if self.is_running(): + terminate_task_subtree(self._child.pid, signal, sleep, self._logger) if self.is_relinquished(): self._relinquish_thread.join() @@ -275,7 +322,7 @@ class Process(object): :returns: True if process is running, else False """ - return self._child is not None + return self._child and self._child.isalive() def _affinitize_pid(self, core, pid): """Affinitize a process with ``pid`` to ``core``. @@ -298,7 +345,7 @@ class Process(object): """ self._logger.info('Affinitizing process') - if self._child and self._child.isalive(): + if self.is_running(): self._affinitize_pid(core, self._child.pid) class ContinueReadPrintLoop(threading.Thread): diff --git a/vnfs/qemu/qemu.py b/vnfs/qemu/qemu.py index c735062f..d108dc9a 100644 --- a/vnfs/qemu/qemu.py +++ b/vnfs/qemu/qemu.py @@ -21,6 +21,7 @@ import locale import re import subprocess import time +import pexpect from conf import settings as S from conf import get_test_param @@ -133,15 +134,24 @@ class IVnfQemu(IVnf): """ Stops VNF instance gracefully first. """ - # exit testpmd if needed - if self._guest_loopback == 'testpmd': - self.execute_and_wait('stop', 120, "Done") - self.execute_and_wait('quit', 120, "bye") - - # turn off VM - self.execute_and_wait('poweroff', 120, "Power down") - # VM OS is off, but wait until qemu shutdowns - time.sleep(2) + try: + # exit testpmd if needed + if self._guest_loopback == 'testpmd': + self.execute_and_wait('stop', 120, "Done") + self.execute_and_wait('quit', 120, "bye") + + # turn off VM + self.execute_and_wait('poweroff', 120, "Power down") + + except pexpect.TIMEOUT: + self.kill() + + # wait until qemu shutdowns + self._logger.debug('Wait for QEMU to terminate') + for dummy in range(30): + time.sleep(1) + if not self.is_running(): + break # just for case that graceful shutdown failed super(IVnfQemu, self).stop() diff --git a/vnfs/vnf/vnf.py b/vnfs/vnf/vnf.py index 3dae2733..1410a0c4 100644 --- a/vnfs/vnf/vnf.py +++ b/vnfs/vnf/vnf.py @@ -51,11 +51,12 @@ class IVnf(tasks.Process): """ Stops VNF instance. """ - self._logger.info('Killing VNF...') + if self.is_running(): + self._logger.info('Killing VNF...') - # force termination of VNF and wait for it to terminate; It will avoid - # sporadic reboot of host. (caused by hugepages or DPDK ports) - super(IVnf, self).kill(signal='-9', sleep=10) + # force termination of VNF and wait for it to terminate; It will avoid + # sporadic reboot of host. (caused by hugepages or DPDK ports) + super(IVnf, self).kill(signal='-9', sleep=10) def execute(self, cmd, delay=0): """ @@ -610,7 +610,7 @@ def main(): # set traffic details, so they can be passed to traffic ctl traffic = copy.deepcopy(TRAFFIC_DEFAULTS) traffic.update({'traffic_type': get_test_param('traffic_type', 'rfc2544'), - 'bidir': get_test_param('bidirectional', False), + 'bidir': get_test_param('bidirectional', 'False'), 'multistream': int(get_test_param('multistream', 0)), 'stream_type': get_test_param('stream_type', 'L4'), 'frame_rate': int(get_test_param('iload', 100))}) diff --git a/vswitches/ovs.py b/vswitches/ovs.py index 06dc7a1a..dd49a1fc 100644 --- a/vswitches/ovs.py +++ b/vswitches/ovs.py @@ -21,7 +21,7 @@ from conf import settings from vswitches.vswitch import IVSwitch from src.ovs import OFBridge, flow_key, flow_match -_VSWITCHD_CONST_ARGS = ['--', '--pidfile', '--log-file'] +_VSWITCHD_CONST_ARGS = [] class IVSwitchOvs(IVSwitch): """Open vSwitch base class implementation |