diff options
author | Martin Klozik <martinx.klozik@intel.com> | 2016-01-13 14:57:07 +0000 |
---|---|---|
committer | Maryam Tahhan <maryam.tahhan@intel.com> | 2016-01-22 10:03:52 +0000 |
commit | 864832fd348efa21155b24a314dab22fe967c8c3 (patch) | |
tree | 04c918abbbf7b81672a9ddac19b6ebcc3df1e224 | |
parent | 2a2baf3f5f348539b50194a456b49b4ccb32b775 (diff) |
pkt_gen: support of standalone execution of traffic generator
Support for multiple modes of VSPERF operation has been added.
These modes can be used for standalone execution of traffic
generator or for manual testing or for execution of unsupported
traffic generator. Supported modes are: "normal" - execute vSwitch,
VNF and traffic generator; "trafficgen" - execute only traffic
generator; "trafficgen-off" - execute vSwitch and VNF.
Normal mode is selected by default.
In case that trafficgen mode is selected, then various
--test-params could be specified to affect traffic generator
configuration. These parameters include traffic type, frame rate,
bidirectional and scalability settings. Selection of transport
protocol is not supported by IxNet yet (UDP is enforced), thus
modification of transport protocol from command line is not
supported too.
Fixes of testpmd and qemu warning patches are inclduded.
Change-Id: Idac10fe03e724075268a01ec3eb0817fba830aec
JIRA: VSPERF-173
Signed-off-by: Martin Klozik <martinx.klozik@intel.com>
Reviewed-by: Maryam Tahhan <maryam.tahhan@intel.com>
Reviewed-by: Al Morton <acmorton@att.com>
-rwxr-xr-x | conf/01_testcases.conf | 6 | ||||
-rw-r--r-- | core/pktfwd_controller.py | 10 | ||||
-rwxr-xr-x | docs/userguides/quickstart.rst | 57 | ||||
-rw-r--r-- | testcases/testcase.py | 56 | ||||
-rw-r--r-- | vnfs/qemu/qemu.py | 2 | ||||
-rwxr-xr-x | vsperf | 229 |
6 files changed, 226 insertions, 134 deletions
diff --git a/conf/01_testcases.conf b/conf/01_testcases.conf index b855405d..77072eeb 100755 --- a/conf/01_testcases.conf +++ b/conf/01_testcases.conf @@ -20,14 +20,18 @@ # "Name": "phy2phy_burst", # A human-readable string identifying the # # test. # "Traffic Type": "rfc2544", # One of the supported traffic types. +# # It can be overridden by cli option traffic_type. +# # Default value is "rfc2544". # "Deployment": "p2p", # One of the supported deployment scenarios. # "Description": "Lorem ipsum..." # Optional. A human-readable string # # describing the test. # "Frame Modification": "vlan" # One of the supported frame modifications: # # vlan, mpls, mac, dscp, ttl, ip_addr, # # ip_port. -# "biDirectional": [true|false], # Specifies if genearted traffic will be +# "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". # "MultiStream": 0-65535 # Optional. Defines number of flows simulated # # by traffic generator. Value 0 disables # # MultiStream feature diff --git a/core/pktfwd_controller.py b/core/pktfwd_controller.py index 4f300ce8..40565504 100644 --- a/core/pktfwd_controller.py +++ b/core/pktfwd_controller.py @@ -17,9 +17,6 @@ import logging -from conf import settings - - class PktFwdController(object): """Packet forwarder controller for P2P deployment scenario. @@ -66,3 +63,10 @@ class PktFwdController(object): :return: The controlled IPktFwd """ return self._pktfwd + + def dump_vswitch_flows(self): + """ Dumps flows from vswitch + """ + raise NotImplementedError( + "The PktFwdController does not implement the " + "\"dump_vswitch_flows\" function.") diff --git a/docs/userguides/quickstart.rst b/docs/userguides/quickstart.rst index caf3be04..fa951e0e 100755 --- a/docs/userguides/quickstart.rst +++ b/docs/userguides/quickstart.rst @@ -294,9 +294,9 @@ To run tests using Vanilla OVS: or use --test-param - ./vsperf --conf-file=<path_to_custom_conf>/10_custom.conf - --test-param "vanilla_tgen_tx_ip=n.n.n.n; - vanilla_tgen_tx_mac=nn:nn:nn:nn:nn:nn" + $ ./vsperf --conf-file=<path_to_custom_conf>/10_custom.conf + --test-param "vanilla_tgen_tx_ip=n.n.n.n; + vanilla_tgen_tx_mac=nn:nn:nn:nn:nn:nn" 2. Recompile src for Vanilla OVS testing @@ -356,7 +356,7 @@ following configuration parameter should be configured: or use --vswitch and --fwdapp - ./vsperf --conf-file user_settings.py + $ ./vsperf --conf-file user_settings.py --vswitch none --fwdapp TestPMD @@ -386,8 +386,55 @@ for selected Packet Forwarder: .. code-block:: console - ./vsperf --conf-file <path_to_settings_py> + $ ./vsperf --conf-file <path_to_settings_py> +VSPERF modes of operation +------------------------- +VSPERF can be run in different modes. By default it will configure vSwitch, +traffic generator and VNF. However it can be used just for configuration +and execution of traffic generator. Another option is execution of all +components except traffic generator itself. + +Mode of operation is driven by configuration parameter -m or --mode + +.. code-block:: console + + -m MODE, --mode MODE vsperf mode of operation; + Values: + "normal" - execute vSwitch, VNF and traffic generator + "trafficgen" - execute only traffic generator + "trafficgen-off" - execute vSwitch and VNF + +In case, that VSPERF is executed in "trafficgen" mode, then configuration +of traffic generator should be configured through --test-param option. +Supported CLI options useful for traffic generator configuration are: + +.. code-block:: console + + 'traffic_type' - One of the supported traffic types. E.g. rfc2544, + back2back or continuous + Default value is "rfc2544". + 'bidirectional' - Specifies if generated traffic will be full-duplex (true) + or half-duplex (false) + Default value is "false". + 'iload' - Defines desired percentage of frame rate used during + continuous stream tests. + Default value is 100. + 'multistream' - Defines number of flows simulated by traffic generator. + Value 0 disables MultiStream feature + Default value is 0. + 'stream_type' - Stream Type is an extension of the "MultiStream" feature. + If MultiStream is disabled, then Stream Type will be + ignored. Stream Type defines ISO OSI network layer used + for simulation of multiple streams. + Default value is "L4". + +Example of execution of VSPERF in "trafficgen" mode: + +.. code-block:: console + + $ ./vsperf -m trafficgen --trafficgen IxNet --conf-file vsperf.conf + --test-params "traffic_type=continuous;bidirectional=True;iload=60" Code change verification by pylint ---------------------------------- diff --git a/testcases/testcase.py b/testcases/testcase.py index 7d5162e6..9c755ea7 100644 --- a/testcases/testcase.py +++ b/testcases/testcase.py @@ -19,6 +19,7 @@ import os import logging import subprocess import copy +import time from collections import OrderedDict from core.results.results_constants import ResultsConstants @@ -45,14 +46,23 @@ class TestCase(object): :param results_dir: Where the csv formatted results are written. """ self._hugepages_mounted = False + + # set test parameters; CLI options take precedence to testcase settings self._logger = logging.getLogger(__name__) self.name = cfg['Name'] self.desc = cfg.get('Description', 'No description given.') + + bidirectional = cfg.get('biDirectional', False) + bidirectional = get_test_param('bidirectional', bidirectional) + + traffic_type = cfg.get('Traffic Type', 'rfc2544') + traffic_type = get_test_param('traffic_type', traffic_type) + + framerate = cfg.get('iLoad', 100) + framerate = get_test_param('iload', framerate) + self.deployment = cfg['Deployment'] self._frame_mod = cfg.get('Frame Modification', None) - framerate = get_test_param('iload', None) - if framerate == None: - framerate = cfg.get('iLoad', 100) # identify guest loopback method, so it can be added into reports self.guest_loopback = [] @@ -75,7 +85,6 @@ class TestCase(object): pre_installed_flows = cfg.get('Pre-installed Flows', 'No') pre_installed_flows = get_test_param('pre-installed_flows', pre_installed_flows) - # check if test requires background load and which generator it uses self._load_cfg = cfg.get('Load', None) if self._load_cfg and 'tool' in self._load_cfg: @@ -90,9 +99,9 @@ class TestCase(object): # set traffic details, so they can be passed to vswitch and traffic ctls self._traffic = copy.deepcopy(TRAFFIC_DEFAULTS) - self._traffic.update({'traffic_type': cfg['Traffic Type'], + self._traffic.update({'traffic_type': traffic_type, 'flow_type': cfg.get('Flow Type', 'port'), - 'bidir': cfg['biDirectional'], + 'bidir': bidirectional, 'multistream': int(multistream), 'stream_type': stream_type, 'pre_installed_flows' : pre_installed_flows, @@ -152,29 +161,36 @@ class TestCase(object): if not self._vswitch_none: self._add_flows(vswitch_ctl) - with traffic_ctl: - traffic_ctl.send_traffic(self._traffic) + # run traffic generator if requested, otherwise wait for manual termination + if S.getValue('mode') == 'trafficgen-off': + time.sleep(2) + self._logger.debug("All is set. Please run traffic generator manually.") + input(os.linesep + "Press Enter to terminate vswitchperf..." + os.linesep + os.linesep) + else: + with traffic_ctl: + traffic_ctl.send_traffic(self._traffic) - # dump vswitch flows before they are affected by VNF termination - if not self._vswitch_none: - vswitch_ctl.dump_vswitch_flows() + # dump vswitch flows before they are affected by VNF termination + if not self._vswitch_none: + vswitch_ctl.dump_vswitch_flows() # umount hugepages if mounted self._umount_hugepages() - self._logger.debug("Traffic Results:") - traffic_ctl.print_results() - self._logger.debug("Collector Results:") collector.print_results() - output_file = os.path.join(self._results_dir, "result_" + self.name + - "_" + self.deployment + ".csv") + if S.getValue('mode') != 'trafficgen-off': + self._logger.debug("Traffic Results:") + traffic_ctl.print_results() + + output_file = os.path.join(self._results_dir, "result_" + self.name + + "_" + self.deployment + ".csv") - tc_results = self._append_results(traffic_ctl.get_results()) - TestCase._write_result_to_file(tc_results, output_file) + tc_results = self._append_results(traffic_ctl.get_results()) + TestCase._write_result_to_file(tc_results, output_file) - report.generate(output_file, tc_results, collector.get_results()) + report.generate(output_file, tc_results, collector.get_results()) def _append_results(self, results): """ @@ -287,7 +303,7 @@ class TestCase(object): return list(result.keys()) - def _add_flows(vswitch_ctl): + def _add_flows(self, vswitch_ctl): """Add flows to the vswitch :param vswitch_ctl vswitch controller diff --git a/vnfs/qemu/qemu.py b/vnfs/qemu/qemu.py index 536f1fd0..38394974 100644 --- a/vnfs/qemu/qemu.py +++ b/vnfs/qemu/qemu.py @@ -83,7 +83,7 @@ class IVnfQemu(IVnf): '-nographic', '-vnc', str(vnc), '-name', name, '-snapshot', '-net none', '-no-reboot', '-drive', - 'if=scsi,type=raw,file=fat:rw:%s,snapshot=off' % + 'if=scsi,format=raw,file=fat:rw:%s,snapshot=off' % S.getValue('GUEST_SHARE_DIR')[self._number], ] self._configure_logging() @@ -27,6 +27,7 @@ import shutil import unittest import xmlrunner import locale +import copy sys.dont_write_bytecode = True @@ -37,6 +38,9 @@ from testcases import TestCase from tools import tasks from tools.pkt_gen import trafficgen from tools.opnfvdashboard import opnfvdashboard +from tools.pkt_gen.trafficgen.trafficgenhelper import TRAFFIC_DEFAULTS +from conf import get_test_param +import core.component_factory as component_factory VERBOSITY_LEVELS = { 'debug': logging.DEBUG, @@ -133,6 +137,11 @@ def parse_arguments(): To run all tests omit both positional args and --tests arg.') group = parser.add_argument_group('test selection options') + group.add_argument('-m', '--mode', help='vsperf mode of operation;\ + Values: "normal" - execute vSwitch, VNF and traffic generator;\ + "trafficgen" - execute only traffic generator; "trafficgen-off" \ + - execute vSwitch and VNF', default='normal') + group.add_argument('-f', '--test-spec', help='test specification file') group.add_argument('-d', '--test-dir', help='directory containing tests') group.add_argument('-t', '--tests', help='Comma-separated list of terms \ @@ -332,7 +341,6 @@ def main(): check_and_set_locale() # configure trafficgens - if args['trafficgen']: trafficgens = Loader().get_trafficgens() if args['trafficgen'] not in trafficgens: @@ -387,119 +395,132 @@ def main(): tmp_gl.append(guest_loopback) settings.setValue('GUEST_LOOPBACK', tmp_gl) + settings.setValue('mode', args['mode']) + # generate results directory name date = datetime.datetime.fromtimestamp(time.time()) results_dir = "results_" + date.strftime('%Y-%m-%d_%H-%M-%S') results_path = os.path.join(settings.getValue('LOG_DIR'), results_dir) - # configure tests - testcases = settings.getValue('PERFORMANCE_TESTS') - all_tests = [] - for cfg in testcases: - try: - all_tests.append(TestCase(cfg, results_path)) - except (Exception) as _: - logger.exception("Failed to create test: %s", - cfg.get('Name', '<Name not set>')) - raise - - # if required, handle list-* operations - - if args['list']: - print("Available Tests:") - print("======") - for test in all_tests: - print('* %-18s%s' % ('%s:' % test.name, test.desc)) - exit() - - if args['list_trafficgens']: - print(Loader().get_trafficgens_printable()) - exit() - - if args['list_collectors']: - print(Loader().get_collectors_printable()) - exit() - - if args['list_vswitches']: - print(Loader().get_vswitches_printable()) - exit() - - if args['list_fwdapps']: - print(Loader().get_pktfwds_printable()) - exit() - - if args['list_vnfs']: - print(Loader().get_vnfs_printable()) - exit() - - if args['list_settings']: - print(str(settings)) - exit() - - # select requested tests - if args['exact_test_name'] and args['tests']: - logger.error("Cannot specify tests with both positional args and --test.") - sys.exit(1) - - if args['exact_test_name']: - exact_names = args['exact_test_name'] - # positional args => exact matches only - selected_tests = [test for test in all_tests if test.name in exact_names] - elif args['tests']: - # --tests => apply filter to select requested tests - selected_tests = apply_filter(all_tests, args['tests']) - else: - # Default - run all tests - selected_tests = all_tests - - if not selected_tests: - logger.error("No tests matched --test option or positional args. Done.") - sys.exit(1) - # create results directory if not os.path.exists(results_path): logger.info("Creating result directory: " + results_path) os.makedirs(results_path) - # run tests - suite = unittest.TestSuite() - for test in selected_tests: - try: - if vswitch_none: - if test.deployment.lower() != 'p2p': - logging.error('\'none\' vswitch option supported only' - ' for p2p deployment.') - sys.exit(1) - test.run() - suite.addTest(MockTestCase('', True, test.name)) - #pylint: disable=broad-except - except (Exception) as ex: - logger.exception("Failed to run test: %s", test.name) - suite.addTest(MockTestCase(str(ex), False, test.name)) - logger.info("Continuing with next test...") - - if settings.getValue('XUNIT'): - xmlrunner.XMLTestRunner( - output=settings.getValue('XUNIT_DIR'), outsuffix="", - verbosity=0).run(suite) - - if args['opnfvpod']: - pod_name = args['opnfvpod'] - installer_name = settings.getValue('OPNFV_INSTALLER') - opnfv_url = settings.getValue('OPNFV_URL') - pkg_list = settings.getValue('PACKAGE_LIST') - - int_data = {'cuse': False, - 'vanilla': False, - 'pod': pod_name, - 'installer': installer_name, - 'pkg_list': pkg_list, - 'db_url': opnfv_url} - if settings.getValue('VSWITCH').endswith('Vanilla'): - int_data['vanilla'] = True - if settings.getValue('VNF').endswith('Cuse'): - int_data['cuse'] = True - opnfvdashboard.results2opnfv_dashboard(results_path, int_data) + if settings.getValue('mode') == 'trafficgen': + # execute only traffic generator + logging.debug("Executing traffic generator:") + loader = Loader() + # 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), + 'multistream': int(get_test_param('multistream', 0)), + 'stream_type': get_test_param('stream_type', 'L4'), + 'frame_rate': int(get_test_param('iload', 100))}) + + traffic_ctl = component_factory.create_traffic( + traffic['traffic_type'], + loader.get_trafficgen_class()) + with traffic_ctl: + traffic_ctl.send_traffic(traffic) + logging.debug("Traffic Results:") + traffic_ctl.print_results() + else: + # configure tests + testcases = settings.getValue('PERFORMANCE_TESTS') + all_tests = [] + for cfg in testcases: + try: + all_tests.append(TestCase(cfg, results_path)) + except (Exception) as _: + logger.exception("Failed to create test: %s", + cfg.get('Name', '<Name not set>')) + raise + + # if required, handle list-* operations + + if args['list']: + print("Available Tests:") + print("======") + for test in all_tests: + print('* %-18s%s' % ('%s:' % test.name, test.desc)) + exit() + + if args['list_trafficgens']: + print(Loader().get_trafficgens_printable()) + exit() + + if args['list_collectors']: + print(Loader().get_collectors_printable()) + exit() + + if args['list_vswitches']: + print(Loader().get_vswitches_printable()) + exit() + + if args['list_vnfs']: + print(Loader().get_vnfs_printable()) + exit() + + if args['list_settings']: + print(str(settings)) + exit() + + # select requested tests + if args['exact_test_name'] and args['tests']: + logger.error("Cannot specify tests with both positional args and --test.") + sys.exit(1) + + if args['exact_test_name']: + exact_names = args['exact_test_name'] + # positional args => exact matches only + selected_tests = [test for test in all_tests if test.name in exact_names] + elif args['tests']: + # --tests => apply filter to select requested tests + selected_tests = apply_filter(all_tests, args['tests']) + else: + # Default - run all tests + selected_tests = all_tests + + if not selected_tests: + logger.error("No tests matched --test option or positional args. Done.") + sys.exit(1) + + # run tests + suite = unittest.TestSuite() + for test in selected_tests: + try: + test.run() + suite.addTest(MockTestCase('', True, test.name)) + #pylint: disable=broad-except + except (Exception) as ex: + logger.exception("Failed to run test: %s", test.name) + suite.addTest(MockTestCase(str(ex), False, test.name)) + logger.info("Continuing with next test...") + + if settings.getValue('XUNIT'): + xmlrunner.XMLTestRunner( + output=settings.getValue('XUNIT_DIR'), outsuffix="", + verbosity=0).run(suite) + + if args['opnfvpod']: + pod_name = args['opnfvpod'] + installer_name = settings.getValue('OPNFV_INSTALLER') + opnfv_url = settings.getValue('OPNFV_URL') + pkg_list = settings.getValue('PACKAGE_LIST') + + int_data = {'cuse': False, + 'vanilla': False, + 'pod': pod_name, + 'installer': installer_name, + 'pkg_list': pkg_list, + 'db_url': opnfv_url} + if settings.getValue('VSWITCH').endswith('Vanilla'): + int_data['vanilla'] = True + if settings.getValue('VNF').endswith('Cuse'): + int_data['cuse'] = True + opnfvdashboard.results2opnfv_dashboard(results_path, int_data) #remove directory if no result files were created. if os.path.exists(results_path): |