From 02c8ed97e27b6e417945d27d4d3c2ab8e7dbfa7e Mon Sep 17 00:00:00 2001 From: ahothan Date: Tue, 16 Jan 2018 12:46:21 -0800 Subject: [NFVBENCH-62] Add support for non-openstack environments Add Unit test to validate non-openstack with dummy traffic gen Change-Id: I359ddb7d43169f706d8262842af975d5b4675a3a Signed-off-by: ahothan --- nfvbench/cfg.default.yaml | 10 +++++++--- nfvbench/chain_clients.py | 18 +++++++++++------- nfvbench/chain_managers.py | 30 ++++++++++++++++++------------ nfvbench/nfvbench.py | 22 ++++++++++++++++------ nfvbench/specs.py | 3 ++- nfvbench/summarizer.py | 14 ++++++++++---- nfvbench/traffic_gen/dummy.py | 10 ++++++++++ test/test_nfvbench.py | 37 ++++++++++++++++++++++++------------- 8 files changed, 98 insertions(+), 46 deletions(-) diff --git a/nfvbench/cfg.default.yaml b/nfvbench/cfg.default.yaml index bc8921d..07d48f3 100644 --- a/nfvbench/cfg.default.yaml +++ b/nfvbench/cfg.default.yaml @@ -18,6 +18,13 @@ # Fields that can be over-ridden at the command line are marked with the corresponding # option, e.g. "--interval" +# The OpenStack openrc file to use (must be a valid full pathname). If running +# in a container, this path must be valid in the container. +# +# The only case where this field can be empty is when measuring a system that does not run +# OpenStack or when OpenStack APIs are not accessible or OpenStack APis use is not +# desirable. In that case the EXT service chain must be used. +openrc_file: # Forwarder to use in nfvbenchvm image. Available options: ['vpp', 'testpmd'] vm_forwarder: testpmd @@ -195,9 +202,6 @@ traffic_generator: # ----------------------------------------------------------------------------- # These variables are not likely to be changed -# The openrc file -openrc_file: - # Number of seconds to wait for VMs to pass traffic in both directions check_traffic_time_sec: 200 diff --git a/nfvbench/chain_clients.py b/nfvbench/chain_clients.py index 7106129..faf7c2a 100644 --- a/nfvbench/chain_clients.py +++ b/nfvbench/chain_clients.py @@ -416,7 +416,8 @@ class BasicStageClient(object): Creates two networks and spawn a VM which act as a loop VM connected with the two networks. """ - self._setup_openstack_clients() + if self.cred: + self._setup_openstack_clients() def dispose(self, only_vm=False): """ @@ -448,12 +449,15 @@ class EXTStageClient(BasicStageClient): super(EXTStageClient, self).setup() # Lookup two existing networks - for net_name in [self.config.external_networks.left, self.config.external_networks.right]: - net = self._lookup_network(net_name) - if net: - self.nets.append(net) - else: - raise StageClientException('Existing network {} cannot be found.'.format(net_name)) + if self.cred: + for net_name in [self.config.external_networks.left, + self.config.external_networks.right]: + net = self._lookup_network(net_name) + if net: + self.nets.append(net) + else: + raise StageClientException('Existing network {} cannot be found.'. + format(net_name)) class PVPStageClient(BasicStageClient): diff --git a/nfvbench/chain_managers.py b/nfvbench/chain_managers.py index 8b605aa..087c751 100644 --- a/nfvbench/chain_managers.py +++ b/nfvbench/chain_managers.py @@ -96,11 +96,12 @@ class StatsManager(object): raise exc def _get_data(self): - return self.worker.get_data() + return self.worker.get_data() if self.worker else {} def _get_network(self, traffic_port, index=None, reverse=False): interfaces = [self.clients['traffic'].get_interface(traffic_port)] - interfaces.extend(self.worker.get_network_interfaces(index)) + if self.worker: + interfaces.extend(self.worker.get_network_interfaces(index)) return Network(interfaces, reverse) def _config_interfaces(self): @@ -127,13 +128,14 @@ class StatsManager(object): return self.interval_collector.get() if self.interval_collector else [] def get_version(self): - return self.worker.get_version() + return self.worker.get_version() if self.worker else {} def run(self): """ Run analysis in both direction and return the analysis """ - self.worker.run() + if self.worker: + self.worker.run() stats = self._generate_traffic() result = { @@ -157,7 +159,7 @@ class StatsManager(object): return result def get_compute_nodes_bios(self): - return self.worker.get_compute_nodes_bios() + return self.worker.get_compute_nodes_bios() if self.worker else {} @staticmethod def get_analysis(nets): @@ -176,7 +178,8 @@ class StatsManager(object): return packet_analyzer.get_analysis() def close(self): - self.worker.close() + if self.worker: + self.worker.close() class PVPStatsManager(StatsManager): @@ -229,10 +232,13 @@ class EXTStatsManager(StatsManager): StatsManager.__init__(self, config, clients, specs, factory, vlans, notifier) def _setup(self): - WORKER_CLASS = self.factory.get_chain_worker(self.specs.openstack.encaps, - self.config.service_chain) - self.worker = WORKER_CLASS(self.config, self.clients, self.specs) - self.worker.set_vlans(self.vlans) + if self.specs.openstack: + WORKER_CLASS = self.factory.get_chain_worker(self.specs.openstack.encaps, + self.config.service_chain) + self.worker = WORKER_CLASS(self.config, self.clients, self.specs) + self.worker.set_vlans(self.vlans) - if not self.config.no_int_config: - self._config_interfaces() + if not self.config.no_int_config: + self._config_interfaces() + else: + self.worker = None diff --git a/nfvbench/nfvbench.py b/nfvbench/nfvbench.py index 6f59e24..8c88248 100644 --- a/nfvbench/nfvbench.py +++ b/nfvbench/nfvbench.py @@ -58,7 +58,8 @@ class NFVBench(object): self.config_plugin = config_plugin self.factory = factory self.notifier = notifier - self.cred = credentials.Credentials(config.openrc_file, None, False) + self.cred = credentials.Credentials(config.openrc_file, None, False) \ + if config.openrc_file else None self.chain_runner = None self.specs = Specs() self.specs.set_openstack_spec(openstack_spec) @@ -94,10 +95,6 @@ class NFVBench(object): result = { "date": datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), "nfvbench_version": __version__, - "openstack_spec": { - "vswitch": self.specs.openstack.vswitch, - "encaps": self.specs.openstack.encaps - }, "config": self.config_plugin.prepare_results_config(copy.deepcopy(self.config)), "benchmarks": { "network": { @@ -106,6 +103,9 @@ class NFVBench(object): } } } + if self.specs.openstack: + result['openstack_spec'] = {"vswitch": self.specs.openstack.vswitch, + "encaps": self.specs.openstack.encaps} result['benchmarks']['network']['versions'].update(self.config_plugin.get_version()) except Exception: status = NFVBench.STATUS_ERROR @@ -444,7 +444,6 @@ def main(): # create config plugin for this platform config_plugin = factory.get_config_plugin_class()(config) config = config_plugin.get_config() - openstack_spec = config_plugin.get_openstack_spec() opts, unknown_opts = parse_opts_from_cli() log.set_level(debug=opts.debug) @@ -520,6 +519,14 @@ def main(): print json.dumps(config, sort_keys=True, indent=4) sys.exit(0) + # check that an empty openrc file (no OpenStack) is only allowed + # with EXT chain + if not config.openrc_file: + if config.service_chain == ChainType.EXT: + LOG.info('EXT chain with OpenStack mode disabled') + else: + raise Exception("openrc_file is empty in the configuration and is required") + # update the config in the config plugin as it might have changed # in a copy of the dict (config plugin still holds the original dict) config_plugin.set_config(config) @@ -528,6 +535,9 @@ def main(): if config.log_file: log.add_file_logger(config.log_file) + openstack_spec = config_plugin.get_openstack_spec() if config.openrc_file \ + else None + nfvbench_instance = NFVBench(config, openstack_spec, config_plugin, factory) if opts.server: diff --git a/nfvbench/specs.py b/nfvbench/specs.py index 7a24d5c..a84a55f 100644 --- a/nfvbench/specs.py +++ b/nfvbench/specs.py @@ -75,7 +75,8 @@ class OpenStackSpec(object): class RunSpec(object): def __init__(self, no_vswitch_access, openstack_spec): - self.use_vswitch = (not no_vswitch_access) and openstack_spec.vswitch != "BASIC" + self.use_vswitch = (not no_vswitch_access) and openstack_spec \ + and openstack_spec.vswitch != "BASIC" class Specs(object): diff --git a/nfvbench/summarizer.py b/nfvbench/summarizer.py index 1676e93..0ff9c48 100644 --- a/nfvbench/summarizer.py +++ b/nfvbench/summarizer.py @@ -221,18 +221,24 @@ class NFVBenchSummarizer(Summarizer): self.__record_init() self.__summarize() + def __get_openstack_spec(self, property): + try: + return self.result['openstack_spec'][property] + except KeyError: + return '' + def __summarize(self): self._put() self._put('========== NFVBench Summary ==========') self._put('Date:', self.result['date']) self._put('NFVBench version', self.result['nfvbench_version']) self._put('Openstack Neutron:', { - 'vSwitch': self.result['openstack_spec']['vswitch'], - 'Encapsulation': self.result['openstack_spec']['encaps'] + 'vSwitch': self.__get_openstack_spec('vswitch'), + 'Encapsulation': self.__get_openstack_spec('encaps') }) self.__record_header_put('version', self.result['nfvbench_version']) - self.__record_header_put('vSwitch', self.result['openstack_spec']['vswitch']) - self.__record_header_put('Encapsulation', self.result['openstack_spec']['encaps']) + self.__record_header_put('vSwitch', self.__get_openstack_spec('vswitch')) + self.__record_header_put('Encapsulation', self.__get_openstack_spec('encaps')) self._put('Benchmarks:') with self._create_block(): self._put('Networks:') diff --git a/nfvbench/traffic_gen/dummy.py b/nfvbench/traffic_gen/dummy.py index b43030f..6f57f4d 100644 --- a/nfvbench/traffic_gen/dummy.py +++ b/nfvbench/traffic_gen/dummy.py @@ -30,6 +30,7 @@ class DummyTG(AbstractTrafficGenerator): self.l2_frame_size = 0 self.duration_sec = self.config.duration_sec self.intf_speed = config.generator_config.intf_speed + self.set_response_curve() def get_version(self): return "0.1" @@ -154,6 +155,9 @@ class DummyTG(AbstractTrafficGenerator): result['total_tx_rate'] = total_tx_pps return result + def get_macs(self): + return ['00.00.00.00.00.01', '00.00.00.00.00.02'] + def clear_stats(self): pass @@ -165,3 +169,9 @@ class DummyTG(AbstractTrafficGenerator): def cleanup(self): pass + + def set_mode(self): + pass + + def resolve_arp(self): + return True diff --git a/test/test_nfvbench.py b/test/test_nfvbench.py index fc8174f..113ecfd 100644 --- a/test/test_nfvbench.py +++ b/test/test_nfvbench.py @@ -13,7 +13,7 @@ # License for the specific language governing permissions and limitations # under the License. # - +import json import logging import os import sys @@ -429,8 +429,6 @@ from nfvbench.traffic_client import IpBlock from nfvbench.traffic_client import TrafficClient from nfvbench.traffic_client import TrafficGeneratorFactory -# pylint: enable=wrong-import-position,ungrouped-imports - def test_ip_block(): ipb = IpBlock('10.0.0.0', '0.0.0.1', 256) assert ipb.get_ip() == '10.0.0.0' @@ -595,16 +593,16 @@ def assert_ndr_pdr(stats, ndr, ndr_dr, pdr, pdr_dr): assert_equivalence(pdr, stats['pdr']['rate_percent']) assert_equivalence(pdr_dr, stats['pdr']['stats']['overall']['drop_percentage']) -def get_traffic_client(): - config = AttrDict({ +def get_dummy_tg_config(chain_type, rate): + return AttrDict({ 'traffic_generator': {'host_name': 'nfvbench_tg', 'default_profile': 'dummy', 'generator_profile': [{'name': 'dummy', 'tool': 'dummy', 'ip': '127.0.0.1', 'intf_speed': '10Gbps', - 'interfaces': [{'port': 0, 'pci': 0}, - {'port': 1, 'pci': 0}]}], + 'interfaces': [{'port': 0, 'pci': '0.0'}, + {'port': 1, 'pci': '0.0'}]}], 'ip_addrs_step': '0.0.0.1', 'ip_addrs': ['10.0.0.0/8', '20.0.0.0/8'], 'tg_gateway_ip_addrs': ['1.1.0.100', '2.2.0.100'], @@ -613,22 +611,25 @@ def get_traffic_client(): 'gateway_ip_addrs_step': '0.0.0.1', 'udp_src_port': None, 'udp_dst_port': None}, - 'generator_profile': 'dummy', - 'service_chain': 'PVP', + 'service_chain': chain_type, 'service_chain_count': 1, 'flow_count': 10, 'vlan_tagging': True, 'no_arp': False, 'duration_sec': 1, 'interval_sec': 1, - 'single_run': False, - 'ndr_run': True, - 'pdr_run': True, - 'rate': 'ndr_pdr', + 'rate': rate, 'check_traffic_time_sec': 200, 'generic_poll_sec': 2, 'measurement': {'NDR': 0.001, 'PDR': 0.1, 'load_epsilon': 0.1}, }) + +def get_traffic_client(): + config = get_dummy_tg_config('PVP', 'ndr_pdr') + config['ndr_run'] = True + config['pdr_run'] = True + config['generator_profile'] = 'dummy' + config['single_run'] = False generator_factory = TrafficGeneratorFactory(config) config.generator_config = generator_factory.get_generator_config(config.generator_profile) traffic_client = TrafficClient(config, skip_sleep=True) @@ -680,3 +681,13 @@ def test_ndr_pdr_low_cpu(): # import pprint # pp = pprint.PrettyPrinter(indent=4) # pp.pprint(results) + +import nfvbench.nfvbench + +def test_no_openstack(): + config = get_dummy_tg_config('EXT', '1000pps') + config.openrc_file = None + old_argv = sys.argv + sys.argv = [old_argv[0], '-c', json.dumps(config)] + nfvbench.nfvbench.main() + sys.argv = old_argv -- cgit 1.2.3-korg