diff options
Diffstat (limited to 'yardstick')
16 files changed, 304 insertions, 256 deletions
diff --git a/yardstick/benchmark/contexts/model.py b/yardstick/benchmark/contexts/model.py index facfab892..d3c03e100 100644 --- a/yardstick/benchmark/contexts/model.py +++ b/yardstick/benchmark/contexts/model.py @@ -237,6 +237,7 @@ class Server(Object): # pragma: no cover self._flavor = attrs["flavor"] self.user_data = attrs.get('user_data', '') + self.availability_zone = attrs.get('availability_zone') Server.list.append(self) @@ -329,12 +330,10 @@ class Server(Object): # pragma: no cover mountpoint=self.volume_mountpoint) template.add_server(server_name, self.image, flavor=self.flavor_name, - flavors=self.context.flavors, - ports=port_name_list, - user=self.user, - key_name=self.keypair_name, - user_data=self.user_data, - scheduler_hints=scheduler_hints) + flavors=self.context.flavors, ports=port_name_list, + scheduler_hints=scheduler_hints, user=self.user, + key_name=self.keypair_name, user_data=self.user_data, + availability_zone=self.availability_zone) def add_to_template(self, template, networks, scheduler_hints=None): """adds to the template one or more servers (instances)""" diff --git a/yardstick/benchmark/core/scenario.py b/yardstick/benchmark/core/scenario.py index cd119c24c..28eb65230 100644 --- a/yardstick/benchmark/core/scenario.py +++ b/yardstick/benchmark/core/scenario.py @@ -10,7 +10,6 @@ """ Handler for yardstick command 'scenario' """ from __future__ import absolute_import -from __future__ import print_function from yardstick.benchmark.scenarios.base import Scenario from yardstick.benchmark.core import print_hbar @@ -27,9 +26,9 @@ class Scenarios(object): # pragma: no cover print_hbar(78) print("| %-16s | %-60s" % ("Type", "Description")) print_hbar(78) - for stype in types: - print("| %-16s | %-60s" % (stype.__scenario_type__, - stype.__doc__.split("\n")[0])) + for scenario_class in types: + print("| %-16s | %-60s" % (scenario_class.get_scenario_type(), + scenario_class.get_description())) print_hbar(78) def show(self, args): diff --git a/yardstick/benchmark/scenarios/availability/ha_tools/fault_process_kill.bash b/yardstick/benchmark/scenarios/availability/ha_tools/fault_process_kill.bash index a865b6551..eec86e133 100755 --- a/yardstick/benchmark/scenarios/availability/ha_tools/fault_process_kill.bash +++ b/yardstick/benchmark/scenarios/availability/ha_tools/fault_process_kill.bash @@ -20,6 +20,11 @@ if [ "$process_name" = "keystone" ]; then do kill -9 "${pid}" done +elif [ "$process_name" = "haproxy" ]; then + for pid in $(pgrep -f "^/usr/[^ ]*/${process_name}"); + do + kill -9 "${pid}" + done else for pid in $(pgrep -f "/usr/.*/${process_name}"); do diff --git a/yardstick/benchmark/scenarios/base.py b/yardstick/benchmark/scenarios/base.py index 3cb138dd8..7af85834c 100644 --- a/yardstick/benchmark/scenarios/base.py +++ b/yardstick/benchmark/scenarios/base.py @@ -64,6 +64,20 @@ class Scenario(object): raise RuntimeError("No such scenario type %s" % scenario_type) + @classmethod + def get_scenario_type(cls): + """Return a string with the scenario type, if defined""" + return str(getattr(cls, '__scenario_type__', None)) + + @classmethod + def get_description(cls): + """Return a single line string with the class description + + This function will retrieve the class docstring and return the first + line, or 'None' if it's empty. + """ + return cls.__doc__.splitlines()[0] if cls.__doc__ else str(None) + def _push_to_outputs(self, keys, values): return dict(zip(keys, values)) diff --git a/yardstick/network_services/nfvi/resource.py b/yardstick/network_services/nfvi/resource.py index 5b96aaf29..adf4d8ae6 100644 --- a/yardstick/network_services/nfvi/resource.py +++ b/yardstick/network_services/nfvi/resource.py @@ -55,8 +55,7 @@ class ResourceProfile(object): DEFAULT_TIMEOUT = 3600 OVS_SOCKET_PATH = "/usr/local/var/run/openvswitch/db.sock" - def __init__(self, mgmt, port_names=None, cores=None, plugins=None, - interval=None, timeout=None): + def __init__(self, mgmt, port_names=None, plugins=None, interval=None, timeout=None): if plugins is None: self.plugins = {} @@ -91,7 +90,6 @@ class ResourceProfile(object): plugins = collectd_options.get("plugins", {}) interval = collectd_options.get("interval") - # use default cores = None to MatchAllCores return cls(node, plugins=plugins, interval=interval, timeout=timeout) def check_if_sa_running(self, process): @@ -245,19 +243,6 @@ class ResourceProfile(object): } self._provide_config_file(config_file_path, self.COLLECTD_CONF, kwargs) - def _setup_intel_pmu(self, connection, bin_path): - pmu_event_path = os.path.join(bin_path, "pmu_event.json") - try: - self.plugins["intel_pmu"]["pmu_event_path"] = pmu_event_path - except KeyError: - # if intel_pmu is not a dict, force it into a dict - self.plugins["intel_pmu"] = {"pmu_event_path": pmu_event_path} - LOG.debug("Downloading event list for pmu_stats plugin") - cmd = 'cd {0}; PMU_EVENTS_PATH={1} python event_download_local.py'.format( - bin_path, pmu_event_path) - cmd = "sudo bash -c '{}'".format(cmd) - connection.execute(cmd) - def _setup_ovs_stats(self, connection): try: socket_path = self.plugins["ovs_stats"].get("ovs_socket_path", self.OVS_SOCKET_PATH) @@ -284,8 +269,6 @@ class ResourceProfile(object): # connection.execute("sudo %s '%s' '%s'" % ( # collectd_installer, http_proxy, https_proxy)) return - if "intel_pmu" in self.plugins: - self._setup_intel_pmu(connection, bin_path) if "ovs_stats" in self.plugins: self._setup_ovs_stats(connection) diff --git a/yardstick/network_services/traffic_profile/prox_mpls_tag_untag.py b/yardstick/network_services/traffic_profile/prox_mpls_tag_untag.py deleted file mode 100644 index 0e1048b5d..000000000 --- a/yardstick/network_services/traffic_profile/prox_mpls_tag_untag.py +++ /dev/null @@ -1,99 +0,0 @@ -# Copyright (c) 2016-2017 Intel Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -""" Fixed traffic profile definitions """ - -from __future__ import absolute_import - -import logging - -from yardstick.network_services.traffic_profile.prox_profile import ProxProfile - -LOG = logging.getLogger(__name__) - - -class ProxMplsTagUntagProfile(ProxProfile): - """ - This profile adds a single stream at the beginning of the traffic session - """ - - def __init__(self, tp_config): - super(ProxMplsTagUntagProfile, self).__init__(tp_config) - self.current_lower = self.lower_bound - self.current_upper = self.upper_bound - - @property - def delta(self): - return self.current_upper - self.current_lower - - @property - def mid_point(self): - return (self.current_lower + self.current_upper) / 2 - - def bounds_iterator(self, logger=None): - self.current_lower = self.lower_bound - self.current_upper = self.upper_bound - - test_value = self.current_upper - while abs(self.delta) >= self.precision: - if logger: - logger.debug("New interval [%s, %s), precision: %d", self.current_lower, - self.current_upper, self.step_value) - logger.info("Testing with value %s", test_value) - - yield test_value - test_value = self.mid_point - - def run_test_with_pkt_size(self, traffic_gen, pkt_size, duration): - """Run the test for a single packet size. - - :param traffic_gen: traffic generator instance - :type traffic_gen: TrafficGen - :param pkt_size: The packet size to test with. - :type pkt_size: int - :param duration: The duration for each try. - :type duration: int - - """ - - LOG.info("Testing with packet size %d", pkt_size) - - # Binary search assumes the lower value of the interval is - # successful and the upper value is a failure. - # The first value that is tested, is the maximum value. If that - # succeeds, no more searching is needed. If it fails, a regular - # binary search is performed. - # - # The test_value used for the first iteration of binary search - # is adjusted so that the delta between this test_value and the - # upper bound is a power-of-2 multiple of precision. In the - # optimistic situation where this first test_value results in a - # success, the binary search will complete on an integer multiple - # of the precision, rather than on a fraction of it. - - # throughput and packet loss from the most recent successful test - successful_pkt_loss = 0.0 - for test_value in self.bounds_iterator(LOG): - result, port_samples = self._profile_helper.run_test(pkt_size, duration, - test_value, self.tolerated_loss) - - if result.success: - LOG.debug("Success! Increasing lower bound") - self.current_lower = test_value - successful_pkt_loss = result.pkt_loss - else: - LOG.debug("Failure... Decreasing upper bound") - self.current_upper = test_value - - samples = result.get_samples(pkt_size, successful_pkt_loss, port_samples) - self.queue.put(samples) diff --git a/yardstick/network_services/traffic_profile/rfc2544.py b/yardstick/network_services/traffic_profile/rfc2544.py index 16e809b65..b1ca8a345 100644 --- a/yardstick/network_services/traffic_profile/rfc2544.py +++ b/yardstick/network_services/traffic_profile/rfc2544.py @@ -62,7 +62,7 @@ class RFC2544Profile(TrexProfile): self.generator.rfc2544_helper.correlated_traffic: continue for intf in intfs: - port = self.generator.vnfd_helper.port_num(intf) + port = self.generator.port_num(intf) self.ports.append(port) self.generator.client.add_streams(self.get_streams(profile_data), ports=port) @@ -170,7 +170,7 @@ class RFC2544Profile(TrexProfile): self.generator.rfc2544_helper.correlated_traffic: continue for intf in intfs: - port = self.generator.vnfd_helper.port_num(intf) + port = self.generator.port_num(intf) self.ports.append(port) self.generator.client.add_streams(self.get_streams(profile_data), ports=port) diff --git a/yardstick/network_services/vnf_generic/vnf/base.py b/yardstick/network_services/vnf_generic/vnf/base.py index 778119568..8ed754dce 100644 --- a/yardstick/network_services/vnf_generic/vnf/base.py +++ b/yardstick/network_services/vnf_generic/vnf/base.py @@ -13,11 +13,14 @@ # limitations under the License. """ Base class implementation for generic vnf implementation """ -from __future__ import absolute_import +import abc + import logging +import six from yardstick.network_services.helpers.samplevnf_helper import PortPairs + LOG = logging.getLogger(__name__) @@ -207,6 +210,7 @@ class GenericVNF(VNFObject): raise NotImplementedError() +@six.add_metaclass(abc.ABCMeta) class GenericTrafficGen(GenericVNF): """ Class providing file-like API for generic traffic generator """ @@ -215,18 +219,29 @@ class GenericTrafficGen(GenericVNF): self.runs_traffic = True self.traffic_finished = False + @abc.abstractmethod def run_traffic(self, traffic_profile): - """ Generate traffic on the wire according to the given params. - Method is non-blocking, returns immediately when traffic process + """Generate traffic on the wire according to the given params. + + This method is non-blocking, returns immediately when traffic process is running. Mandatory. :param traffic_profile: :return: True/False """ - raise NotImplementedError() + + @abc.abstractmethod + def terminate(self): + """After this method finishes, all traffic processes should stop. + + Mandatory. + + :return: True/False + """ def listen_traffic(self, traffic_profile): - """ Listen to traffic with the given parameters. + """Listen to traffic with the given parameters. + Method is non-blocking, returns immediately when traffic process is running. Optional. @@ -236,16 +251,20 @@ class GenericTrafficGen(GenericVNF): pass def verify_traffic(self, traffic_profile): - """ Verify captured traffic after it has ended. Optional. + """Verify captured traffic after it has ended. + + Optional. :param traffic_profile: :return: dict """ pass - def terminate(self): - """ After this method finishes, all traffic processes should stop. Mandatory. + def wait_for_instantiate(self): + """Wait for an instance to load. + + Optional. :return: True/False """ - raise NotImplementedError() + pass diff --git a/yardstick/network_services/vnf_generic/vnf/prox_helpers.py b/yardstick/network_services/vnf_generic/vnf/prox_helpers.py index ac5abfbcb..ba066333d 100644 --- a/yardstick/network_services/vnf_generic/vnf/prox_helpers.py +++ b/yardstick/network_services/vnf_generic/vnf/prox_helpers.py @@ -509,11 +509,6 @@ class ProxSocketHelper(object): def hz(self): return self.get_all_tot_stats()[3] - # Deprecated - # TODO: remove - def rx_stats(self, cores, task=0): - return self.core_stats(cores, task) - def core_stats(self, cores, task=0): """Get the receive statistics from the remote system""" rx = tx = drop = tsc = 0 @@ -1490,7 +1485,6 @@ class ProxVpeProfileHelper(ProxProfileHelper): if item_key != 'name': continue - for item_key, item_value in section: if item_value.startswith("cpe"): cpe_ports.append(tx_port_no) @@ -1595,3 +1589,192 @@ class ProxVpeProfileHelper(ProxProfileHelper): data_helper.latency = self.get_latency() return data_helper.result_tuple, data_helper.samples + + +class ProxlwAFTRProfileHelper(ProxProfileHelper): + + __prox_profile_type__ = "lwAFTR gen" + + def __init__(self, resource_helper): + super(ProxlwAFTRProfileHelper, self).__init__(resource_helper) + self._cores_tuple = None + self._ports_tuple = None + self.step_delta = 5 + self.step_time = 0.5 + + @property + def _lwaftr_cores(self): + if not self._cores_tuple: + self._cores_tuple = self._get_cores_gen_lwaftr() + return self._cores_tuple + + @property + def tun_cores(self): + return self._lwaftr_cores[0] + + @property + def inet_cores(self): + return self._lwaftr_cores[1] + + @property + def _lwaftr_ports(self): + if not self._ports_tuple: + self._ports_tuple = self._get_ports_gen_lw_aftr() + return self._ports_tuple + + @property + def tun_ports(self): + return self._lwaftr_ports[0] + + @property + def inet_ports(self): + return self._lwaftr_ports[1] + + @property + def all_rx_cores(self): + return self.latency_cores + + def _get_cores_gen_lwaftr(self): + tun_cores = [] + inet_cores = [] + for section_name, section in self.resource_helper.setup_helper.prox_config_data: + if not section_name.startswith("core"): + continue + + if all(key != "mode" or value != self.PROX_CORE_GEN_MODE for key, value in section): + continue + + core_tuple = CoreSocketTuple(section_name) + core_tag = core_tuple.find_in_topology(self.cpu_topology) + for item_value in (v for k, v in section if k == 'name'): + if item_value.startswith('tun'): + tun_cores.append(core_tag) + elif item_value.startswith('inet'): + inet_cores.append(core_tag) + + return tun_cores, inet_cores + + def _get_ports_gen_lw_aftr(self): + tun_ports = [] + inet_ports = [] + + re_port = re.compile('port (\d+)') + for section_name, section in self.resource_helper.setup_helper.prox_config_data: + match = re_port.search(section_name) + if not match: + continue + + tx_port_no = int(match.group(1)) + for item_value in (v for k, v in section if k == 'name'): + if item_value.startswith('lwB4'): + tun_ports.append(tx_port_no) + elif item_value.startswith('inet'): + inet_ports.append(tx_port_no) + + return tun_ports, inet_ports + + @staticmethod + def _resize(len1, len2): + if len1 == len2: + return 1.0 + return 1.0 * len1 / len2 + + @contextmanager + def traffic_context(self, pkt_size, value): + # Tester is sending packets at the required speed already after + # setup_test(). Just get the current statistics, sleep the required + # amount of time and calculate packet loss. + tun_pkt_size = pkt_size + inet_pkt_size = pkt_size - 40 + ratio = 1.0 * (tun_pkt_size + 20) / (inet_pkt_size + 20) + + curr_up_speed = curr_down_speed = 0 + max_up_speed = max_down_speed = value + + max_up_speed = value / ratio + + # Adjust speed when multiple cores per port are used to generate traffic + if len(self.tun_ports) != len(self.tun_cores): + max_down_speed *= self._resize(len(self.tun_ports), len(self.tun_cores)) + if len(self.inet_ports) != len(self.inet_cores): + max_up_speed *= self._resize(len(self.inet_ports), len(self.inet_cores)) + + # Initialize cores + self.sut.stop_all() + time.sleep(0.5) + + # Flush any packets in the NIC RX buffers, otherwise the stats will be + # wrong. + self.sut.start(self.all_rx_cores) + time.sleep(0.5) + self.sut.stop(self.all_rx_cores) + time.sleep(0.5) + self.sut.reset_stats() + + self.sut.set_pkt_size(self.inet_cores, inet_pkt_size) + self.sut.set_pkt_size(self.tun_cores, tun_pkt_size) + + self.sut.reset_values(self.tun_cores) + self.sut.reset_values(self.inet_cores) + + # Set correct IP and UDP lengths in packet headers + # tun + # IPv6 length (byte 18): 58 for MAC(12), EthType(2), IPv6(40) , CRC(4) + self.sut.set_value(self.tun_cores, 18, tun_pkt_size - 58, 2) + # IP length (byte 56): 58 for MAC(12), EthType(2), CRC(4) + self.sut.set_value(self.tun_cores, 56, tun_pkt_size - 58, 2) + # UDP length (byte 78): 78 for MAC(12), EthType(2), IP(20), UDP(8), CRC(4) + self.sut.set_value(self.tun_cores, 78, tun_pkt_size - 78, 2) + + # INET + # IP length (byte 20): 22 for MAC(12), EthType(2), CRC(4) + self.sut.set_value(self.inet_cores, 16, inet_pkt_size - 18, 2) + # UDP length (byte 42): 42 for MAC(12), EthType(2), IP(20), UPD(8), CRC(4) + self.sut.set_value(self.inet_cores, 38, inet_pkt_size - 38, 2) + + LOG.info("Initializing SUT: sending lwAFTR packets") + self.sut.set_speed(self.inet_cores, curr_up_speed) + self.sut.set_speed(self.tun_cores, curr_down_speed) + time.sleep(4) + + # Ramp up the transmission speed. First go to the common speed, then + # increase steps for the faster one. + self.sut.start(self.tun_cores + self.inet_cores + self.latency_cores) + + LOG.info("Ramping up speed to %s up, %s down", max_up_speed, max_down_speed) + + while (curr_up_speed < max_up_speed) or (curr_down_speed < max_down_speed): + # The min(..., ...) takes care of 1) floating point rounding errors + # that could make curr_*_speed to be slightly greater than + # max_*_speed and 2) max_*_speed not being an exact multiple of + # self._step_delta. + if curr_up_speed < max_up_speed: + curr_up_speed = min(curr_up_speed + self.step_delta, max_up_speed) + if curr_down_speed < max_down_speed: + curr_down_speed = min(curr_down_speed + self.step_delta, max_down_speed) + + self.sut.set_speed(self.inet_cores, curr_up_speed) + self.sut.set_speed(self.tun_cores, curr_down_speed) + time.sleep(self.step_time) + + LOG.info("Target speeds reached. Starting real test.") + + yield + + self.sut.stop(self.tun_cores + self.inet_cores) + LOG.info("Test ended. Flushing NIC buffers") + self.sut.start(self.all_rx_cores) + time.sleep(3) + self.sut.stop(self.all_rx_cores) + + def run_test(self, pkt_size, duration, value, tolerated_loss=0.0): + data_helper = ProxDataHelper(self.vnfd_helper, self.sut, pkt_size, value, tolerated_loss) + + with data_helper, self.traffic_context(pkt_size, value): + with data_helper.measure_tot_stats(): + time.sleep(duration) + # Getting statistics to calculate PPS at right speed.... + data_helper.capture_tsc_hz() + data_helper.latency = self.get_latency() + + return data_helper.result_tuple, data_helper.samples diff --git a/yardstick/network_services/vnf_generic/vnf/sample_vnf.py b/yardstick/network_services/vnf_generic/vnf/sample_vnf.py index 08ec44f65..20e5895ee 100644 --- a/yardstick/network_services/vnf_generic/vnf/sample_vnf.py +++ b/yardstick/network_services/vnf_generic/vnf/sample_vnf.py @@ -22,7 +22,6 @@ import os import re import subprocess from collections import Mapping - from multiprocessing import Queue, Value, Process from six.moves import cStringIO @@ -30,7 +29,6 @@ from six.moves import cStringIO from yardstick.benchmark.contexts.base import Context from yardstick.benchmark.scenarios.networking.vnf_generic import find_relative_file from yardstick.common.process import check_if_process_failed -from yardstick.network_services.helpers.cpu import CpuSysCores from yardstick.network_services.helpers.samplevnf_helper import PortPairs from yardstick.network_services.helpers.samplevnf_helper import MultiPortConfig from yardstick.network_services.helpers.dpdkbindnic_helper import DpdkBindHelper @@ -97,7 +95,6 @@ class SetupEnvHelper(object): CFG_CONFIG = os.path.join(REMOTE_TMP, "sample_config") CFG_SCRIPT = os.path.join(REMOTE_TMP, "sample_script") - CORES = [] DEFAULT_CONFIG_TPL_CFG = "sample.cfg" PIPELINE_COMMAND = '' VNF_TYPE = "SAMPLE" @@ -126,9 +123,6 @@ class DpdkVnfSetupEnvHelper(SetupEnvHelper): APP_NAME = 'DpdkVnf' FIND_NET_CMD = "find /sys/class/net -lname '*{}*' -printf '%f'" - HW_DEFAULT_CORE = 3 - SW_DEFAULT_CORE = 2 - @staticmethod def _update_packet_type(ip_pipeline_cfg, traffic_options): match_str = 'pkt_type = ipv4' @@ -241,41 +235,6 @@ class DpdkVnfSetupEnvHelper(SetupEnvHelper): 'tool_path': tool_path, } - def _get_app_cpu(self): - if self.CORES: - return self.CORES - - vnf_cfg = self.scenario_helper.vnf_cfg - sys_obj = CpuSysCores(self.ssh_helper) - self.sys_cpu = sys_obj.get_core_socket() - num_core = int(vnf_cfg["worker_threads"]) - if vnf_cfg.get("lb_config", "SW") == 'HW': - num_core += self.HW_DEFAULT_CORE - else: - num_core += self.SW_DEFAULT_CORE - app_cpu = self.sys_cpu[str(self.socket)][:num_core] - return app_cpu - - def _get_cpu_sibling_list(self, cores=None): - if cores is None: - cores = self._get_app_cpu() - sys_cmd_template = "%s/cpu%s/topology/thread_siblings_list" - awk_template = "awk -F: '{ print $1 }' < %s" - sys_path = "/sys/devices/system/cpu/" - cpu_topology = [] - try: - for core in cores: - sys_cmd = sys_cmd_template % (sys_path, core) - cpu_id = self.ssh_helper.execute(awk_template % sys_cmd)[1] - cpu_topology.extend(cpu.strip() for cpu in cpu_id.split(',')) - - return cpu_topology - except Exception: - return [] - - def _validate_cpu_cfg(self): - return self._get_cpu_sibling_list() - def setup_vnf_environment(self): self._setup_dpdk() self.bound_pci = [v['virtual-interface']["vpci"] for v in self.vnfd_helper.interfaces] @@ -323,7 +282,6 @@ class DpdkVnfSetupEnvHelper(SetupEnvHelper): else: self.socket = 1 - cores = self._validate_cpu_cfg() # implicit ordering, presumably by DPDK port num, so pre-sort by port_num # this won't work because we don't have DPDK port numbers yet ports = sorted(self.vnfd_helper.interfaces, key=self.vnfd_helper.port_num) @@ -331,7 +289,7 @@ class DpdkVnfSetupEnvHelper(SetupEnvHelper): collectd_options = self.get_collectd_options() plugins = collectd_options.get("plugins", {}) # we must set timeout to be the same as the VNF otherwise KPIs will die before VNF - return ResourceProfile(self.vnfd_helper.mgmt_interface, port_names=port_names, cores=cores, + return ResourceProfile(self.vnfd_helper.mgmt_interface, port_names=port_names, plugins=plugins, interval=collectd_options.get("interval"), timeout=self.scenario_helper.timeout) @@ -433,6 +391,10 @@ class ClientResourceHelper(ResourceHelper): self.vnfd_helper.port_nums(self.vnfd_helper.port_pairs.downlink_ports) self.all_ports = self.vnfd_helper.port_nums(self.vnfd_helper.port_pairs.all_ports) + def port_num(self, intf): + # by default return port num + return self.vnfd_helper.port_num(intf) + def get_stats(self, *args, **kwargs): try: return self.client.get_stats(*args, **kwargs) @@ -933,10 +895,6 @@ class SampleVNFTrafficGen(GenericTrafficGen): self._tg_process = Process(name=name, target=self._start_server) self._tg_process.start() - def wait_for_instantiate(self): - # overridden by subclasses - return self._wait_for_process() - def _check_status(self): raise NotImplementedError @@ -980,24 +938,6 @@ class SampleVNFTrafficGen(GenericTrafficGen): return self._traffic_process.is_alive() - def listen_traffic(self, traffic_profile): - """ Listen to traffic with the given parameters. - Method is non-blocking, returns immediately when traffic process - is running. Optional. - - :param traffic_profile: - :return: True/False - """ - pass - - def verify_traffic(self, traffic_profile): - """ Verify captured traffic after it has ended. Optional. - - :param traffic_profile: - :return: dict - """ - pass - def collect_kpi(self): # check if the tg processes have exited for proc in (self._tg_process, self._traffic_process): diff --git a/yardstick/network_services/vnf_generic/vnf/tg_ixload.py b/yardstick/network_services/vnf_generic/vnf/tg_ixload.py index 612799ff5..61c045405 100644 --- a/yardstick/network_services/vnf_generic/vnf/tg_ixload.py +++ b/yardstick/network_services/vnf_generic/vnf/tg_ixload.py @@ -170,16 +170,9 @@ class IxLoadTrafficGen(SampleVNFTrafficGen): self.resource_helper.log() self.resource_helper.data = self.resource_helper.make_aggregates() - def listen_traffic(self, traffic_profile): - pass - def instantiate(self, scenario_cfg, context_cfg): super(IxLoadTrafficGen, self).instantiate(scenario_cfg, context_cfg) - def wait_for_instantiate(self): - # not needed for Ixload - pass - def terminate(self): call(["pkill", "-9", "http_ixload.py"]) super(IxLoadTrafficGen, self).terminate() diff --git a/yardstick/network_services/vnf_generic/vnf/tg_ping.py b/yardstick/network_services/vnf_generic/vnf/tg_ping.py index 9cd9f2574..30a917862 100644 --- a/yardstick/network_services/vnf_generic/vnf/tg_ping.py +++ b/yardstick/network_services/vnf_generic/vnf/tg_ping.py @@ -14,7 +14,6 @@ """ PING acts as traffic generation and vnf definitions based on IETS Spec """ from __future__ import absolute_import -from __future__ import print_function import logging import re @@ -135,14 +134,3 @@ class PingTrafficGen(SampleVNFTrafficGen): } self.setup_helper.setup_vnf_environment() - - def wait_for_instantiate(self): - pass - - def listen_traffic(self, traffic_profile): - """ Not needed for ping - - :param traffic_profile: - :return: - """ - pass diff --git a/yardstick/network_services/vnf_generic/vnf/tg_prox.py b/yardstick/network_services/vnf_generic/vnf/tg_prox.py index 40eda753f..151252ce8 100644 --- a/yardstick/network_services/vnf_generic/vnf/tg_prox.py +++ b/yardstick/network_services/vnf_generic/vnf/tg_prox.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from __future__ import print_function, absolute_import +from __future__ import absolute_import import logging @@ -63,9 +63,6 @@ class ProxTrafficGen(SampleVNFTrafficGen): self.vpci_if_name_ascending = self._sort_vpci(vnfd) self.resource_helper.vpci_if_name_ascending = self._sort_vpci(vnfd) - def listen_traffic(self, traffic_profile): - pass - def terminate(self): self._vnf_wrapper.terminate() super(ProxTrafficGen, self).terminate() diff --git a/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py b/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py index 47c5a35d9..a8b19cfba 100644 --- a/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py +++ b/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py @@ -204,13 +204,6 @@ class IxiaTrafficGen(SampleVNFTrafficGen): def scale(self, flavor=""): pass - def listen_traffic(self, traffic_profile): - pass - def terminate(self): self.resource_helper.stop_collect() super(IxiaTrafficGen, self).terminate() - - def wait_for_instantiate(self): - # not needed for IxNet - pass diff --git a/yardstick/network_services/vnf_generic/vnf/tg_trex.py b/yardstick/network_services/vnf_generic/vnf/tg_trex.py index 458f1b844..4250cb7a6 100644 --- a/yardstick/network_services/vnf_generic/vnf/tg_trex.py +++ b/yardstick/network_services/vnf_generic/vnf/tg_trex.py @@ -14,8 +14,6 @@ """ Trex acts as traffic generation and vnf definitions based on IETS Spec """ from __future__ import absolute_import -from __future__ import print_function - import logging import os @@ -48,27 +46,38 @@ class TrexResourceHelper(ClientResourceHelper): ASYNC_PORT = 4500 SYNC_PORT = 4501 + def __init__(self, setup_helper): + super(TrexResourceHelper, self).__init__(setup_helper) + self.port_map = {} + self.dpdk_to_trex_port_map = {} + def generate_cfg(self): port_names = self.vnfd_helper.port_pairs.all_ports vpci_list = [] port_list = [] + self.port_map = {} + self.dpdk_to_trex_port_map = {} - port_nums = sorted(self.vnfd_helper.port_nums(port_names)) - for port_num in port_nums: - interface = self.vnfd_helper.find_interface_by_port(port_num) + sorted_ports = sorted((self.vnfd_helper.port_num(port_name), port_name) for port_name in + port_names) + for index, (port_num, port_name) in enumerate(sorted_ports): + interface = self.vnfd_helper.find_interface(name=port_name) virtual_interface = interface['virtual-interface'] dst_mac = virtual_interface["dst_mac"] - # why skip?, ordering is based on DPDK port number so we can't skip + # this is to check for unused ports, all ports in the topology + # will always have dst_mac if not dst_mac: continue - # TRex ports must be in DPDK port number, so order of append matters + # TRex ports are in logical order roughly based on DPDK port number sorting vpci_list.append(virtual_interface["vpci"]) local_mac = virtual_interface["local_mac"] port_list.append({ "src_mac": mac_address_to_hex_list(local_mac), "dest_mac": mac_address_to_hex_list(dst_mac), }) + self.port_map[port_name] = index + self.dpdk_to_trex_port_map[port_num] = index trex_cfg = { 'interfaces': vpci_list, 'port_info': port_list, @@ -80,6 +89,17 @@ class TrexResourceHelper(ClientResourceHelper): cfg_str = yaml.safe_dump(cfg_file, default_flow_style=False, explicit_start=True) self.ssh_helper.upload_config_file(os.path.basename(self.CONF_FILE), cfg_str) + def _build_ports(self): + super(TrexResourceHelper, self)._build_ports() + # override with TRex logic port number + self.uplink_ports = [self.dpdk_to_trex_port_map[p] for p in self.uplink_ports] + self.downlink_ports = [self.dpdk_to_trex_port_map[p] for p in self.downlink_ports] + self.all_ports = [self.dpdk_to_trex_port_map[p] for p in self.all_ports] + + def port_num(self, intf): + # return logical TRex port + return self.port_map[intf] + def check_status(self): status, _, _ = self.ssh_helper.execute("sudo lsof -i:%s" % self.SYNC_PORT) return status @@ -169,8 +189,8 @@ class TrexTrafficGen(SampleVNFTrafficGen): def scale(self, flavor=""): pass - def listen_traffic(self, traffic_profile): - pass - def terminate(self): self.resource_helper.terminate() + + def wait_for_instantiate(self): + return self._wait_for_process() diff --git a/yardstick/orchestrator/heat.py b/yardstick/orchestrator/heat.py index 455ddc34e..d58ae5618 100644 --- a/yardstick/orchestrator/heat.py +++ b/yardstick/orchestrator/heat.py @@ -497,7 +497,7 @@ name (i.e. %s).\ 'type': 'OS::Neutron::SecurityGroup', 'properties': { 'name': name, - 'description': "Group allowing icmp and upd/tcp on all ports", + 'description': "Group allowing IPv4 and IPv6 for icmp and upd/tcp on all ports", 'rules': [ {'remote_ip_prefix': '0.0.0.0/0', 'protocol': 'tcp', @@ -508,7 +508,20 @@ name (i.e. %s).\ 'port_range_min': '1', 'port_range_max': '65535'}, {'remote_ip_prefix': '0.0.0.0/0', - 'protocol': 'icmp'} + 'protocol': 'icmp'}, + {'remote_ip_prefix': '::/0', + 'ethertype': 'IPv6', + 'protocol': 'tcp', + 'port_range_min': '1', + 'port_range_max': '65535'}, + {'remote_ip_prefix': '::/0', + 'ethertype': 'IPv6', + 'protocol': 'udp', + 'port_range_min': '1', + 'port_range_max': '65535'}, + {'remote_ip_prefix': '::/0', + 'ethertype': 'IPv6', + 'protocol': 'ipv6-icmp'} ] } } @@ -518,11 +531,10 @@ name (i.e. %s).\ 'value': {'get_resource': name} } - def add_server(self, name, image, flavor, flavors, ports=None, - networks=None, scheduler_hints=None, user=None, - key_name=None, user_data=None, metadata=None, - additional_properties=None): - """add to the template a Nova Server""" + def add_server(self, name, image, flavor, flavors, ports=None, networks=None, + scheduler_hints=None, user=None, key_name=None, user_data=None, metadata=None, + additional_properties=None, availability_zone=None): + """add to the template a Nova Server """ log.debug("adding Nova::Server '%s', image '%s', flavor '%s', " "ports %s", name, image, flavor, ports) @@ -537,6 +549,8 @@ name (i.e. %s).\ 'flavor': {}, 'networks': [] # list of dictionaries } + if availability_zone: + server_properties["availability_zone"] = availability_zone if flavor in flavors: self.resources[name]['depends_on'].append(flavor) |