aboutsummaryrefslogtreecommitdiffstats
path: root/yardstick
diff options
context:
space:
mode:
Diffstat (limited to 'yardstick')
-rw-r--r--yardstick/benchmark/contexts/heat.py59
-rw-r--r--yardstick/network_services/helpers/cpu.py103
-rw-r--r--yardstick/network_services/helpers/dpdkbindnic_helper.py18
-rw-r--r--yardstick/network_services/helpers/vpp_helpers/__init__.py0
-rw-r--r--yardstick/network_services/helpers/vpp_helpers/abstract_search_algorithm.py53
-rw-r--r--yardstick/network_services/helpers/vpp_helpers/multiple_loss_ratio_search.py688
-rw-r--r--yardstick/network_services/helpers/vpp_helpers/ndr_pdr_result.py68
-rw-r--r--yardstick/network_services/helpers/vpp_helpers/receive_rate_interval.py88
-rw-r--r--yardstick/network_services/helpers/vpp_helpers/receive_rate_measurement.py58
-rw-r--r--yardstick/network_services/traffic_profile/__init__.py1
-rw-r--r--yardstick/network_services/traffic_profile/sip.py32
-rw-r--r--yardstick/network_services/traffic_profile/vpp_rfc2544.py34
-rw-r--r--yardstick/network_services/vnf_generic/vnf/base.py2
-rw-r--r--yardstick/network_services/vnf_generic/vnf/ipsec_vnf.py498
-rw-r--r--yardstick/network_services/vnf_generic/vnf/tg_imsbench_sipp.py143
-rw-r--r--yardstick/network_services/vnf_generic/vnf/tg_trex_vpp.py178
-rwxr-xr-xyardstick/network_services/vnf_generic/vnf/tg_vcmts_pktgen.py215
-rw-r--r--yardstick/network_services/vnf_generic/vnf/udp_replay.py4
-rwxr-xr-xyardstick/network_services/vnf_generic/vnf/vcmts_vnf.py273
-rw-r--r--yardstick/network_services/vnf_generic/vnf/vims_vnf.py105
-rw-r--r--yardstick/network_services/vnf_generic/vnf/vpp_helpers.py751
-rw-r--r--yardstick/resources/templates/add_ip_address.vat1
-rw-r--r--yardstick/resources/templates/add_ip_neighbor.vat1
-rw-r--r--yardstick/resources/templates/add_route.vat1
-rw-r--r--yardstick/resources/templates/del_route.vat1
-rw-r--r--yardstick/resources/templates/flush_ip_addresses.vat1
-rw-r--r--yardstick/resources/templates/hw_interface_set_mtu.vat1
-rw-r--r--yardstick/resources/templates/interface_dump.vat1
-rw-r--r--yardstick/resources/templates/set_if_state.vat1
-rw-r--r--yardstick/tests/unit/benchmark/contexts/test_heat.py37
-rw-r--r--yardstick/tests/unit/network_services/helpers/test_cpu.py94
-rw-r--r--yardstick/tests/unit/network_services/helpers/vpp_helpers/__init__.py0
-rw-r--r--yardstick/tests/unit/network_services/helpers/vpp_helpers/test_multiple_loss_ratio_search.py2164
-rw-r--r--yardstick/tests/unit/network_services/helpers/vpp_helpers/test_ndr_pdr_result.py91
-rw-r--r--yardstick/tests/unit/network_services/helpers/vpp_helpers/test_receive_rate_interval.py100
-rw-r--r--yardstick/tests/unit/network_services/helpers/vpp_helpers/test_receive_rate_measurement.py44
-rw-r--r--yardstick/tests/unit/network_services/traffic_profile/test_sip.py51
-rw-r--r--yardstick/tests/unit/network_services/traffic_profile/test_vpp_rfc2544.py77
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_ipsec_vnf.py2151
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_imsbench_sipp.py481
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_trex_vpp.py1130
-rwxr-xr-xyardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_vcmts_pktgen.py652
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_udp_replay.py6
-rwxr-xr-xyardstick/tests/unit/network_services/vnf_generic/vnf/test_vcmts_vnf.py651
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_vims_vnf.py713
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_vpp_helpers.py1723
46 files changed, 13499 insertions, 45 deletions
diff --git a/yardstick/benchmark/contexts/heat.py b/yardstick/benchmark/contexts/heat.py
index fda917015..917aa9c39 100644
--- a/yardstick/benchmark/contexts/heat.py
+++ b/yardstick/benchmark/contexts/heat.py
@@ -71,6 +71,7 @@ class HeatContext(Context):
self.shade_client = None
self.heat_timeout = None
self.key_filename = None
+ self.yardstick_gen_key_file = True
self.shade_client = None
self.operator_client = None
self.nodes = []
@@ -105,6 +106,14 @@ class HeatContext(Context):
self.template_file = attrs.get("heat_template")
+ # try looking for external private key when using external heat template
+ if self.template_file is not None:
+ self.key_filename = attrs.get("key_filename", None)
+ if self.key_filename is not None:
+ # Disable key file generation if an external private key
+ # has been provided
+ self.yardstick_gen_key_file = False
+
self.shade_client = openstack_utils.get_shade_client()
self.operator_client = openstack_utils.get_shade_operator_client()
@@ -335,14 +344,16 @@ class HeatContext(Context):
"""deploys template into a stack using cloud"""
LOG.info("Deploying context '%s' START", self.name)
- self.key_filename = ''.join(
- [consts.YARDSTICK_ROOT_PATH,
- 'yardstick/resources/files/yardstick_key-',
- self.name])
+ # Check if there was no external private key provided
+ if self.key_filename is None:
+ self.key_filename = ''.join(
+ [consts.YARDSTICK_ROOT_PATH,
+ 'yardstick/resources/files/yardstick_key-',
+ self.name])
# Permissions may have changed since creation; this can be fixed. If we
# overwrite the file, we lose future access to VMs using this key.
# As long as the file exists, even if it is unreadable, keep it intact
- if not os.path.exists(self.key_filename):
+ if self.yardstick_gen_key_file and not os.path.exists(self.key_filename):
SSH.gen_keys(self.key_filename)
heat_template = HeatTemplate(
@@ -442,12 +453,14 @@ class HeatContext(Context):
}
def _delete_key_file(self):
- try:
- utils.remove_file(self.key_filename)
- utils.remove_file(self.key_filename + ".pub")
- except OSError:
- LOG.exception("There was an error removing the key file %s",
- self.key_filename)
+ # Only remove the key file if it has been generated by yardstick
+ if self.yardstick_gen_key_file:
+ try:
+ utils.remove_file(self.key_filename)
+ utils.remove_file(self.key_filename + ".pub")
+ except OSError:
+ LOG.exception("There was an error removing the key file %s",
+ self.key_filename)
def undeploy(self):
"""undeploys stack from cloud"""
@@ -513,11 +526,25 @@ class HeatContext(Context):
if server is None:
return None
- pkey = pkg_resources.resource_string(
- 'yardstick.resources',
- h_join('files/yardstick_key', self.name)).decode('utf-8')
- key_filename = pkg_resources.resource_filename('yardstick.resources',
- h_join('files/yardstick_key', self.name))
+ # Get the pkey
+ if self.yardstick_gen_key_file:
+ pkey = pkg_resources.resource_string(
+ 'yardstick.resources',
+ h_join('files/yardstick_key', self.name)).decode('utf-8')
+ key_filename = pkg_resources.resource_filename('yardstick.resources',
+ h_join('files/yardstick_key', self.name))
+ else:
+ # make sure the file exists before attempting to open it
+ if not os.path.exists(self.key_filename):
+ LOG.error("The key_filename provided %s does not exist!",
+ self.key_filename)
+ else:
+ try:
+ pkey = open(self.key_filename, 'r').read().decode('utf-8')
+ key_filename = self.key_filename
+ except IOError:
+ LOG.error("The key_filename provided (%s) is unreadable.",
+ self.key_filename)
result = {
"user": server.context.user,
"pkey": pkey,
diff --git a/yardstick/network_services/helpers/cpu.py b/yardstick/network_services/helpers/cpu.py
index 8c21754ff..279af204a 100644
--- a/yardstick/network_services/helpers/cpu.py
+++ b/yardstick/network_services/helpers/cpu.py
@@ -15,11 +15,15 @@
import io
+# Number of threads per core.
+NR_OF_THREADS = 2
+
class CpuSysCores(object):
def __init__(self, connection=""):
self.core_map = {}
+ self.cpuinfo = {}
self.connection = connection
def _open_cpuinfo(self):
@@ -33,11 +37,11 @@ class CpuSysCores(object):
core_lines = {}
for line in lines:
if line.strip():
- name, value = line.split(":", 1)
- core_lines[name.strip()] = value.strip()
+ name, value = line.split(":", 1)
+ core_lines[name.strip()] = value.strip()
else:
- core_details.append(core_lines)
- core_lines = {}
+ core_details.append(core_lines)
+ core_lines = {}
return core_details
@@ -51,7 +55,7 @@ class CpuSysCores(object):
lines = self._open_cpuinfo()
core_details = self._get_core_details(lines)
for core in core_details:
- for k, v in core.items():
+ for k, _ in core.items():
if k == "physical id":
if core["physical id"] not in self.core_map:
self.core_map[core['physical id']] = []
@@ -60,6 +64,17 @@ class CpuSysCores(object):
return self.core_map
+ def get_cpu_layout(self):
+ _, stdout, _ = self.connection.execute("lscpu -p")
+ self.cpuinfo = {}
+ self.cpuinfo['cpuinfo'] = list()
+ for line in stdout.split("\n"):
+ if line and line[0] != "#":
+ self.cpuinfo['cpuinfo'].append(
+ [CpuSysCores._str2int(x) for x in
+ line.split(",")])
+ return self.cpuinfo
+
def validate_cpu_cfg(self, vnf_cfg=None):
if vnf_cfg is None:
vnf_cfg = {
@@ -78,3 +93,81 @@ class CpuSysCores(object):
return -1
return 0
+
+ def is_smt_enabled(self):
+ return CpuSysCores.smt_enabled(self.cpuinfo)
+
+ def cpu_list_per_node(self, cpu_node, smt_used=False):
+ cpu_node = int(cpu_node)
+ cpu_info = self.cpuinfo.get("cpuinfo")
+ if cpu_info is None:
+ raise RuntimeError("Node cpuinfo not available.")
+
+ smt_enabled = self.is_smt_enabled()
+ if not smt_enabled and smt_used:
+ raise RuntimeError("SMT is not enabled.")
+
+ cpu_list = []
+ for cpu in cpu_info:
+ if cpu[3] == cpu_node:
+ cpu_list.append(cpu[0])
+
+ if not smt_enabled or smt_enabled and smt_used:
+ pass
+
+ if smt_enabled and not smt_used:
+ cpu_list_len = len(cpu_list)
+ cpu_list = cpu_list[:int(cpu_list_len / NR_OF_THREADS)]
+
+ return cpu_list
+
+ def cpu_slice_of_list_per_node(self, cpu_node, skip_cnt=0, cpu_cnt=0,
+ smt_used=False):
+ cpu_list = self.cpu_list_per_node(cpu_node, smt_used)
+
+ cpu_list_len = len(cpu_list)
+ if cpu_cnt + skip_cnt > cpu_list_len:
+ raise RuntimeError("cpu_cnt + skip_cnt > length(cpu list).")
+
+ if cpu_cnt == 0:
+ cpu_cnt = cpu_list_len - skip_cnt
+
+ if smt_used:
+ cpu_list_0 = cpu_list[:int(cpu_list_len / NR_OF_THREADS)]
+ cpu_list_1 = cpu_list[int(cpu_list_len / NR_OF_THREADS):]
+ cpu_list = [cpu for cpu in cpu_list_0[skip_cnt:skip_cnt + cpu_cnt]]
+ cpu_list_ex = [cpu for cpu in
+ cpu_list_1[skip_cnt:skip_cnt + cpu_cnt]]
+ cpu_list.extend(cpu_list_ex)
+ else:
+ cpu_list = [cpu for cpu in cpu_list[skip_cnt:skip_cnt + cpu_cnt]]
+
+ return cpu_list
+
+ def cpu_list_per_node_str(self, cpu_node, skip_cnt=0, cpu_cnt=0, sep=",",
+ smt_used=False):
+ cpu_list = self.cpu_slice_of_list_per_node(cpu_node,
+ skip_cnt=skip_cnt,
+ cpu_cnt=cpu_cnt,
+ smt_used=smt_used)
+ return sep.join(str(cpu) for cpu in cpu_list)
+
+ @staticmethod
+ def _str2int(string):
+ try:
+ return int(string)
+ except ValueError:
+ return 0
+
+ @staticmethod
+ def smt_enabled(cpuinfo):
+ cpu_info = cpuinfo.get("cpuinfo")
+ if cpu_info is None:
+ raise RuntimeError("Node cpuinfo not available.")
+ cpu_mems = [item[-4:] for item in cpu_info]
+ cpu_mems_len = int(len(cpu_mems) / NR_OF_THREADS)
+ count = 0
+ for cpu_mem in cpu_mems[:cpu_mems_len]:
+ if cpu_mem in cpu_mems[cpu_mems_len:]:
+ count += 1
+ return count == cpu_mems_len
diff --git a/yardstick/network_services/helpers/dpdkbindnic_helper.py b/yardstick/network_services/helpers/dpdkbindnic_helper.py
index 0fc63f88d..33a5e8c1d 100644
--- a/yardstick/network_services/helpers/dpdkbindnic_helper.py
+++ b/yardstick/network_services/helpers/dpdkbindnic_helper.py
@@ -13,7 +13,6 @@
# limitations under the License.
import logging
import os
-
import re
from collections import defaultdict
from itertools import chain
@@ -21,7 +20,6 @@ from itertools import chain
from yardstick.common import exceptions
from yardstick.common.utils import validate_non_string_sequence
-
NETWORK_KERNEL = 'network_kernel'
NETWORK_DPDK = 'network_dpdk'
NETWORK_OTHER = 'network_other'
@@ -288,12 +286,18 @@ printf "%s/driver:" $1 ; basename $(readlink -s $1/device/driver); } \
raise DpdkBindHelperException(template.format(self.dpdk_devbind, res[0]))
return res
- def load_dpdk_driver(self):
+ def load_dpdk_driver(self, dpdk_driver=None):
+ if dpdk_driver is None:
+ dpdk_driver = self.dpdk_driver
cmd_template = "sudo modprobe {} && sudo modprobe {}"
- self.ssh_helper.execute(cmd_template.format(self.UIO_DRIVER, self.dpdk_driver))
-
- def check_dpdk_driver(self):
- return self.ssh_helper.execute("lsmod | grep -i {}".format(self.dpdk_driver))[0]
+ self.ssh_helper.execute(
+ cmd_template.format(self.UIO_DRIVER, dpdk_driver))
+
+ def check_dpdk_driver(self, dpdk_driver=None):
+ if dpdk_driver is None:
+ dpdk_driver = self.dpdk_driver
+ return \
+ self.ssh_helper.execute("lsmod | grep -i {}".format(dpdk_driver))[0]
@property
def _status_cmd(self):
diff --git a/yardstick/network_services/helpers/vpp_helpers/__init__.py b/yardstick/network_services/helpers/vpp_helpers/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/yardstick/network_services/helpers/vpp_helpers/__init__.py
diff --git a/yardstick/network_services/helpers/vpp_helpers/abstract_search_algorithm.py b/yardstick/network_services/helpers/vpp_helpers/abstract_search_algorithm.py
new file mode 100644
index 000000000..fced05833
--- /dev/null
+++ b/yardstick/network_services/helpers/vpp_helpers/abstract_search_algorithm.py
@@ -0,0 +1,53 @@
+# Copyright (c) 2019 Viosoft 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.
+#
+# This is a modified copy of
+# https://gerrit.fd.io/r/gitweb?p=csit.git;a=blob_plain;f=resources/libraries/python/MLRsearch/AbstractSearchAlgorithm.py;hb=HEAD
+
+
+from abc import ABCMeta, abstractmethod
+
+
+class AbstractSearchAlgorithm(object):
+ """Abstract class defining common API for search algorithms."""
+
+ __metaclass__ = ABCMeta
+
+ def __init__(self, measurer):
+ """Store the rate provider.
+
+ :param measurer: Object able to perform trial or composite measurements.
+ :type measurer: AbstractMeasurer.AbstractMeasurer
+ """
+ # TODO: Type check for AbstractMeasurer?
+ self.measurer = measurer
+
+ @abstractmethod
+ def narrow_down_ndr_and_pdr(
+ self, fail_rate, line_rate, packet_loss_ratio):
+ """Perform measurements to narrow down intervals, return them.
+
+ This will be renamed when custom loss ratio lists are supported.
+
+ :param fail_rate: Minimal target transmit rate [pps].
+ :param line_rate: Maximal target transmit rate [pps].
+ :param packet_loss_ratio: Fraction of packets lost, for PDR [1].
+ :type fail_rate: float
+ :type line_rate: float
+ :type packet_loss_ratio: float
+ :returns: Structure containing narrowed down intervals
+ and their measurements.
+ :rtype: NdrPdrResult.NdrPdrResult
+ """
+ # TODO: Do we agree on arguments related to precision or trial duration?
diff --git a/yardstick/network_services/helpers/vpp_helpers/multiple_loss_ratio_search.py b/yardstick/network_services/helpers/vpp_helpers/multiple_loss_ratio_search.py
new file mode 100644
index 000000000..582e3dc27
--- /dev/null
+++ b/yardstick/network_services/helpers/vpp_helpers/multiple_loss_ratio_search.py
@@ -0,0 +1,688 @@
+# Copyright (c) 2019 Viosoft 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.
+#
+# This is a modified copy of
+# https://gerrit.fd.io/r/gitweb?p=csit.git;a=blob_plain;f=resources/libraries/python/MLRsearch/MultipleLossRatioSearch.py;hb=HEAD
+
+import datetime
+import logging
+import math
+import time
+
+from yardstick.network_services.helpers.vpp_helpers.abstract_search_algorithm import \
+ AbstractSearchAlgorithm
+from yardstick.network_services.helpers.vpp_helpers.ndr_pdr_result import \
+ NdrPdrResult
+from yardstick.network_services.helpers.vpp_helpers.receive_rate_interval import \
+ ReceiveRateInterval
+from yardstick.network_services.helpers.vpp_helpers.receive_rate_measurement import \
+ ReceiveRateMeasurement
+
+LOGGING = logging.getLogger(__name__)
+
+
+class MultipleLossRatioSearch(AbstractSearchAlgorithm):
+ """Optimized binary search algorithm for finding NDR and PDR bounds.
+
+ Traditional binary search algorithm needs initial interval
+ (lower and upper bound), and returns final interval after bisecting
+ (until some exit condition is met).
+ The exit condition is usually related to the interval width,
+ (upper bound value minus lower bound value).
+
+ The optimized algorithm contains several improvements
+ aimed to reduce overall search time.
+
+ One improvement is searching for two intervals at once.
+ The intervals are for NDR (No Drop Rate) and PDR (Partial Drop Rate).
+
+ Next improvement is that the initial interval does not need to be valid.
+ Imagine initial interval (10, 11) where 11 is smaller
+ than the searched value.
+ The algorithm will try (11, 13) interval next, and if 13 is still smaller,
+ (13, 17) and so on, doubling width until the upper bound is valid.
+ The part when interval expands is called external search,
+ the part when interval is bisected is called internal search.
+
+ Next improvement is that trial measurements at small trial duration
+ can be used to find a reasonable interval for full trial duration search.
+ This results in more trials performed, but smaller overall duration
+ in general.
+
+ Next improvement is bisecting in logarithmic quantities,
+ so that exit criteria can be independent of measurement units.
+
+ Next improvement is basing the initial interval on receive rates.
+
+ Final improvement is exiting early if the minimal value
+ is not a valid lower bound.
+
+ The complete search consist of several phases,
+ each phase performing several trial measurements.
+ Initial phase creates initial interval based on receive rates
+ at maximum rate and at maximum receive rate (MRR).
+ Final phase and preceding intermediate phases are performing
+ external and internal search steps,
+ each resulting interval is the starting point for the next phase.
+ The resulting interval of final phase is the result of the whole algorithm.
+
+ Each non-initial phase uses its own trial duration and width goal.
+ Any non-initial phase stops searching (for NDR or PDR independently)
+ when minimum is not a valid lower bound (at current duration),
+ or all of the following is true:
+ Both bounds are valid, bound bounds are measured at the current phase
+ trial duration, interval width is less than the width goal
+ for current phase.
+
+ TODO: Review and update this docstring according to rst docs.
+ TODO: Support configurable number of Packet Loss Ratios.
+ """
+
+ class ProgressState(object):
+ """Structure containing data to be passed around in recursion."""
+
+ def __init__(
+ self, result, phases, duration, width_goal, packet_loss_ratio,
+ minimum_transmit_rate, maximum_transmit_rate):
+ """Convert and store the argument values.
+
+ :param result: Current measured NDR and PDR intervals.
+ :param phases: How many intermediate phases to perform
+ before the current one.
+ :param duration: Trial duration to use in the current phase [s].
+ :param width_goal: The goal relative width for the curreent phase.
+ :param packet_loss_ratio: PDR fraction for the current search.
+ :param minimum_transmit_rate: Minimum target transmit rate
+ for the current search [pps].
+ :param maximum_transmit_rate: Maximum target transmit rate
+ for the current search [pps].
+ :type result: NdrPdrResult.NdrPdrResult
+ :type phases: int
+ :type duration: float
+ :type width_goal: float
+ :type packet_loss_ratio: float
+ :type minimum_transmit_rate: float
+ :type maximum_transmit_rate: float
+ """
+ self.result = result
+ self.phases = int(phases)
+ self.duration = float(duration)
+ self.width_goal = float(width_goal)
+ self.packet_loss_ratio = float(packet_loss_ratio)
+ self.minimum_transmit_rate = float(minimum_transmit_rate)
+ self.maximum_transmit_rate = float(maximum_transmit_rate)
+
+ def __init__(self, measurer, latency=False, pkt_size=64,
+ final_relative_width=0.005,
+ final_trial_duration=30.0, initial_trial_duration=1.0,
+ number_of_intermediate_phases=2, timeout=600.0, doublings=1):
+ """Store the measurer object and additional arguments.
+
+ :param measurer: Rate provider to use by this search object.
+ :param final_relative_width: Final lower bound transmit rate
+ cannot be more distant that this multiple of upper bound [1].
+ :param final_trial_duration: Trial duration for the final phase [s].
+ :param initial_trial_duration: Trial duration for the initial phase
+ and also for the first intermediate phase [s].
+ :param number_of_intermediate_phases: Number of intermediate phases
+ to perform before the final phase [1].
+ :param timeout: The search will fail itself when not finished
+ before this overall time [s].
+ :param doublings: How many doublings to do in external search step.
+ Default 1 is suitable for fairly stable tests,
+ less stable tests might get better overal duration with 2 or more.
+ :type measurer: AbstractMeasurer.AbstractMeasurer
+ :type final_relative_width: float
+ :type final_trial_duration: float
+ :type initial_trial_duration: int
+ :type number_of_intermediate_phases: int
+ :type timeout: float
+ :type doublings: int
+ """
+ super(MultipleLossRatioSearch, self).__init__(measurer)
+ self.latency = latency
+ self.pkt_size = int(pkt_size)
+ self.final_trial_duration = float(final_trial_duration)
+ self.final_relative_width = float(final_relative_width)
+ self.number_of_intermediate_phases = int(number_of_intermediate_phases)
+ self.initial_trial_duration = float(initial_trial_duration)
+ self.timeout = float(timeout)
+ self.doublings = int(doublings)
+
+ self.queue = None
+ self.port_pg_id = None
+ self.ports = []
+ self.test_data = {}
+ self.profiles = {}
+
+ @staticmethod
+ def double_relative_width(relative_width):
+ """Return relative width corresponding to double logarithmic width.
+
+ :param relative_width: The base relative width to double.
+ :type relative_width: float
+ :returns: The relative width of double logarithmic size.
+ :rtype: float
+ """
+ return 1.999 * relative_width - relative_width * relative_width
+ # The number should be 2.0, but we want to avoid rounding errors,
+ # and ensure half of double is not larger than the original value.
+
+ @staticmethod
+ def double_step_down(relative_width, current_bound):
+ """Return rate of double logarithmic width below.
+
+ :param relative_width: The base relative width to double.
+ :param current_bound: The current target transmit rate to move [pps].
+ :type relative_width: float
+ :type current_bound: float
+ :returns: Transmit rate smaller by logarithmically double width [pps].
+ :rtype: float
+ """
+ return current_bound * (
+ 1.0 - MultipleLossRatioSearch.double_relative_width(
+ relative_width))
+
+ @staticmethod
+ def expand_down(relative_width, doublings, current_bound):
+ """Return rate of expanded logarithmic width below.
+
+ :param relative_width: The base relative width to double.
+ :param doublings: How many doublings to do for expansion.
+ :param current_bound: The current target transmit rate to move [pps].
+ :type relative_width: float
+ :type doublings: int
+ :type current_bound: float
+ :returns: Transmit rate smaller by logarithmically double width [pps].
+ :rtype: float
+ """
+ for _ in range(doublings):
+ relative_width = MultipleLossRatioSearch.double_relative_width(
+ relative_width)
+ return current_bound * (1.0 - relative_width)
+
+ @staticmethod
+ def double_step_up(relative_width, current_bound):
+ """Return rate of double logarithmic width above.
+
+ :param relative_width: The base relative width to double.
+ :param current_bound: The current target transmit rate to move [pps].
+ :type relative_width: float
+ :type current_bound: float
+ :returns: Transmit rate larger by logarithmically double width [pps].
+ :rtype: float
+ """
+ return current_bound / (
+ 1.0 - MultipleLossRatioSearch.double_relative_width(
+ relative_width))
+
+ @staticmethod
+ def expand_up(relative_width, doublings, current_bound):
+ """Return rate of expanded logarithmic width above.
+
+ :param relative_width: The base relative width to double.
+ :param doublings: How many doublings to do for expansion.
+ :param current_bound: The current target transmit rate to move [pps].
+ :type relative_width: float
+ :type doublings: int
+ :type current_bound: float
+ :returns: Transmit rate smaller by logarithmically double width [pps].
+ :rtype: float
+ """
+ for _ in range(doublings):
+ relative_width = MultipleLossRatioSearch.double_relative_width(
+ relative_width)
+ return current_bound / (1.0 - relative_width)
+
+ @staticmethod
+ def half_relative_width(relative_width):
+ """Return relative width corresponding to half logarithmic width.
+
+ :param relative_width: The base relative width to halve.
+ :type relative_width: float
+ :returns: The relative width of half logarithmic size.
+ :rtype: float
+ """
+ return 1.0 - math.sqrt(1.0 - relative_width)
+
+ @staticmethod
+ def half_step_up(relative_width, current_bound):
+ """Return rate of half logarithmic width above.
+
+ :param relative_width: The base relative width to halve.
+ :param current_bound: The current target transmit rate to move [pps].
+ :type relative_width: float
+ :type current_bound: float
+ :returns: Transmit rate larger by logarithmically half width [pps].
+ :rtype: float
+ """
+ return current_bound / (
+ 1.0 - MultipleLossRatioSearch.half_relative_width(
+ relative_width))
+
+ def init_generator(self, ports, port_pg_id, profiles, test_data, queue):
+ self.ports = ports
+ self.port_pg_id = port_pg_id
+ self.profiles = profiles
+ self.test_data = test_data
+ self.queue = queue
+ self.queue.cancel_join_thread()
+
+ def collect_kpi(self, stats, test_value):
+ samples = self.measurer.generate_samples(stats, self.ports,
+ self.port_pg_id, self.latency)
+ samples.update(self.test_data)
+ LOGGING.info("Collect TG KPIs %s %s %s", datetime.datetime.now(),
+ test_value, samples)
+ self.queue.put(samples)
+
+ def narrow_down_ndr_and_pdr(
+ self, minimum_transmit_rate, maximum_transmit_rate,
+ packet_loss_ratio):
+ """Perform initial phase, create state object, proceed with next phases.
+
+ :param minimum_transmit_rate: Minimal target transmit rate [pps].
+ :param maximum_transmit_rate: Maximal target transmit rate [pps].
+ :param packet_loss_ratio: Fraction of packets lost, for PDR [1].
+ :type minimum_transmit_rate: float
+ :type maximum_transmit_rate: float
+ :type packet_loss_ratio: float
+ :returns: Structure containing narrowed down intervals
+ and their measurements.
+ :rtype: NdrPdrResult.NdrPdrResult
+ :raises RuntimeError: If total duration is larger than timeout.
+ """
+ minimum_transmit_rate = float(minimum_transmit_rate)
+ maximum_transmit_rate = float(maximum_transmit_rate)
+ packet_loss_ratio = float(packet_loss_ratio)
+ line_measurement = self.measure(
+ self.initial_trial_duration, maximum_transmit_rate, self.latency)
+ initial_width_goal = self.final_relative_width
+ for _ in range(self.number_of_intermediate_phases):
+ initial_width_goal = self.double_relative_width(initial_width_goal)
+ max_lo = maximum_transmit_rate * (1.0 - initial_width_goal)
+ mrr = max(
+ minimum_transmit_rate,
+ min(max_lo, line_measurement.receive_rate))
+ mrr_measurement = self.measure(
+ self.initial_trial_duration, mrr, self.latency)
+ # Attempt to get narrower width.
+ if mrr_measurement.loss_fraction > 0.0:
+ max2_lo = mrr * (1.0 - initial_width_goal)
+ mrr2 = min(max2_lo, mrr_measurement.receive_rate)
+ else:
+ mrr2 = mrr / (1.0 - initial_width_goal)
+ if mrr2 > minimum_transmit_rate and mrr2 < maximum_transmit_rate:
+ line_measurement = mrr_measurement
+ mrr_measurement = self.measure(
+ self.initial_trial_duration, mrr2, self.latency)
+ if mrr2 > mrr:
+ buf = line_measurement
+ line_measurement = mrr_measurement
+ mrr_measurement = buf
+ starting_interval = ReceiveRateInterval(
+ mrr_measurement, line_measurement)
+ starting_result = NdrPdrResult(starting_interval, starting_interval)
+ state = self.ProgressState(
+ starting_result, self.number_of_intermediate_phases,
+ self.final_trial_duration, self.final_relative_width,
+ packet_loss_ratio, minimum_transmit_rate, maximum_transmit_rate)
+ state = self.ndrpdr(state)
+ result = state.result
+ # theor_max_thruput = 0
+ result_samples = {}
+
+ MultipleLossRatioSearch.display_single_bound(result_samples,
+ 'NDR_LOWER', result.ndr_interval.measured_low.transmit_rate,
+ self.pkt_size, result.ndr_interval.measured_low.latency)
+ MultipleLossRatioSearch.display_single_bound(result_samples,
+ 'NDR_UPPER', result.ndr_interval.measured_high.transmit_rate,
+ self.pkt_size)
+ MultipleLossRatioSearch.display_single_bound(result_samples,
+ 'PDR_LOWER', result.pdr_interval.measured_low.transmit_rate,
+ self.pkt_size, result.pdr_interval.measured_low.latency)
+ MultipleLossRatioSearch.display_single_bound(result_samples,
+ 'PDR_UPPER', result.pdr_interval.measured_high.transmit_rate,
+ self.pkt_size)
+ pdr_msg = self.check_ndrpdr_interval_validity(result_samples, "PDR",
+ result.pdr_interval,
+ packet_loss_ratio)
+ ndr_msg = self.check_ndrpdr_interval_validity(result_samples, "NDR",
+ result.ndr_interval)
+ self.queue.put(result_samples)
+
+ LOGGING.debug("result_samples: %s", result_samples)
+ LOGGING.info(pdr_msg)
+ LOGGING.info(ndr_msg)
+
+ self.perform_additional_measurements_based_on_ndrpdr_result(result)
+
+ return result_samples
+
+ def _measure_and_update_state(self, state, transmit_rate):
+ """Perform trial measurement, update bounds, return new state.
+
+ :param state: State before this measurement.
+ :param transmit_rate: Target transmit rate for this measurement [pps].
+ :type state: ProgressState
+ :type transmit_rate: float
+ :returns: State after the measurement.
+ :rtype: ProgressState
+ """
+ # TODO: Implement https://stackoverflow.com/a/24683360
+ # to avoid the string manipulation if log verbosity is too low.
+ LOGGING.info("result before update: %s", state.result)
+ LOGGING.debug(
+ "relative widths in goals: %s", state.result.width_in_goals(
+ self.final_relative_width))
+ measurement = self.measure(state.duration, transmit_rate, self.latency)
+ ndr_interval = self._new_interval(
+ state.result.ndr_interval, measurement, 0.0)
+ pdr_interval = self._new_interval(
+ state.result.pdr_interval, measurement, state.packet_loss_ratio)
+ state.result = NdrPdrResult(ndr_interval, pdr_interval)
+ return state
+
+ @staticmethod
+ def _new_interval(old_interval, measurement, packet_loss_ratio):
+ """Return new interval with bounds updated according to the measurement.
+
+ :param old_interval: The current interval before the measurement.
+ :param measurement: The new meaqsurement to take into account.
+ :param packet_loss_ratio: Fraction for PDR (or zero for NDR).
+ :type old_interval: ReceiveRateInterval.ReceiveRateInterval
+ :type measurement: ReceiveRateMeasurement.ReceiveRateMeasurement
+ :type packet_loss_ratio: float
+ :returns: The updated interval.
+ :rtype: ReceiveRateInterval.ReceiveRateInterval
+ """
+ old_lo, old_hi = old_interval.measured_low, old_interval.measured_high
+ # Priority zero: direct replace if the target Tr is the same.
+ if measurement.target_tr in (old_lo.target_tr, old_hi.target_tr):
+ if measurement.target_tr == old_lo.target_tr:
+ return ReceiveRateInterval(measurement, old_hi)
+ else:
+ return ReceiveRateInterval(old_lo, measurement)
+ # Priority one: invalid lower bound allows only one type of update.
+ if old_lo.loss_fraction > packet_loss_ratio:
+ # We can only expand down, old bound becomes valid upper one.
+ if measurement.target_tr < old_lo.target_tr:
+ return ReceiveRateInterval(measurement, old_lo)
+ else:
+ return old_interval
+ # Lower bound is now valid.
+ # Next priorities depend on target Tr.
+ if measurement.target_tr < old_lo.target_tr:
+ # Lower external measurement, relevant only
+ # if the new measurement has high loss rate.
+ if measurement.loss_fraction > packet_loss_ratio:
+ # Returning the broader interval as old_lo
+ # would be invalid upper bound.
+ return ReceiveRateInterval(measurement, old_hi)
+ elif measurement.target_tr > old_hi.target_tr:
+ # Upper external measurement, only relevant for invalid upper bound.
+ if old_hi.loss_fraction <= packet_loss_ratio:
+ # Old upper bound becomes valid new lower bound.
+ return ReceiveRateInterval(old_hi, measurement)
+ else:
+ # Internal measurement, replaced boundary
+ # depends on measured loss fraction.
+ if measurement.loss_fraction > packet_loss_ratio:
+ # We have found a narrow valid interval,
+ # regardless of whether old upper bound was valid.
+ return ReceiveRateInterval(old_lo, measurement)
+ else:
+ # In ideal world, we would not want to shrink interval
+ # if upper bound is not valid.
+ # In the real world, we want to shrink it for
+ # "invalid upper bound at maximal rate" case.
+ return ReceiveRateInterval(measurement, old_hi)
+ # Fallback, the interval is unchanged by the measurement.
+ return old_interval
+
+ def ndrpdr(self, state):
+ """Pefrom trials for this phase. Return the new state when done.
+
+ :param state: State before this phase.
+ :type state: ProgressState
+ :returns: The updated state.
+ :rtype: ProgressState
+ :raises RuntimeError: If total duration is larger than timeout.
+ """
+ start_time = time.time()
+ if state.phases > 0:
+ # We need to finish preceding intermediate phases first.
+ saved_phases = state.phases
+ state.phases -= 1
+ # Preceding phases have shorter duration.
+ saved_duration = state.duration
+ duration_multiplier = state.duration / self.initial_trial_duration
+ phase_exponent = float(state.phases) / saved_phases
+ state.duration = self.initial_trial_duration * math.pow(
+ duration_multiplier, phase_exponent)
+ # Shorter durations do not need that narrow widths.
+ saved_width = state.width_goal
+ state.width_goal = self.double_relative_width(state.width_goal)
+ # Recurse.
+ state = self.ndrpdr(state)
+ # Restore the state for current phase.
+ state.duration = saved_duration
+ state.width_goal = saved_width
+ state.phases = saved_phases # Not needed, but just in case.
+ LOGGING.info(
+ "starting iterations with duration %s and relative width goal %s",
+ state.duration, state.width_goal)
+ while 1:
+ if time.time() > start_time + self.timeout:
+ raise RuntimeError("Optimized search takes too long.")
+ # Order of priorities: invalid bounds (nl, pl, nh, ph),
+ # then narrowing relative Tr widths.
+ # Durations are not priorities yet,
+ # they will settle on their own hopefully.
+ ndr_lo = state.result.ndr_interval.measured_low
+ ndr_hi = state.result.ndr_interval.measured_high
+ pdr_lo = state.result.pdr_interval.measured_low
+ pdr_hi = state.result.pdr_interval.measured_high
+ ndr_rel_width = max(
+ state.width_goal, state.result.ndr_interval.rel_tr_width)
+ pdr_rel_width = max(
+ state.width_goal, state.result.pdr_interval.rel_tr_width)
+ # If we are hitting maximal or minimal rate, we cannot shift,
+ # but we can re-measure.
+ if ndr_lo.loss_fraction > 0.0:
+ if ndr_lo.target_tr > state.minimum_transmit_rate:
+ new_tr = max(
+ state.minimum_transmit_rate,
+ self.expand_down(
+ ndr_rel_width, self.doublings, ndr_lo.target_tr))
+ LOGGING.info("ndr lo external %s", new_tr)
+ state = self._measure_and_update_state(state, new_tr)
+ continue
+ elif ndr_lo.duration < state.duration:
+ LOGGING.info("ndr lo minimal re-measure")
+ state = self._measure_and_update_state(
+ state, state.minimum_transmit_rate)
+ continue
+ if pdr_lo.loss_fraction > state.packet_loss_ratio:
+ if pdr_lo.target_tr > state.minimum_transmit_rate:
+ new_tr = max(
+ state.minimum_transmit_rate,
+ self.expand_down(
+ pdr_rel_width, self.doublings, pdr_lo.target_tr))
+ LOGGING.info("pdr lo external %s", new_tr)
+ state = self._measure_and_update_state(state, new_tr)
+ continue
+ elif pdr_lo.duration < state.duration:
+ LOGGING.info("pdr lo minimal re-measure")
+ state = self._measure_and_update_state(
+ state, state.minimum_transmit_rate)
+ continue
+ if ndr_hi.loss_fraction <= 0.0:
+ if ndr_hi.target_tr < state.maximum_transmit_rate:
+ new_tr = min(
+ state.maximum_transmit_rate,
+ self.expand_up(
+ ndr_rel_width, self.doublings, ndr_hi.target_tr))
+ LOGGING.info("ndr hi external %s", new_tr)
+ state = self._measure_and_update_state(state, new_tr)
+ continue
+ elif ndr_hi.duration < state.duration:
+ LOGGING.info("ndr hi maximal re-measure")
+ state = self._measure_and_update_state(
+ state, state.maximum_transmit_rate)
+ continue
+ if pdr_hi.loss_fraction <= state.packet_loss_ratio:
+ if pdr_hi.target_tr < state.maximum_transmit_rate:
+ new_tr = min(
+ state.maximum_transmit_rate,
+ self.expand_up(
+ pdr_rel_width, self.doublings, pdr_hi.target_tr))
+ LOGGING.info("pdr hi external %s", new_tr)
+ state = self._measure_and_update_state(state, new_tr)
+ continue
+ elif pdr_hi.duration < state.duration:
+ LOGGING.info("ndr hi maximal re-measure")
+ state = self._measure_and_update_state(
+ state, state.maximum_transmit_rate)
+ continue
+ # If we are hitting maximum_transmit_rate,
+ # it is still worth narrowing width,
+ # hoping large enough loss fraction will happen.
+ # But if we are hitting the minimal rate (at current duration),
+ # no additional measurement will help with that,
+ # so we can stop narrowing in this phase.
+ if (ndr_lo.target_tr <= state.minimum_transmit_rate
+ and ndr_lo.loss_fraction > 0.0):
+ ndr_rel_width = 0.0
+ if (pdr_lo.target_tr <= state.minimum_transmit_rate
+ and pdr_lo.loss_fraction > state.packet_loss_ratio):
+ pdr_rel_width = 0.0
+ if ndr_rel_width > state.width_goal:
+ # We have to narrow NDR width first, as NDR internal search
+ # can invalidate PDR (but not vice versa).
+ new_tr = self.half_step_up(ndr_rel_width, ndr_lo.target_tr)
+ LOGGING.info("Bisecting for NDR at %s", new_tr)
+ state = self._measure_and_update_state(state, new_tr)
+ continue
+ if pdr_rel_width > state.width_goal:
+ # PDR iternal search.
+ new_tr = self.half_step_up(pdr_rel_width, pdr_lo.target_tr)
+ LOGGING.info("Bisecting for PDR at %s", new_tr)
+ state = self._measure_and_update_state(state, new_tr)
+ continue
+ # We do not need to improve width, but there still might be
+ # some measurements with smaller duration.
+ # We need to re-measure with full duration, possibly
+ # creating invalid bounds to resolve (thus broadening width).
+ if ndr_lo.duration < state.duration:
+ LOGGING.info("re-measuring NDR lower bound")
+ state = self._measure_and_update_state(state, ndr_lo.target_tr)
+ continue
+ if pdr_lo.duration < state.duration:
+ LOGGING.info("re-measuring PDR lower bound")
+ state = self._measure_and_update_state(state, pdr_lo.target_tr)
+ continue
+ # Except when lower bounds have high loss fraction, in that case
+ # we do not need to re-measure _upper_ bounds.
+ if ndr_hi.duration < state.duration and ndr_rel_width > 0.0:
+ LOGGING.info("re-measuring NDR upper bound")
+ state = self._measure_and_update_state(state, ndr_hi.target_tr)
+ continue
+ if pdr_hi.duration < state.duration and pdr_rel_width > 0.0:
+ LOGGING.info("re-measuring PDR upper bound")
+ state = self._measure_and_update_state(state, pdr_hi.target_tr)
+ continue
+ # Widths are narrow (or lower bound minimal), bound measurements
+ # are long enough, we can return.
+ LOGGING.info("phase done")
+ break
+ return state
+
+ def measure(self, duration, transmit_rate, latency):
+ duration = float(duration)
+ transmit_rate = float(transmit_rate)
+ # Trex needs target Tr per stream, but reports aggregate Tx and Dx.
+ unit_rate = str(transmit_rate / 2.0) + "pps"
+ stats = self.measurer.send_traffic_on_tg(self.ports, self.port_pg_id,
+ duration, unit_rate,
+ latency=latency)
+ self.measurer.client.reset(ports=self.ports)
+ self.measurer.client.clear_stats(ports=self.ports)
+ self.measurer.client.remove_all_streams(ports=self.ports)
+ for port, profile in self.profiles.items():
+ self.measurer.client.add_streams(profile, ports=[port])
+ self.collect_kpi(stats, unit_rate)
+ transmit_count = int(self.measurer.sent)
+ loss_count = int(self.measurer.loss)
+ measurement = ReceiveRateMeasurement(
+ duration, transmit_rate, transmit_count, loss_count)
+ measurement.latency = self.measurer.latency
+ return measurement
+
+ def perform_additional_measurements_based_on_ndrpdr_result(self, result):
+ duration = 5.0
+ rate = "{}{}".format(result.ndr_interval.measured_low.target_tr / 2.0,
+ 'pps')
+ for _ in range(0, 1):
+ stats = self.measurer.send_traffic_on_tg(self.ports,
+ self.port_pg_id, duration,
+ rate)
+ self.collect_kpi(stats, rate)
+ LOGGING.info('Traffic loss occurred: %s', self.measurer.loss)
+
+ @staticmethod
+ def display_single_bound(result_samples, result_type, rate_total, pkt_size,
+ latency=None):
+ bandwidth_total = float(rate_total) * (pkt_size + 20) * 8 / (10 ** 9)
+
+ result_samples["Result_{}".format(result_type)] = {
+ "rate_total_pps": float(rate_total),
+ "bandwidth_total_Gbps": float(bandwidth_total),
+ }
+
+ if latency:
+ for item in latency:
+ if latency.index(item) == 0:
+ name = "Result_{}_{}".format("stream0", result_type)
+ else:
+ name = "Result_{}_{}".format("stream1", result_type)
+ lat_min, lat_avg, lat_max = item.split('/')
+ result_samples[name] = {
+ "min_latency": float(lat_min),
+ "avg_latency": float(lat_avg),
+ "max_latency": float(lat_max),
+ }
+
+ @staticmethod
+ def check_ndrpdr_interval_validity(result_samples, result_type, interval,
+ packet_loss_ratio=0.0):
+ lower_bound = interval.measured_low
+ lower_bound_lf = lower_bound.loss_fraction
+
+ result_samples["Result_{}_packets_lost".format(result_type)] = {
+ "packet_loss_ratio": float(lower_bound_lf),
+ "packets_lost": float(lower_bound.loss_count),
+ }
+
+ if lower_bound_lf <= packet_loss_ratio:
+ return "Minimal rate loss fraction {} reach target {}".format(
+ lower_bound_lf, packet_loss_ratio)
+ else:
+ message = "Minimal rate loss fraction {} does not reach target {}".format(
+ lower_bound_lf, packet_loss_ratio)
+ if lower_bound_lf >= 1.0:
+ return '{}\nZero packets forwarded!'.format(message)
+ else:
+ return '{}\n{} packets lost.'.format(message,
+ lower_bound.loss_count)
diff --git a/yardstick/network_services/helpers/vpp_helpers/ndr_pdr_result.py b/yardstick/network_services/helpers/vpp_helpers/ndr_pdr_result.py
new file mode 100644
index 000000000..34a97f9fb
--- /dev/null
+++ b/yardstick/network_services/helpers/vpp_helpers/ndr_pdr_result.py
@@ -0,0 +1,68 @@
+# Copyright (c) 2019 Viosoft 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.
+#
+# This is a modified copy of
+# https://gerrit.fd.io/r/gitweb?p=csit.git;a=blob_plain;f=resources/libraries/python/MLRsearch/NdrPdrResult.py;hb=HEAD
+
+from yardstick.network_services.helpers.vpp_helpers.receive_rate_interval import \
+ ReceiveRateInterval
+
+
+class NdrPdrResult(object):
+ """Two measurement intervals, return value of search algorithms.
+
+ Partial fraction is NOT part of the result. Pdr interval should be valid
+ for all partial fractions implied by the interval."""
+
+ def __init__(self, ndr_interval, pdr_interval):
+ """Store the measured intervals after checking argument types.
+
+ :param ndr_interval: Object containing data for NDR part of the result.
+ :param pdr_interval: Object containing data for PDR part of the result.
+ :type ndr_interval: ReceiveRateInterval.ReceiveRateInterval
+ :type pdr_interval: ReceiveRateInterval.ReceiveRateInterval
+ """
+ # TODO: Type checking is not very pythonic,
+ # perhaps users can fix wrong usage without it?
+ if not isinstance(ndr_interval, ReceiveRateInterval):
+ raise TypeError("ndr_interval, is not a ReceiveRateInterval: "
+ "{ndr!r}".format(ndr=ndr_interval))
+ if not isinstance(pdr_interval, ReceiveRateInterval):
+ raise TypeError("pdr_interval, is not a ReceiveRateInterval: "
+ "{pdr!r}".format(pdr=pdr_interval))
+ self.ndr_interval = ndr_interval
+ self.pdr_interval = pdr_interval
+
+ def width_in_goals(self, relative_width_goal):
+ """Return a debug string related to current widths in logarithmic scale.
+
+ :param relative_width_goal: Upper bound times this is the goal
+ difference between upper bound and lower bound.
+ :type relative_width_goal: float
+ :returns: Message containing NDR and PDR widths in goals.
+ :rtype: str
+ """
+ return "ndr {ndr_in_goals}; pdr {pdr_in_goals}".format(
+ ndr_in_goals=self.ndr_interval.width_in_goals(relative_width_goal),
+ pdr_in_goals=self.pdr_interval.width_in_goals(relative_width_goal))
+
+ def __str__(self):
+ """Return string as tuple of named values."""
+ return "NDR={ndr!s};PDR={pdr!s}".format(
+ ndr=self.ndr_interval, pdr=self.pdr_interval)
+
+ def __repr__(self):
+ """Return string evaluable as a constructor call."""
+ return "NdrPdrResult(ndr_interval={ndr!r},pdr_interval={pdr!r})".format(
+ ndr=self.ndr_interval, pdr=self.pdr_interval)
diff --git a/yardstick/network_services/helpers/vpp_helpers/receive_rate_interval.py b/yardstick/network_services/helpers/vpp_helpers/receive_rate_interval.py
new file mode 100644
index 000000000..517a99c1f
--- /dev/null
+++ b/yardstick/network_services/helpers/vpp_helpers/receive_rate_interval.py
@@ -0,0 +1,88 @@
+# Copyright (c) 2019 Viosoft 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.
+#
+# This is a modified copy of
+# https://gerrit.fd.io/r/gitweb?p=csit.git;a=blob_plain;f=resources/libraries/python/MLRsearch/ReceiveRateInterval.py;hb=HEAD
+
+import math
+
+from yardstick.network_services.helpers.vpp_helpers.receive_rate_measurement import \
+ ReceiveRateMeasurement
+
+
+class ReceiveRateInterval(object):
+ """Structure defining two Rr measurements, and their relation."""
+
+ def __init__(self, measured_low, measured_high):
+ """Store the bound measurements after checking argument types.
+
+ :param measured_low: Measurement for the lower bound.
+ :param measured_high: Measurement for the upper bound.
+ :type measured_low: ReceiveRateMeasurement.ReceiveRateMeasurement
+ :type measured_high: ReceiveRateMeasurement.ReceiveRateMeasurement
+ """
+ # TODO: Type checking is not very pythonic,
+ # perhaps users can fix wrong usage without it?
+ if not isinstance(measured_low, ReceiveRateMeasurement):
+ raise TypeError("measured_low is not a ReceiveRateMeasurement: "
+ "{low!r}".format(low=measured_low))
+ if not isinstance(measured_high, ReceiveRateMeasurement):
+ raise TypeError("measured_high is not a ReceiveRateMeasurement: "
+ "{high!r}".format(high=measured_high))
+ self.measured_low = measured_low
+ self.measured_high = measured_high
+ # Declare secondary quantities to appease pylint.
+ self.abs_tr_width = None
+ """Absolute width of target transmit rate. Upper minus lower."""
+ self.rel_tr_width = None
+ """Relative width of target transmit rate. Absolute divided by upper."""
+ self.sort()
+
+ def sort(self):
+ """Sort bounds by target Tr, compute secondary quantities."""
+ if self.measured_low.target_tr > self.measured_high.target_tr:
+ self.measured_low, self.measured_high = (
+ self.measured_high, self.measured_low)
+ self.abs_tr_width = (
+ self.measured_high.target_tr - self.measured_low.target_tr)
+ self.rel_tr_width = round(
+ self.abs_tr_width / self.measured_high.target_tr, 5)
+
+ def width_in_goals(self, relative_width_goal):
+ """Return float value.
+
+ Relative width goal is some (negative) value on logarithmic scale.
+ Current relative width is another logarithmic value.
+ Return the latter divided by the former.
+ This is useful when investigating how did surprising widths come to be.
+
+ :param relative_width_goal: Upper bound times this is the goal
+ difference between upper bound and lower bound.
+ :type relative_width_goal: float
+ :returns: Current width as logarithmic multiple of goal width [1].
+ :rtype: float
+ """
+ return round(math.log(1.0 - self.rel_tr_width) / math.log(
+ 1.0 - relative_width_goal), 5)
+
+ def __str__(self):
+ """Return string as half-open interval."""
+ return "[{low!s};{high!s})".format(
+ low=self.measured_low, high=self.measured_high)
+
+ def __repr__(self):
+ """Return string evaluable as a constructor call."""
+ return ("ReceiveRateInterval(measured_low={low!r}"
+ ",measured_high={high!r})".format(low=self.measured_low,
+ high=self.measured_high))
diff --git a/yardstick/network_services/helpers/vpp_helpers/receive_rate_measurement.py b/yardstick/network_services/helpers/vpp_helpers/receive_rate_measurement.py
new file mode 100644
index 000000000..2c59ea104
--- /dev/null
+++ b/yardstick/network_services/helpers/vpp_helpers/receive_rate_measurement.py
@@ -0,0 +1,58 @@
+# Copyright (c) 2019 Viosoft 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.
+#
+# This is a modified copy of
+# https://gerrit.fd.io/r/gitweb?p=csit.git;a=blob_plain;f=resources/libraries/python/MLRsearch/ReceiveRateMeasurement.py;hb=HEAD
+
+
+class ReceiveRateMeasurement(object):
+ """Structure defining the result of single Rr measurement."""
+
+ def __init__(self, duration, target_tr, transmit_count, loss_count):
+ """Constructor, normalize primary and compute secondary quantities.
+
+ :param duration: Measurement duration [s].
+ :param target_tr: Target transmit rate [pps].
+ If bidirectional traffic is measured, this is bidirectional rate.
+ :param transmit_count: Number of packets transmitted [1].
+ :param loss_count: Number of packets transmitted but not received [1].
+ :type duration: float
+ :type target_tr: float
+ :type transmit_count: int
+ :type loss_count: int
+ """
+ self.duration = float(duration)
+ self.target_tr = float(target_tr)
+ self.transmit_count = int(transmit_count)
+ self.loss_count = int(loss_count)
+ self.receive_count = round(transmit_count - loss_count, 5)
+ self.transmit_rate = round(transmit_count / self.duration, 5)
+ self.loss_rate = round(loss_count / self.duration, 5)
+ self.receive_rate = round(self.receive_count / self.duration, 5)
+ self.loss_fraction = round(
+ float(self.loss_count) / self.transmit_count, 5)
+ # TODO: Do we want to store also the real time (duration + overhead)?
+
+ def __str__(self):
+ """Return string reporting input and loss fraction."""
+ return "d={dur!s},Tr={rate!s},Df={frac!s}".format(
+ dur=self.duration, rate=self.target_tr, frac=self.loss_fraction)
+
+ def __repr__(self):
+ """Return string evaluable as a constructor call."""
+ return ("ReceiveRateMeasurement(duration={dur!r},target_tr={rate!r}"
+ ",transmit_count={trans!r},loss_count={loss!r})".format(
+ dur=self.duration, rate=self.target_tr,
+ trans=self.transmit_count,
+ loss=self.loss_count))
diff --git a/yardstick/network_services/traffic_profile/__init__.py b/yardstick/network_services/traffic_profile/__init__.py
index c5d8eff0b..85b3d54a0 100644
--- a/yardstick/network_services/traffic_profile/__init__.py
+++ b/yardstick/network_services/traffic_profile/__init__.py
@@ -31,6 +31,7 @@ def register_modules():
'yardstick.network_services.traffic_profile.pktgen',
'yardstick.network_services.traffic_profile.landslide_profile',
'yardstick.network_services.traffic_profile.vpp_rfc2544',
+ 'yardstick.network_services.traffic_profile.sip',
]
for module in modules:
diff --git a/yardstick/network_services/traffic_profile/sip.py b/yardstick/network_services/traffic_profile/sip.py
new file mode 100644
index 000000000..d18574090
--- /dev/null
+++ b/yardstick/network_services/traffic_profile/sip.py
@@ -0,0 +1,32 @@
+# Copyright (c) 2019 Viosoft 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.
+
+from yardstick.network_services.traffic_profile import base
+
+
+class SipProfile(base.TrafficProfile):
+ """ Sipp Traffic profile """
+
+ def __init__(self, yaml_data):
+ super(SipProfile, self).__init__(yaml_data)
+ self.generator = None
+
+ def execute_traffic(self, traffic_generator=None):
+ if traffic_generator is not None and self.generator is None:
+ self.generator = traffic_generator
+
+ def is_ended(self):
+ if self.generator is not None:
+ return self.generator.is_ended()
+ return False
diff --git a/yardstick/network_services/traffic_profile/vpp_rfc2544.py b/yardstick/network_services/traffic_profile/vpp_rfc2544.py
index 0f8185f90..412e4e69a 100644
--- a/yardstick/network_services/traffic_profile/vpp_rfc2544.py
+++ b/yardstick/network_services/traffic_profile/vpp_rfc2544.py
@@ -13,17 +13,19 @@
# limitations under the License.
import datetime
+import ipaddress
import logging
-from random import choice
-from string import ascii_letters
+import random
+import string
-from ipaddress import ip_address
from trex_stl_lib import api as Pkt
from trex_stl_lib import trex_stl_client
from trex_stl_lib import trex_stl_packet_builder_scapy
from trex_stl_lib import trex_stl_streams
from yardstick.common import constants
+from yardstick.network_services.helpers.vpp_helpers.multiple_loss_ratio_search import \
+ MultipleLossRatioSearch
from yardstick.network_services.traffic_profile.rfc2544 import RFC2544Profile, \
PortPgIDMap
from yardstick.network_services.traffic_profile.trex_traffic_profile import IP, \
@@ -37,6 +39,10 @@ class VppRFC2544Profile(RFC2544Profile):
def __init__(self, traffic_generator):
super(VppRFC2544Profile, self).__init__(traffic_generator)
+ tp_cfg = traffic_generator["traffic_profile"]
+ self.number_of_intermediate_phases = tp_cfg.get("intermediate_phases",
+ 2)
+
self.duration = self.config.duration
self.precision = self.config.test_precision
self.lower_bound = self.config.lower_bound
@@ -85,7 +91,7 @@ class VppRFC2544Profile(RFC2544Profile):
def _gen_payload(length):
payload = ""
for _ in range(length):
- payload += choice(ascii_letters)
+ payload += random.choice(string.ascii_letters)
return payload
@@ -153,8 +159,9 @@ class VppRFC2544Profile(RFC2544Profile):
dst=dst_start_ip,
proto=outer_l3v4['proto'])
if self.flow > 1:
- dst_start_int = int(ip_address(str(dst_start_ip)))
- dst_end_ip_new = ip_address(dst_start_int + self.flow - 1)
+ dst_start_int = int(ipaddress.ip_address(str(dst_start_ip)))
+ dst_end_ip_new = ipaddress.ip_address(
+ dst_start_int + self.flow - 1)
# self._set_proto_addr(IP, SRC, outer_l3v4['srcip4'], outer_l3v4['count'])
self._set_proto_addr(IP, DST,
"{start_ip}-{end_ip}".format(
@@ -248,8 +255,19 @@ class VppRFC2544Profile(RFC2544Profile):
def binary_search_with_optimized(self, traffic_generator, duration,
timeout, test_data):
- # TODO Support FD.io Multiple Loss Ratio search (MLRsearch)
- pass
+ self.queue.cancel_join_thread()
+ algorithm = MultipleLossRatioSearch(
+ measurer=traffic_generator, latency=self.enable_latency,
+ pkt_size=self.pkt_size,
+ final_trial_duration=duration,
+ final_relative_width=self.step_interval / 100,
+ number_of_intermediate_phases=self.number_of_intermediate_phases,
+ initial_trial_duration=1,
+ timeout=timeout)
+ algorithm.init_generator(self.ports, self.port_pg_id, self.profiles,
+ test_data, self.queue)
+ return algorithm.narrow_down_ndr_and_pdr(10000, self.max_rate,
+ self.tolerance_high)
def binary_search(self, traffic_generator, duration, tolerance_value,
test_data):
diff --git a/yardstick/network_services/vnf_generic/vnf/base.py b/yardstick/network_services/vnf_generic/vnf/base.py
index 8064ae927..8ef96b744 100644
--- a/yardstick/network_services/vnf_generic/vnf/base.py
+++ b/yardstick/network_services/vnf_generic/vnf/base.py
@@ -94,7 +94,7 @@ class VnfdHelper(dict):
for interface in self.interfaces:
virtual_intf = interface["virtual-interface"]
if virtual_intf[key] == value:
- return interface
+ return virtual_intf
raise KeyError()
def find_interface(self, **kwargs):
diff --git a/yardstick/network_services/vnf_generic/vnf/ipsec_vnf.py b/yardstick/network_services/vnf_generic/vnf/ipsec_vnf.py
new file mode 100644
index 000000000..1961ac1b1
--- /dev/null
+++ b/yardstick/network_services/vnf_generic/vnf/ipsec_vnf.py
@@ -0,0 +1,498 @@
+# Copyright (c) 2019 Viosoft 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.
+
+import logging
+import re
+import time
+from collections import Counter
+from enum import Enum
+
+from yardstick.benchmark.contexts.base import Context
+from yardstick.common.process import check_if_process_failed
+from yardstick.network_services import constants
+from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNF
+from yardstick.network_services.vnf_generic.vnf.vpp_helpers import \
+ VppSetupEnvHelper, VppConfigGenerator
+
+LOG = logging.getLogger(__name__)
+
+
+class CryptoAlg(Enum):
+ """Encryption algorithms."""
+ AES_CBC_128 = ('aes-cbc-128', 'AES-CBC', 16)
+ AES_CBC_192 = ('aes-cbc-192', 'AES-CBC', 24)
+ AES_CBC_256 = ('aes-cbc-256', 'AES-CBC', 32)
+ AES_GCM_128 = ('aes-gcm-128', 'AES-GCM', 20)
+
+ def __init__(self, alg_name, scapy_name, key_len):
+ self.alg_name = alg_name
+ self.scapy_name = scapy_name
+ self.key_len = key_len
+
+
+class IntegAlg(Enum):
+ """Integrity algorithms."""
+ SHA1_96 = ('sha1-96', 'HMAC-SHA1-96', 20)
+ SHA_256_128 = ('sha-256-128', 'SHA2-256-128', 32)
+ SHA_384_192 = ('sha-384-192', 'SHA2-384-192', 48)
+ SHA_512_256 = ('sha-512-256', 'SHA2-512-256', 64)
+ AES_GCM_128 = ('aes-gcm-128', 'AES-GCM', 20)
+
+ def __init__(self, alg_name, scapy_name, key_len):
+ self.alg_name = alg_name
+ self.scapy_name = scapy_name
+ self.key_len = key_len
+
+
+class VipsecApproxSetupEnvHelper(VppSetupEnvHelper):
+ DEFAULT_IPSEC_VNF_CFG = {
+ 'crypto_type': 'SW_cryptodev',
+ 'rxq': 1,
+ 'worker_config': '1C/1T',
+ 'worker_threads': 1,
+ }
+
+ def __init__(self, vnfd_helper, ssh_helper, scenario_helper):
+ super(VipsecApproxSetupEnvHelper, self).__init__(
+ vnfd_helper, ssh_helper, scenario_helper)
+
+ def _get_crypto_type(self):
+ vnf_cfg = self.scenario_helper.options.get('vnf_config',
+ self.DEFAULT_IPSEC_VNF_CFG)
+ return vnf_cfg.get('crypto_type', 'SW_cryptodev')
+
+ def _get_crypto_algorithms(self):
+ vpp_cfg = self.scenario_helper.all_options.get('vpp_config', {})
+ return vpp_cfg.get('crypto_algorithms', 'aes-gcm')
+
+ def _get_n_tunnels(self):
+ vpp_cfg = self.scenario_helper.all_options.get('vpp_config', {})
+ return vpp_cfg.get('tunnels', 1)
+
+ def _get_n_connections(self):
+ try:
+ flow_cfg = self.scenario_helper.all_options['flow']
+ return flow_cfg['count']
+ except KeyError:
+ raise KeyError("Missing flow definition in scenario section" +
+ " of the task definition file")
+
+ def _get_flow_src_start_ip(self):
+ node_name = self.find_encrypted_data_interface()["node_name"]
+ try:
+ flow_cfg = self.scenario_helper.all_options['flow']
+ src_ips = flow_cfg['src_ip']
+ dst_ips = flow_cfg['dst_ip']
+ except KeyError:
+ raise KeyError("Missing flow definition in scenario section" +
+ " of the task definition file")
+
+ for src, dst in zip(src_ips, dst_ips):
+ flow_src_start_ip, _ = src.split('-')
+ flow_dst_start_ip, _ = dst.split('-')
+
+ if node_name == "vnf__0":
+ return flow_src_start_ip
+ elif node_name == "vnf__1":
+ return flow_dst_start_ip
+
+ def _get_flow_dst_start_ip(self):
+ node_name = self.find_encrypted_data_interface()["node_name"]
+ try:
+ flow_cfg = self.scenario_helper.all_options['flow']
+ src_ips = flow_cfg['src_ip']
+ dst_ips = flow_cfg['dst_ip']
+ except KeyError:
+ raise KeyError("Missing flow definition in scenario section" +
+ " of the task definition file")
+
+ for src, dst in zip(src_ips, dst_ips):
+ flow_src_start_ip, _ = src.split('-')
+ flow_dst_start_ip, _ = dst.split('-')
+
+ if node_name == "vnf__0":
+ return flow_dst_start_ip
+ elif node_name == "vnf__1":
+ return flow_src_start_ip
+
+ def build_config(self):
+ vnf_cfg = self.scenario_helper.options.get('vnf_config',
+ self.DEFAULT_IPSEC_VNF_CFG)
+ rxq = vnf_cfg.get('rxq', 1)
+ phy_cores = vnf_cfg.get('worker_threads', 1)
+ # worker_config = vnf_cfg.get('worker_config', '1C/1T').split('/')[1].lower()
+
+ vpp_cfg = self.create_startup_configuration_of_vpp()
+ self.add_worker_threads_and_rxqueues(vpp_cfg, phy_cores, rxq)
+ self.add_pci_devices(vpp_cfg)
+
+ frame_size_cfg = self.scenario_helper.all_options.get('framesize', {})
+ uplink_cfg = frame_size_cfg.get('uplink', {})
+ downlink_cfg = frame_size_cfg.get('downlink', {})
+ framesize = min(self.calculate_frame_size(uplink_cfg),
+ self.calculate_frame_size(downlink_cfg))
+ if framesize < 1522:
+ vpp_cfg.add_dpdk_no_multi_seg()
+
+ crypto_algorithms = self._get_crypto_algorithms()
+ if crypto_algorithms == 'aes-gcm':
+ self.add_dpdk_cryptodev(vpp_cfg, 'aesni_gcm', phy_cores)
+ elif crypto_algorithms == 'cbc-sha1':
+ self.add_dpdk_cryptodev(vpp_cfg, 'aesni_mb', phy_cores)
+
+ vpp_cfg.add_dpdk_dev_default_rxd(2048)
+ vpp_cfg.add_dpdk_dev_default_txd(2048)
+ self.apply_config(vpp_cfg, True)
+ self.update_vpp_interface_data()
+
+ def setup_vnf_environment(self):
+ resource = super(VipsecApproxSetupEnvHelper,
+ self).setup_vnf_environment()
+
+ self.start_vpp_service()
+ # for QAT device DH895xCC, the number of VFs is required as 32
+ if self._get_crypto_type() == 'HW_cryptodev':
+ sriov_numvfs = self.get_sriov_numvfs(
+ self.find_encrypted_data_interface()["vpci"])
+ if sriov_numvfs != 32:
+ self.crypto_device_init(
+ self.find_encrypted_data_interface()["vpci"], 32)
+
+ self._update_vnfd_helper(self.sys_cores.get_cpu_layout())
+ self.update_vpp_interface_data()
+ self.iface_update_numa()
+
+ return resource
+
+ @staticmethod
+ def calculate_frame_size(frame_cfg):
+ if not frame_cfg:
+ return 64
+
+ imix_count = {size.upper().replace('B', ''): int(weight)
+ for size, weight in frame_cfg.items()}
+ imix_sum = sum(imix_count.values())
+ if imix_sum <= 0:
+ return 64
+ packets_total = sum([int(size) * weight
+ for size, weight in imix_count.items()])
+ return packets_total / imix_sum
+
+ def check_status(self):
+ ipsec_created = False
+ cmd = "vppctl show int"
+ _, stdout, _ = self.ssh_helper.execute(cmd)
+ entries = re.split(r"\n+", stdout)
+ tmp = [re.split(r"\s\s+", entry, 5) for entry in entries]
+
+ for item in tmp:
+ if isinstance(item, list):
+ if item[0] and item[0] != 'local0':
+ if "ipsec" in item[0] and not ipsec_created:
+ ipsec_created = True
+ if len(item) > 2 and item[2] == 'down':
+ return False
+ return ipsec_created
+
+ def get_vpp_statistics(self):
+ cmd = "vppctl show int {intf}"
+ result = {}
+ for interface in self.vnfd_helper.interfaces:
+ iface_name = self.get_value_by_interface_key(
+ interface["virtual-interface"]["ifname"], "vpp_name")
+ command = cmd.format(intf=iface_name)
+ _, stdout, _ = self.ssh_helper.execute(command)
+ result.update(
+ self.parser_vpp_stats(interface["virtual-interface"]["ifname"],
+ iface_name, stdout))
+ self.ssh_helper.execute("vppctl clear interfaces")
+ return result
+
+ @staticmethod
+ def parser_vpp_stats(interface, iface_name, stats):
+ packets_in = 0
+ packets_fwd = 0
+ packets_dropped = 0
+ result = {}
+
+ entries = re.split(r"\n+", stats)
+ tmp = [re.split(r"\s\s+", entry, 5) for entry in entries]
+
+ for item in tmp:
+ if isinstance(item, list):
+ if item[0] == iface_name and len(item) >= 5:
+ if item[3] == 'rx packets':
+ packets_in = int(item[4])
+ elif item[4] == 'rx packets':
+ packets_in = int(item[5])
+ elif len(item) == 3:
+ if item[1] == 'tx packets':
+ packets_fwd = int(item[2])
+ elif item[1] == 'drops' or item[1] == 'rx-miss':
+ packets_dropped = int(item[2])
+ if packets_dropped == 0 and packets_in > 0 and packets_fwd > 0:
+ packets_dropped = abs(packets_fwd - packets_in)
+
+ result[interface] = {
+ 'packets_in': packets_in,
+ 'packets_fwd': packets_fwd,
+ 'packets_dropped': packets_dropped,
+ }
+
+ return result
+
+ def create_ipsec_tunnels(self):
+ self.initialize_ipsec()
+
+ # TODO generate the same key
+ crypto_algorithms = self._get_crypto_algorithms()
+ if crypto_algorithms == 'aes-gcm':
+ encr_alg = CryptoAlg.AES_GCM_128
+ auth_alg = IntegAlg.AES_GCM_128
+ encr_key = 'LNYZXMBQDKESNLREHJMS'
+ auth_key = 'SWGLDTYZSQKVBZZMPIEV'
+ elif crypto_algorithms == 'cbc-sha1':
+ encr_alg = CryptoAlg.AES_CBC_128
+ auth_alg = IntegAlg.SHA1_96
+ encr_key = 'IFEMSHYLCZIYFUTT'
+ auth_key = 'PEALEIPSCPTRHYJSDXLY'
+
+ self.execute_script("enable_dpdk_traces.vat", json_out=False)
+ self.execute_script("enable_vhost_user_traces.vat", json_out=False)
+ self.execute_script("enable_memif_traces.vat", json_out=False)
+
+ node_name = self.find_encrypted_data_interface()["node_name"]
+ n_tunnels = self._get_n_tunnels()
+ n_connections = self._get_n_connections()
+ flow_dst_start_ip = self._get_flow_dst_start_ip()
+ if node_name == "vnf__0":
+ self.vpp_create_ipsec_tunnels(
+ self.find_encrypted_data_interface()["local_ip"],
+ self.find_encrypted_data_interface()["peer_intf"]["local_ip"],
+ self.find_encrypted_data_interface()["ifname"],
+ n_tunnels, n_connections, encr_alg, encr_key, auth_alg,
+ auth_key, flow_dst_start_ip)
+ elif node_name == "vnf__1":
+ self.vpp_create_ipsec_tunnels(
+ self.find_encrypted_data_interface()["local_ip"],
+ self.find_encrypted_data_interface()["peer_intf"]["local_ip"],
+ self.find_encrypted_data_interface()["ifname"],
+ n_tunnels, n_connections, encr_alg, encr_key, auth_alg,
+ auth_key, flow_dst_start_ip, 20000, 10000)
+
+ def find_raw_data_interface(self):
+ try:
+ return self.vnfd_helper.find_virtual_interface(vld_id="uplink_0")
+ except KeyError:
+ return self.vnfd_helper.find_virtual_interface(vld_id="downlink_0")
+
+ def find_encrypted_data_interface(self):
+ return self.vnfd_helper.find_virtual_interface(vld_id="ciphertext")
+
+ def create_startup_configuration_of_vpp(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_unix_log()
+ vpp_config_generator.add_unix_cli_listen()
+ vpp_config_generator.add_unix_nodaemon()
+ vpp_config_generator.add_unix_coredump()
+ vpp_config_generator.add_dpdk_socketmem('1024,1024')
+ vpp_config_generator.add_dpdk_no_tx_checksum_offload()
+ vpp_config_generator.add_dpdk_log_level('debug')
+ for interface in self.vnfd_helper.interfaces:
+ vpp_config_generator.add_dpdk_uio_driver(
+ interface["virtual-interface"]["driver"])
+ vpp_config_generator.add_heapsize('4G')
+ # TODO Enable configuration depend on VPP version
+ vpp_config_generator.add_statseg_size('4G')
+ vpp_config_generator.add_plugin('disable', ['default'])
+ vpp_config_generator.add_plugin('enable', ['dpdk_plugin.so'])
+ vpp_config_generator.add_ip6_hash_buckets('2000000')
+ vpp_config_generator.add_ip6_heap_size('4G')
+ vpp_config_generator.add_ip_heap_size('4G')
+ return vpp_config_generator
+
+ def add_worker_threads_and_rxqueues(self, vpp_cfg, phy_cores,
+ rx_queues=None):
+ thr_count_int = phy_cores
+ cpu_count_int = phy_cores
+ num_mbufs_int = 32768
+
+ numa_list = []
+
+ if_list = [self.find_encrypted_data_interface()["ifname"],
+ self.find_raw_data_interface()["ifname"]]
+ for if_key in if_list:
+ try:
+ numa_list.append(
+ self.get_value_by_interface_key(if_key, 'numa_node'))
+ except KeyError:
+ pass
+ numa_cnt_mc = Counter(numa_list).most_common()
+
+ if numa_cnt_mc and numa_cnt_mc[0][0] is not None and \
+ numa_cnt_mc[0][0] != -1:
+ numa = numa_cnt_mc[0][0]
+ elif len(numa_cnt_mc) > 1 and numa_cnt_mc[0][0] == -1:
+ numa = numa_cnt_mc[1][0]
+ else:
+ numa = 0
+
+ try:
+ smt_used = self.sys_cores.is_smt_enabled()
+ except KeyError:
+ smt_used = False
+
+ cpu_main = self.sys_cores.cpu_list_per_node_str(numa, skip_cnt=1,
+ cpu_cnt=1)
+ cpu_wt = self.sys_cores.cpu_list_per_node_str(numa, skip_cnt=2,
+ cpu_cnt=cpu_count_int,
+ smt_used=smt_used)
+
+ if smt_used:
+ thr_count_int = 2 * cpu_count_int
+
+ if rx_queues is None:
+ rxq_count_int = int(thr_count_int / 2)
+ else:
+ rxq_count_int = rx_queues
+
+ if rxq_count_int == 0:
+ rxq_count_int = 1
+
+ num_mbufs_int = num_mbufs_int * rxq_count_int
+
+ vpp_cfg.add_cpu_main_core(cpu_main)
+ vpp_cfg.add_cpu_corelist_workers(cpu_wt)
+ vpp_cfg.add_dpdk_dev_default_rxq(rxq_count_int)
+ vpp_cfg.add_dpdk_num_mbufs(num_mbufs_int)
+
+ def add_pci_devices(self, vpp_cfg):
+ pci_devs = [self.find_encrypted_data_interface()["vpci"],
+ self.find_raw_data_interface()["vpci"]]
+ vpp_cfg.add_dpdk_dev(*pci_devs)
+
+ def add_dpdk_cryptodev(self, vpp_cfg, sw_pmd_type, count):
+ crypto_type = self._get_crypto_type()
+ smt_used = self.sys_cores.is_smt_enabled()
+ cryptodev = self.find_encrypted_data_interface()["vpci"]
+ socket_id = self.get_value_by_interface_key(
+ self.find_encrypted_data_interface()["ifname"], "numa_node")
+
+ if smt_used:
+ thr_count_int = count * 2
+ if crypto_type == 'HW_cryptodev':
+ vpp_cfg.add_dpdk_cryptodev(thr_count_int, cryptodev)
+ else:
+ vpp_cfg.add_dpdk_sw_cryptodev(sw_pmd_type, socket_id,
+ thr_count_int)
+ else:
+ thr_count_int = count
+ if crypto_type == 'HW_cryptodev':
+ vpp_cfg.add_dpdk_cryptodev(thr_count_int, cryptodev)
+ else:
+ vpp_cfg.add_dpdk_sw_cryptodev(sw_pmd_type, socket_id,
+ thr_count_int)
+
+ def initialize_ipsec(self):
+ flow_src_start_ip = self._get_flow_src_start_ip()
+
+ self.set_interface_state(
+ self.find_encrypted_data_interface()["ifname"], 'up')
+ self.set_interface_state(self.find_raw_data_interface()["ifname"],
+ 'up')
+ self.vpp_interfaces_ready_wait()
+ self.vpp_set_interface_mtu(
+ self.find_encrypted_data_interface()["ifname"])
+ self.vpp_set_interface_mtu(self.find_raw_data_interface()["ifname"])
+ self.vpp_interfaces_ready_wait()
+
+ self.set_ip(self.find_encrypted_data_interface()["ifname"],
+ self.find_encrypted_data_interface()["local_ip"], 24)
+ self.set_ip(self.find_raw_data_interface()["ifname"],
+ self.find_raw_data_interface()["local_ip"],
+ 24)
+
+ self.add_arp_on_dut(self.find_encrypted_data_interface()["ifname"],
+ self.find_encrypted_data_interface()["peer_intf"][
+ "local_ip"],
+ self.find_encrypted_data_interface()["peer_intf"][
+ "local_mac"])
+ self.add_arp_on_dut(self.find_raw_data_interface()["ifname"],
+ self.find_raw_data_interface()["peer_intf"][
+ "local_ip"],
+ self.find_raw_data_interface()["peer_intf"][
+ "local_mac"])
+
+ self.vpp_route_add(flow_src_start_ip, 8,
+ self.find_raw_data_interface()["peer_intf"][
+ "local_ip"],
+ self.find_raw_data_interface()["ifname"])
+
+
+class VipsecApproxVnf(SampleVNF):
+ """ This class handles vIPSEC VNF model-driver definitions """
+
+ APP_NAME = 'vIPSEC'
+ APP_WORD = 'vipsec'
+ WAIT_TIME = 20
+
+ def __init__(self, name, vnfd, setup_env_helper_type=None,
+ resource_helper_type=None):
+ if setup_env_helper_type is None:
+ setup_env_helper_type = VipsecApproxSetupEnvHelper
+ super(VipsecApproxVnf, self).__init__(
+ name, vnfd, setup_env_helper_type,
+ resource_helper_type)
+
+ def _run(self):
+ # we can't share ssh paramiko objects to force new connection
+ self.ssh_helper.drop_connection()
+ # kill before starting
+ self.setup_helper.kill_vnf()
+ self._build_config()
+ self.setup_helper.create_ipsec_tunnels()
+
+ def wait_for_instantiate(self):
+ time.sleep(self.WAIT_TIME)
+ while True:
+ status = self.setup_helper.check_status()
+ if not self._vnf_process.is_alive() and not status:
+ raise RuntimeError("%s VNF process died." % self.APP_NAME)
+ LOG.info("Waiting for %s VNF to start.. ", self.APP_NAME)
+ time.sleep(self.WAIT_TIME_FOR_SCRIPT)
+ status = self.setup_helper.check_status()
+ if status:
+ LOG.info("%s VNF is up and running.", self.APP_NAME)
+ self._vnf_up_post()
+ return self._vnf_process.exitcode
+
+ def terminate(self):
+ self.setup_helper.kill_vnf()
+ self._tear_down()
+ self.resource_helper.stop_collect()
+ if self._vnf_process is not None:
+ # be proper and join first before we kill
+ LOG.debug("joining before terminate %s", self._vnf_process.name)
+ self._vnf_process.join(constants.PROCESS_JOIN_TIMEOUT)
+ self._vnf_process.terminate()
+
+ def collect_kpi(self):
+ # we can't get KPIs if the VNF is down
+ check_if_process_failed(self._vnf_process, 0.01)
+ physical_node = Context.get_physical_node_from_server(
+ self.scenario_helper.nodes[self.name])
+ result = {"physical_node": physical_node}
+ result["collect_stats"] = self.setup_helper.get_vpp_statistics()
+ LOG.debug("%s collect KPIs %s", self.APP_NAME, result)
+ return result
diff --git a/yardstick/network_services/vnf_generic/vnf/tg_imsbench_sipp.py b/yardstick/network_services/vnf_generic/vnf/tg_imsbench_sipp.py
new file mode 100644
index 000000000..70557b848
--- /dev/null
+++ b/yardstick/network_services/vnf_generic/vnf/tg_imsbench_sipp.py
@@ -0,0 +1,143 @@
+# Copyright (c) 2019 Viosoft 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.
+
+import logging
+from collections import deque
+
+from yardstick.network_services.vnf_generic.vnf import sample_vnf
+
+LOG = logging.getLogger(__name__)
+
+
+class SippSetupEnvHelper(sample_vnf.SetupEnvHelper):
+ APP_NAME = "ImsbenchSipp"
+
+
+class SippResourceHelper(sample_vnf.ClientResourceHelper):
+ pass
+
+
+class SippVnf(sample_vnf.SampleVNFTrafficGen):
+ """
+ This class calls the test script from TG machine, then gets the result file
+ from IMS machine. After that, the result file is handled line by line, and
+ is updated to database.
+ """
+
+ APP_NAME = "ImsbenchSipp"
+ APP_WORD = "ImsbenchSipp"
+ VNF_TYPE = "ImsbenchSipp"
+ HW_OFFLOADING_NFVI_TYPES = {'baremetal', 'sriov'}
+ RESULT = "/tmp/final_result.dat"
+ SIPP_RESULT = "/tmp/sipp_dat_files/final_result.dat"
+ LOCAL_PATH = "/tmp"
+ CMD = "./SIPp_benchmark.bash {} {} {} '{}'"
+
+ def __init__(self, name, vnfd, setup_env_helper_type=None,
+ resource_helper_type=None):
+ if resource_helper_type is None:
+ resource_helper_type = SippResourceHelper
+ if setup_env_helper_type is None:
+ setup_env_helper_type = SippSetupEnvHelper
+ super(SippVnf, self).__init__(
+ name, vnfd, setup_env_helper_type, resource_helper_type)
+ self.params = ""
+ self.pcscf_ip = self.vnfd_helper.interfaces[0]["virtual-interface"]\
+ ["peer_intf"]["local_ip"]
+ self.sipp_ip = self.vnfd_helper.interfaces[0]["virtual-interface"]\
+ ["local_ip"]
+ self.media_ip = self.vnfd_helper.interfaces[1]["virtual-interface"]\
+ ["local_ip"]
+ self.queue = ""
+ self.count = 0
+
+ def instantiate(self, scenario_cfg, context_cfg):
+ super(SippVnf, self).instantiate(scenario_cfg, context_cfg)
+ scenario_cfg = {}
+ _params = [("port", 5060), ("start_user", 1), ("end_user", 10000),
+ ("init_reg_cps", 50), ("init_reg_max", 5000), ("reg_cps", 50),
+ ("reg_step", 10), ("rereg_cps", 10), ("rereg_step", 5),
+ ("dereg_cps", 10), ("dereg_step", 5), ("msgc_cps", 10),
+ ("msgc_step", 2), ("run_mode", "rtp"), ("call_cps", 10),
+ ("hold_time", 15), ("call_step", 5)]
+
+ self.params = ';'.join([str(scenario_cfg.get("options", {}).get(k, v))
+ for k, v in dict(_params).items()])
+
+ def wait_for_instantiate(self):
+ pass
+
+ def get_result_files(self):
+ self.ssh_helper.get(self.SIPP_RESULT, self.LOCAL_PATH, True)
+
+ # Example of result file:
+ # cat /tmp/final_result.dat
+ # timestamp:1000 reg:100 reg_saps:0
+ # timestamp:2000 reg:100 reg_saps:50
+ # timestamp:3000 reg:100 reg_saps:50
+ # timestamp:4000 reg:100 reg_saps:50
+ # ...
+ # reg_Requested_prereg:50
+ # reg_Effective_prereg:49.49
+ # reg_DOC:0
+ # ...
+ @staticmethod
+ def handle_result_files(filename):
+ with open(filename, 'r') as f:
+ content = f.readlines()
+ result = [{k: round(float(v), 2) for k, v in [i.split(":", 1) for i in x.split()]}
+ for x in content if x]
+ return deque(result)
+
+ def run_traffic(self, traffic_profile):
+ traffic_profile.execute_traffic(self)
+ cmd = self.CMD.format(self.sipp_ip, self.media_ip,
+ self.pcscf_ip, self.params)
+ self.ssh_helper.execute(cmd, None, 3600, False)
+ self.get_result_files()
+ self.queue = self.handle_result_files(self.RESULT)
+
+ def collect_kpi(self):
+ result = {}
+ try:
+ result = self.queue.popleft()
+ except IndexError:
+ pass
+ return result
+
+ @staticmethod
+ def count_line_num(fname):
+ try:
+ with open(fname, 'r') as f:
+ return sum(1 for line in f)
+ except IOError:
+ return 0
+
+ def is_ended(self):
+ """
+ The test will end when the results are pushed into database.
+ It does not depend on the "duration" value, so this value will be set
+ enough big to make sure that the test will end before duration.
+ """
+ num_lines = self.count_line_num(self.RESULT)
+ if self.count == num_lines:
+ LOG.debug('TG IS ENDED.....................')
+ self.count = 0
+ return True
+ self.count += 1
+ return False
+
+ def terminate(self):
+ LOG.debug('TERMINATE:.....................')
+ self.resource_helper.terminate()
diff --git a/yardstick/network_services/vnf_generic/vnf/tg_trex_vpp.py b/yardstick/network_services/vnf_generic/vnf/tg_trex_vpp.py
new file mode 100644
index 000000000..846304880
--- /dev/null
+++ b/yardstick/network_services/vnf_generic/vnf/tg_trex_vpp.py
@@ -0,0 +1,178 @@
+# Copyright (c) 2019 Viosoft 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.
+
+import logging
+
+from trex_stl_lib.trex_stl_exceptions import STLError
+
+from yardstick.common.utils import safe_cast
+from yardstick.network_services.vnf_generic.vnf.sample_vnf import \
+ Rfc2544ResourceHelper
+from yardstick.network_services.vnf_generic.vnf.sample_vnf import \
+ SampleVNFTrafficGen
+from yardstick.network_services.vnf_generic.vnf.tg_trex import \
+ TrexDpdkVnfSetupEnvHelper
+from yardstick.network_services.vnf_generic.vnf.tg_trex import \
+ TrexResourceHelper
+
+LOGGING = logging.getLogger(__name__)
+
+
+class TrexVppResourceHelper(TrexResourceHelper):
+
+ def __init__(self, setup_helper, rfc_helper_type=None):
+ super(TrexVppResourceHelper, self).__init__(setup_helper)
+
+ if rfc_helper_type is None:
+ rfc_helper_type = Rfc2544ResourceHelper
+
+ self.rfc2544_helper = rfc_helper_type(self.scenario_helper)
+
+ self.loss = None
+ self.sent = None
+ self.latency = None
+
+ def generate_samples(self, stats=None, ports=None, port_pg_id=None,
+ latency=False):
+ samples = {}
+ if stats is None:
+ stats = self.get_stats(ports)
+ for pname in (intf['name'] for intf in self.vnfd_helper.interfaces):
+ port_num = self.vnfd_helper.port_num(pname)
+ port_stats = stats.get(port_num, {})
+ samples[pname] = {
+ 'rx_throughput_fps': float(port_stats.get('rx_pps', 0.0)),
+ 'tx_throughput_fps': float(port_stats.get('tx_pps', 0.0)),
+ 'rx_throughput_bps': float(port_stats.get('rx_bps', 0.0)),
+ 'tx_throughput_bps': float(port_stats.get('tx_bps', 0.0)),
+ 'in_packets': int(port_stats.get('ipackets', 0)),
+ 'out_packets': int(port_stats.get('opackets', 0)),
+ }
+
+ if latency:
+ pg_id_list = port_pg_id.get_pg_ids(port_num)
+ samples[pname]['latency'] = {}
+ for pg_id in pg_id_list:
+ latency_global = stats.get('latency', {})
+ pg_latency = latency_global.get(pg_id, {}).get('latency')
+
+ t_min = safe_cast(pg_latency.get("total_min", 0.0), float,
+ -1.0)
+ t_avg = safe_cast(pg_latency.get("average", 0.0), float,
+ -1.0)
+ t_max = safe_cast(pg_latency.get("total_max", 0.0), float,
+ -1.0)
+
+ latency = {
+ "min_latency": t_min,
+ "max_latency": t_max,
+ "avg_latency": t_avg,
+ }
+ samples[pname]['latency'][pg_id] = latency
+
+ return samples
+
+ def _run_traffic_once(self, traffic_profile):
+ self.client_started.value = 1
+ traffic_profile.execute_traffic(self)
+ return True
+
+ def run_traffic(self, traffic_profile):
+ self._queue.cancel_join_thread()
+ traffic_profile.init_queue(self._queue)
+ super(TrexVppResourceHelper, self).run_traffic(traffic_profile)
+
+ @staticmethod
+ def fmt_latency(lat_min, lat_avg, lat_max):
+ t_min = int(round(safe_cast(lat_min, float, -1.0)))
+ t_avg = int(round(safe_cast(lat_avg, float, -1.0)))
+ t_max = int(round(safe_cast(lat_max, float, -1.0)))
+
+ return "/".join(str(tmp) for tmp in (t_min, t_avg, t_max))
+
+ def send_traffic_on_tg(self, ports, port_pg_id, duration, rate,
+ latency=False):
+ try:
+ # Choose rate and start traffic:
+ self.client.start(ports=ports, mult=rate, duration=duration)
+ # Block until done:
+ try:
+ self.client.wait_on_traffic(ports=ports, timeout=duration + 20)
+ except STLError as err:
+ self.client.stop(ports)
+ LOGGING.error("TRex stateless timeout error: %s", err)
+
+ if self.client.get_warnings():
+ for warning in self.client.get_warnings():
+ LOGGING.warning(warning)
+
+ # Read the stats after the test
+ stats = self.client.get_stats()
+
+ packets_in = []
+ packets_out = []
+ for port in ports:
+ packets_in.append(stats[port]["ipackets"])
+ packets_out.append(stats[port]["opackets"])
+
+ if latency:
+ self.latency = []
+ pg_id_list = port_pg_id.get_pg_ids(port)
+ for pg_id in pg_id_list:
+ latency_global = stats.get('latency', {})
+ pg_latency = latency_global.get(pg_id, {}).get(
+ 'latency')
+ lat = self.fmt_latency(
+ str(pg_latency.get("total_min")),
+ str(pg_latency.get("average")),
+ str(pg_latency.get("total_max")))
+ LOGGING.info(
+ "latencyStream%s(usec)=%s", pg_id, lat)
+ self.latency.append(lat)
+
+ self.sent = sum(packets_out)
+ total_rcvd = sum(packets_in)
+ self.loss = self.sent - total_rcvd
+ LOGGING.info("rate=%s, totalReceived=%s, totalSent=%s,"
+ " frameLoss=%s", rate, total_rcvd, self.sent,
+ self.loss)
+ return stats
+ except STLError as err:
+ LOGGING.error("TRex stateless runtime error: %s", err)
+ raise RuntimeError('TRex stateless runtime error')
+
+
+class TrexTrafficGenVpp(SampleVNFTrafficGen):
+ APP_NAME = 'TRex'
+ WAIT_TIME = 20
+
+ def __init__(self, name, vnfd, setup_env_helper_type=None,
+ resource_helper_type=None):
+ if setup_env_helper_type is None:
+ setup_env_helper_type = TrexDpdkVnfSetupEnvHelper
+ if resource_helper_type is None:
+ resource_helper_type = TrexVppResourceHelper
+
+ super(TrexTrafficGenVpp, self).__init__(
+ name, vnfd, setup_env_helper_type, resource_helper_type)
+
+ def _check_status(self):
+ return self.resource_helper.check_status()
+
+ def _start_server(self):
+ super(TrexTrafficGenVpp, self)._start_server()
+ self.resource_helper.start()
+
+ def wait_for_instantiate(self):
+ return self._wait_for_process()
diff --git a/yardstick/network_services/vnf_generic/vnf/tg_vcmts_pktgen.py b/yardstick/network_services/vnf_generic/vnf/tg_vcmts_pktgen.py
new file mode 100755
index 000000000..c6df9d04c
--- /dev/null
+++ b/yardstick/network_services/vnf_generic/vnf/tg_vcmts_pktgen.py
@@ -0,0 +1,215 @@
+# Copyright (c) 2019 Viosoft 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.
+
+import logging
+import time
+import socket
+import yaml
+import os
+
+from yardstick.network_services.vnf_generic.vnf import sample_vnf
+from yardstick.common import exceptions
+
+
+LOG = logging.getLogger(__name__)
+
+
+class PktgenHelper(object):
+
+ RETRY_SECONDS = 0.5
+ RETRY_COUNT = 20
+ CONNECT_TIMEOUT = 5
+
+ def __init__(self, host, port=23000):
+ self.host = host
+ self.port = port
+ self.connected = False
+
+ def _connect(self):
+ self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ ret = True
+ try:
+ self._sock.settimeout(self.CONNECT_TIMEOUT)
+ self._sock.connect((self.host, self.port))
+ except (socket.gaierror, socket.error, socket.timeout):
+ self._sock.close()
+ ret = False
+
+ return ret
+
+ def connect(self):
+ if self.connected:
+ return True
+ LOG.info("Connecting to pktgen instance at %s...", self.host)
+ for idx in range(self.RETRY_COUNT):
+ self.connected = self._connect()
+ if self.connected:
+ return True
+ LOG.debug("Connection attempt %d: Unable to connect to %s, " \
+ "retrying in %d seconds",
+ idx, self.host, self.RETRY_SECONDS)
+ time.sleep(self.RETRY_SECONDS)
+
+ LOG.error("Unable to connect to pktgen instance on %s !",
+ self.host)
+ return False
+
+
+ def send_command(self, command):
+ if not self.connected:
+ LOG.error("Pktgen socket is not connected")
+ return False
+
+ try:
+ self._sock.sendall((command + "\n").encode())
+ time.sleep(1)
+ except (socket.timeout, socket.error):
+ LOG.error("Error sending command '%s'", command)
+ return False
+
+ return True
+
+
+class VcmtsPktgenSetupEnvHelper(sample_vnf.SetupEnvHelper):
+
+ BASE_PARAMETERS = "export LUA_PATH=/vcmts/Pktgen.lua;"\
+ + "export CMK_PROC_FS=/host/proc;"
+
+ PORTS_COUNT = 8
+
+ def generate_pcap_filename(self, port_cfg):
+ return port_cfg['traffic_type'] + "_" + port_cfg['num_subs'] \
+ + "cms_" + port_cfg['num_ofdm'] + "ofdm.pcap"
+
+ def find_port_cfg(self, ports_cfg, port_name):
+ for port_cfg in ports_cfg:
+ if port_name in port_cfg:
+ return port_cfg
+ return None
+
+ def build_pktgen_parameters(self, pod_cfg):
+ ports_cfg = pod_cfg['ports']
+ port_cfg = list()
+
+ for i in range(self.PORTS_COUNT):
+ port_cfg.append(self.find_port_cfg(ports_cfg, 'port_' + str(i)))
+
+ pktgen_parameters = self.BASE_PARAMETERS + " " \
+ + " /pktgen-config/setup.sh " + pod_cfg['pktgen_id'] \
+ + " " + pod_cfg['num_ports']
+
+ for i in range(self.PORTS_COUNT):
+ pktgen_parameters += " " + port_cfg[i]['net_pktgen']
+
+ for i in range(self.PORTS_COUNT):
+ pktgen_parameters += " " + self.generate_pcap_filename(port_cfg[i])
+
+ return pktgen_parameters
+
+ def start_pktgen(self, pod_cfg):
+ self.ssh_helper.drop_connection()
+ cmd = self.build_pktgen_parameters(pod_cfg)
+ LOG.debug("Executing: '%s'", cmd)
+ self.ssh_helper.send_command(cmd)
+ LOG.info("Pktgen executed")
+
+ def setup_vnf_environment(self):
+ pass
+
+
+class VcmtsPktgen(sample_vnf.SampleVNFTrafficGen):
+
+ TG_NAME = 'VcmtsPktgen'
+ APP_NAME = 'VcmtsPktgen'
+ RUN_WAIT = 4
+ DEFAULT_RATE = 8.0
+
+ PKTGEN_BASE_PORT = 23000
+
+ def __init__(self, name, vnfd, setup_env_helper_type=None,
+ resource_helper_type=None):
+ if setup_env_helper_type is None:
+ setup_env_helper_type = VcmtsPktgenSetupEnvHelper
+ super(VcmtsPktgen, self).__init__(
+ name, vnfd, setup_env_helper_type, resource_helper_type)
+
+ self.pktgen_address = vnfd['mgmt-interface']['ip']
+ LOG.info("Pktgen container '%s', IP: %s", name, self.pktgen_address)
+
+ def extract_pod_cfg(self, pktgen_pods_cfg, pktgen_id):
+ for pod_cfg in pktgen_pods_cfg:
+ if pod_cfg['pktgen_id'] == pktgen_id:
+ return pod_cfg
+ return None
+
+ def instantiate(self, scenario_cfg, context_cfg):
+ super(VcmtsPktgen, self).instantiate(scenario_cfg, context_cfg)
+ self._start_server()
+ options = scenario_cfg.get('options', {})
+ self.pktgen_rate = options.get('pktgen_rate', self.DEFAULT_RATE)
+
+ try:
+ pktgen_values_filepath = options['pktgen_values']
+ except KeyError:
+ raise KeyError("Missing pktgen_values key in scenario options" \
+ "section of the task definition file")
+
+ if not os.path.isfile(pktgen_values_filepath):
+ raise RuntimeError("The pktgen_values file path provided " \
+ "does not exists")
+
+ # The yaml_loader.py (SafeLoader) underlying regex has an issue
+ # with reading PCI addresses (processed as double). so the
+ # BaseLoader is used here.
+ with open(pktgen_values_filepath) as stream:
+ pktgen_values = yaml.load(stream, Loader=yaml.BaseLoader)
+
+ if pktgen_values == None:
+ raise RuntimeError("Error reading pktgen_values file provided (" +
+ pktgen_values_filepath + ")")
+
+ self.pktgen_id = int(options[self.name]['pktgen_id'])
+ self.resource_helper.pktgen_id = self.pktgen_id
+
+ self.pktgen_helper = PktgenHelper(self.pktgen_address,
+ self.PKTGEN_BASE_PORT + self.pktgen_id)
+
+ pktgen_pods_cfg = pktgen_values['topology']['pktgen_pods']
+
+ self.pod_cfg = self.extract_pod_cfg(pktgen_pods_cfg,
+ str(self.pktgen_id))
+
+ if self.pod_cfg == None:
+ raise KeyError("Pktgen with id " + str(self.pktgen_id) + \
+ " was not found")
+
+ self.setup_helper.start_pktgen(self.pod_cfg)
+
+ def run_traffic(self, traffic_profile):
+ if not self.pktgen_helper.connect():
+ raise exceptions.PktgenActionError(command="connect")
+ LOG.info("Connected to pktgen instance at %s", self.pktgen_address)
+
+ commands = []
+ for i in range(self.setup_helper.PORTS_COUNT):
+ commands.append('pktgen.set("' + str(i) + '", "rate", ' +
+ "%0.1f" % self.pktgen_rate + ');')
+
+ commands.append('pktgen.start("all");')
+
+ for command in commands:
+ if self.pktgen_helper.send_command(command):
+ LOG.debug("Command '%s' sent to pktgen", command)
+ LOG.info("Traffic started on %s...", self.name)
+ return True
diff --git a/yardstick/network_services/vnf_generic/vnf/udp_replay.py b/yardstick/network_services/vnf_generic/vnf/udp_replay.py
index 3f9994486..a3b0b9fd9 100644
--- a/yardstick/network_services/vnf_generic/vnf/udp_replay.py
+++ b/yardstick/network_services/vnf_generic/vnf/udp_replay.py
@@ -109,7 +109,7 @@ class UdpReplayApproxVnf(SampleVNF):
def collect_kpi(self):
def get_sum(offset):
- return sum(int(i) for i in split_stats[offset::5])
+ return sum(int(i) for i in split_stats[offset::6])
# we can't get KPIs if the VNF is down
check_if_process_failed(self._vnf_process)
@@ -117,7 +117,7 @@ class UdpReplayApproxVnf(SampleVNF):
stats = self.get_stats()
stats_words = stats.split()
- split_stats = stats_words[stats_words.index('0'):][:number_of_ports * 5]
+ split_stats = stats_words[stats_words.index('arp_pkts') + 1:][:number_of_ports * 6]
physical_node = ctx_base.Context.get_physical_node_from_server(
self.scenario_helper.nodes[self.name])
diff --git a/yardstick/network_services/vnf_generic/vnf/vcmts_vnf.py b/yardstick/network_services/vnf_generic/vnf/vcmts_vnf.py
new file mode 100755
index 000000000..0b48ef4e9
--- /dev/null
+++ b/yardstick/network_services/vnf_generic/vnf/vcmts_vnf.py
@@ -0,0 +1,273 @@
+# Copyright (c) 2019 Viosoft 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.
+
+import logging
+import os
+import yaml
+
+from influxdb import InfluxDBClient
+
+from yardstick.network_services.vnf_generic.vnf.sample_vnf import SetupEnvHelper
+from yardstick.common import constants
+from yardstick.common import exceptions
+from yardstick.network_services.vnf_generic.vnf.base import GenericVNF
+from yardstick.network_services.vnf_generic.vnf.sample_vnf import ScenarioHelper
+from yardstick.network_services.vnf_generic.vnf.vnf_ssh_helper import VnfSshHelper
+from yardstick.network_services.utils import get_nsb_option
+
+
+LOG = logging.getLogger(__name__)
+
+
+class InfluxDBHelper(object):
+
+ INITIAL_VALUE = 'now() - 1m'
+
+ def __init__(self, vcmts_influxdb_ip, vcmts_influxdb_port):
+ self._vcmts_influxdb_ip = vcmts_influxdb_ip
+ self._vcmts_influxdb_port = vcmts_influxdb_port
+ self._last_upstream_rx = self.INITIAL_VALUE
+ self._last_values_time = dict()
+
+ def start(self):
+ self._read_client = InfluxDBClient(host=self._vcmts_influxdb_ip,
+ port=self._vcmts_influxdb_port,
+ database='collectd')
+ self._write_client = InfluxDBClient(host=constants.INFLUXDB_IP,
+ port=constants.INFLUXDB_PORT,
+ database='collectd')
+
+ def _get_last_value_time(self, measurement):
+ if measurement in self._last_values_time:
+ return self._last_values_time[measurement]
+ return self.INITIAL_VALUE
+
+ def _set_last_value_time(self, measurement, time):
+ self._last_values_time[measurement] = "'" + time + "'"
+
+ def _query_measurement(self, measurement):
+ # There is a delay before influxdb flushes the data
+ query = "SELECT * FROM " + measurement + " WHERE time > " \
+ + self._get_last_value_time(measurement) \
+ + " ORDER BY time ASC;"
+ query_result = self._read_client.query(query)
+ if len(query_result.keys()) == 0:
+ return None
+ return query_result.get_points(measurement)
+
+ def _rw_measurment(self, measurement, columns):
+ query_result = self._query_measurement(measurement)
+ if query_result == None:
+ return
+
+ points_to_write = list()
+ for entry in query_result:
+ point = {
+ "measurement": measurement,
+ "tags": {
+ "type": entry['type'],
+ "host": entry['host']
+ },
+ "time": entry['time'],
+ "fields": {}
+ }
+
+ for column in columns:
+ if column == 'value':
+ point["fields"][column] = float(entry[column])
+ else:
+ point["fields"][column] = entry[column]
+
+ points_to_write.append(point)
+ self._set_last_value_time(measurement, entry['time'])
+
+ # Write the points to yardstick database
+ if self._write_client.write_points(points_to_write):
+ LOG.debug("%d new points written to '%s' measurement",
+ len(points_to_write), measurement)
+
+ def copy_kpi(self):
+ self._rw_measurment("cpu_value", ["instance", "type_instance", "value"])
+ self._rw_measurment("cpufreq_value", ["type_instance", "value"])
+ self._rw_measurment("downstream_rx", ["value"])
+ self._rw_measurment("downstream_tx", ["value"])
+ self._rw_measurment("downstream_value", ["value"])
+ self._rw_measurment("ds_per_cm_value", ["instance", "value"])
+ self._rw_measurment("intel_rdt_value", ["instance", "type_instance", "value"])
+ self._rw_measurment("turbostat_value", ["instance", "type_instance", "value"])
+ self._rw_measurment("upstream_rx", ["value"])
+ self._rw_measurment("upstream_tx", ["value"])
+ self._rw_measurment("upstream_value", ["value"])
+
+
+class VcmtsdSetupEnvHelper(SetupEnvHelper):
+
+ BASE_PARAMETERS = "export LD_LIBRARY_PATH=/opt/collectd/lib:;"\
+ + "export CMK_PROC_FS=/host/proc;"
+
+ def build_us_parameters(self, pod_cfg):
+ return self.BASE_PARAMETERS + " " \
+ + " /opt/bin/cmk isolate --conf-dir=/etc/cmk" \
+ + " --socket-id=" + pod_cfg['cpu_socket_id'] \
+ + " --pool=shared" \
+ + " /vcmts-config/run_upstream.sh " + pod_cfg['sg_id'] \
+ + " " + pod_cfg['ds_core_type'] \
+ + " " + pod_cfg['num_ofdm'] + "ofdm" \
+ + " " + pod_cfg['num_subs'] + "cm" \
+ + " " + pod_cfg['cm_crypto'] \
+ + " " + pod_cfg['qat'] \
+ + " " + pod_cfg['net_us'] \
+ + " " + pod_cfg['power_mgmt']
+
+ def build_ds_parameters(self, pod_cfg):
+ return self.BASE_PARAMETERS + " " \
+ + " /opt/bin/cmk isolate --conf-dir=/etc/cmk" \
+ + " --socket-id=" + pod_cfg['cpu_socket_id'] \
+ + " --pool=" + pod_cfg['ds_core_type'] \
+ + " /vcmts-config/run_downstream.sh " + pod_cfg['sg_id'] \
+ + " " + pod_cfg['ds_core_type'] \
+ + " " + pod_cfg['ds_core_pool_index'] \
+ + " " + pod_cfg['num_ofdm'] + "ofdm" \
+ + " " + pod_cfg['num_subs'] + "cm" \
+ + " " + pod_cfg['cm_crypto'] \
+ + " " + pod_cfg['qat'] \
+ + " " + pod_cfg['net_ds'] \
+ + " " + pod_cfg['power_mgmt']
+
+ def build_cmd(self, stream_dir, pod_cfg):
+ if stream_dir == 'ds':
+ return self.build_ds_parameters(pod_cfg)
+ else:
+ return self.build_us_parameters(pod_cfg)
+
+ def run_vcmtsd(self, stream_dir, pod_cfg):
+ cmd = self.build_cmd(stream_dir, pod_cfg)
+ LOG.debug("Executing %s", cmd)
+ self.ssh_helper.send_command(cmd)
+
+ def setup_vnf_environment(self):
+ pass
+
+
+class VcmtsVNF(GenericVNF):
+
+ RUN_WAIT = 4
+
+ def __init__(self, name, vnfd):
+ super(VcmtsVNF, self).__init__(name, vnfd)
+ self.name = name
+ self.bin_path = get_nsb_option('bin_path', '')
+ self.scenario_helper = ScenarioHelper(self.name)
+ self.ssh_helper = VnfSshHelper(self.vnfd_helper.mgmt_interface, self.bin_path)
+
+ self.setup_helper = VcmtsdSetupEnvHelper(self.vnfd_helper,
+ self.ssh_helper,
+ self.scenario_helper)
+
+ def extract_pod_cfg(self, vcmts_pods_cfg, sg_id):
+ for pod_cfg in vcmts_pods_cfg:
+ if pod_cfg['sg_id'] == sg_id:
+ return pod_cfg
+
+ def instantiate(self, scenario_cfg, context_cfg):
+ self._update_collectd_options(scenario_cfg, context_cfg)
+ self.scenario_helper.scenario_cfg = scenario_cfg
+ self.context_cfg = context_cfg
+
+ options = scenario_cfg.get('options', {})
+
+ try:
+ self.vcmts_influxdb_ip = options['vcmts_influxdb_ip']
+ self.vcmts_influxdb_port = options['vcmts_influxdb_port']
+ except KeyError:
+ raise KeyError("Missing destination InfluxDB details in scenario" \
+ " section of the task definition file")
+
+ try:
+ vcmtsd_values_filepath = options['vcmtsd_values']
+ except KeyError:
+ raise KeyError("Missing vcmtsd_values key in scenario options" \
+ "section of the task definition file")
+
+ if not os.path.isfile(vcmtsd_values_filepath):
+ raise RuntimeError("The vcmtsd_values file path provided " \
+ "does not exists")
+
+ # The yaml_loader.py (SafeLoader) underlying regex has an issue
+ # with reading PCI addresses (processed as double). so the
+ # BaseLoader is used here.
+ with open(vcmtsd_values_filepath) as stream:
+ vcmtsd_values = yaml.load(stream, Loader=yaml.BaseLoader)
+
+ if vcmtsd_values == None:
+ raise RuntimeError("Error reading vcmtsd_values file provided (" +
+ vcmtsd_values_filepath + ")")
+
+ vnf_options = options.get(self.name, {})
+ sg_id = str(vnf_options['sg_id'])
+ stream_dir = vnf_options['stream_dir']
+
+ try:
+ vcmts_pods_cfg = vcmtsd_values['topology']['vcmts_pods']
+ except KeyError:
+ raise KeyError("Missing vcmts_pods key in the " \
+ "vcmtsd_values file provided")
+
+ pod_cfg = self.extract_pod_cfg(vcmts_pods_cfg, sg_id)
+ if pod_cfg == None:
+ raise exceptions.IncorrectConfig(error_msg="Service group " + sg_id + " not found")
+
+ self.setup_helper.run_vcmtsd(stream_dir, pod_cfg)
+
+ def _update_collectd_options(self, scenario_cfg, context_cfg):
+ scenario_options = scenario_cfg.get('options', {})
+ generic_options = scenario_options.get('collectd', {})
+ scenario_node_options = scenario_options.get(self.name, {})\
+ .get('collectd', {})
+ context_node_options = context_cfg.get('nodes', {})\
+ .get(self.name, {}).get('collectd', {})
+
+ options = generic_options
+ self._update_options(options, scenario_node_options)
+ self._update_options(options, context_node_options)
+
+ self.setup_helper.collectd_options = options
+
+ def _update_options(self, options, additional_options):
+ for k, v in additional_options.items():
+ if isinstance(v, dict) and k in options:
+ options[k].update(v)
+ else:
+ options[k] = v
+
+ def wait_for_instantiate(self):
+ pass
+
+ def terminate(self):
+ pass
+
+ def scale(self, flavor=""):
+ pass
+
+ def collect_kpi(self):
+ self.influxdb_helper.copy_kpi()
+ return {"n/a": "n/a"}
+
+ def start_collect(self):
+ self.influxdb_helper = InfluxDBHelper(self.vcmts_influxdb_ip,
+ self.vcmts_influxdb_port)
+ self.influxdb_helper.start()
+
+ def stop_collect(self):
+ pass
diff --git a/yardstick/network_services/vnf_generic/vnf/vims_vnf.py b/yardstick/network_services/vnf_generic/vnf/vims_vnf.py
new file mode 100644
index 000000000..0e339b171
--- /dev/null
+++ b/yardstick/network_services/vnf_generic/vnf/vims_vnf.py
@@ -0,0 +1,105 @@
+# Copyright (c) 2019 Viosoft 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.
+
+import logging
+import time
+
+from yardstick.network_services.vnf_generic.vnf import sample_vnf
+
+LOG = logging.getLogger(__name__)
+
+
+class VimsSetupEnvHelper(sample_vnf.SetupEnvHelper):
+
+ def setup_vnf_environment(self):
+ LOG.debug('VimsSetupEnvHelper:\n')
+
+
+class VimsResourceHelper(sample_vnf.ClientResourceHelper):
+ pass
+
+
+class VimsPcscfVnf(sample_vnf.SampleVNF):
+
+ APP_NAME = "VimsPcscf"
+ APP_WORD = "VimsPcscf"
+
+ def __init__(self, name, vnfd, setup_env_helper_type=None,
+ resource_helper_type=None):
+ if resource_helper_type is None:
+ resource_helper_type = VimsResourceHelper
+ if setup_env_helper_type is None:
+ setup_env_helper_type = VimsSetupEnvHelper
+ super(VimsPcscfVnf, self).__init__(name, vnfd, setup_env_helper_type,
+ resource_helper_type)
+
+ def wait_for_instantiate(self):
+ pass
+
+ def _run(self):
+ pass
+
+ def start_collect(self):
+ # TODO
+ pass
+
+ def collect_kpi(self):
+ # TODO
+ pass
+
+
+class VimsHssVnf(sample_vnf.SampleVNF):
+
+ APP_NAME = "VimsHss"
+ APP_WORD = "VimsHss"
+ CMD = "sudo /media/generate_user.sh {} {} >> /dev/null 2>&1"
+
+ def __init__(self, name, vnfd, setup_env_helper_type=None,
+ resource_helper_type=None):
+ if resource_helper_type is None:
+ resource_helper_type = VimsResourceHelper
+ if setup_env_helper_type is None:
+ setup_env_helper_type = VimsSetupEnvHelper
+ super(VimsHssVnf, self).__init__(name, vnfd, setup_env_helper_type,
+ resource_helper_type)
+ self.start_user = 1
+ self.end_user = 10000
+ self.WAIT_TIME = 600
+
+ def instantiate(self, scenario_cfg, context_cfg):
+ LOG.debug("scenario_cfg=%s\n", scenario_cfg)
+ self.start_user = scenario_cfg.get("options", {}).get("start_user", self.start_user)
+ self.end_user = scenario_cfg.get("options", {}).get("end_user", self.end_user)
+ # TODO
+ # Need to check HSS services are ready before generating user accounts
+ # Now, adding time sleep that manually configured by user
+ # to wait for HSS services.
+ # Note: for heat, waiting time is too long (~ 600s)
+ self.WAIT_TIME = scenario_cfg.get("options", {}).get("wait_time", self.WAIT_TIME)
+ time.sleep(self.WAIT_TIME)
+ LOG.debug("Generate user accounts from %d to %d\n",
+ self.start_user, self.end_user)
+ cmd = self.CMD.format(self.start_user, self.end_user)
+ self.ssh_helper.execute(cmd, None, 3600, False)
+
+ def wait_for_instantiate(self):
+ pass
+
+ def start_collect(self):
+ # TODO
+ pass
+
+ def collect_kpi(self):
+ # TODO
+ pass
diff --git a/yardstick/network_services/vnf_generic/vnf/vpp_helpers.py b/yardstick/network_services/vnf_generic/vnf/vpp_helpers.py
new file mode 100644
index 000000000..fe8e7b2ba
--- /dev/null
+++ b/yardstick/network_services/vnf_generic/vnf/vpp_helpers.py
@@ -0,0 +1,751 @@
+# Copyright (c) 2019 Viosoft 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.
+
+import binascii
+import ipaddress
+import json
+import logging
+import os
+import re
+import tempfile
+import time
+from collections import OrderedDict
+
+from yardstick.common import constants
+from yardstick.common import exceptions
+from yardstick.network_services.helpers.cpu import CpuSysCores
+from yardstick.network_services.vnf_generic.vnf.sample_vnf import \
+ DpdkVnfSetupEnvHelper
+
+LOG = logging.getLogger(__name__)
+
+
+class VppConfigGenerator(object):
+ VPP_LOG_FILE = '/tmp/vpe.log'
+
+ def __init__(self):
+ self._nodeconfig = {}
+ self._vpp_config = ''
+
+ def add_config_item(self, config, value, path):
+ if len(path) == 1:
+ config[path[0]] = value
+ return
+ if path[0] not in config:
+ config[path[0]] = {}
+ elif isinstance(config[path[0]], str):
+ config[path[0]] = {} if config[path[0]] == '' \
+ else {config[path[0]]: ''}
+ self.add_config_item(config[path[0]], value, path[1:])
+
+ def add_unix_log(self, value=None):
+ path = ['unix', 'log']
+ if value is None:
+ value = self.VPP_LOG_FILE
+ self.add_config_item(self._nodeconfig, value, path)
+
+ def add_unix_cli_listen(self, value='/run/vpp/cli.sock'):
+ path = ['unix', 'cli-listen']
+ self.add_config_item(self._nodeconfig, value, path)
+
+ def add_unix_nodaemon(self):
+ path = ['unix', 'nodaemon']
+ self.add_config_item(self._nodeconfig, '', path)
+
+ def add_unix_coredump(self):
+ path = ['unix', 'full-coredump']
+ self.add_config_item(self._nodeconfig, '', path)
+
+ def add_dpdk_dev(self, *devices):
+ for device in devices:
+ if VppConfigGenerator.pci_dev_check(device):
+ path = ['dpdk', 'dev {0}'.format(device)]
+ self.add_config_item(self._nodeconfig, '', path)
+
+ def add_dpdk_cryptodev(self, count, cryptodev):
+ for i in range(count):
+ cryptodev_config = 'dev {0}'.format(
+ re.sub(r'\d.\d$', '1.' + str(i), cryptodev))
+ path = ['dpdk', cryptodev_config]
+ self.add_config_item(self._nodeconfig, '', path)
+ self.add_dpdk_uio_driver('igb_uio')
+
+ def add_dpdk_sw_cryptodev(self, sw_pmd_type, socket_id, count):
+ for _ in range(count):
+ cryptodev_config = 'vdev cryptodev_{0}_pmd,socket_id={1}'. \
+ format(sw_pmd_type, str(socket_id))
+ path = ['dpdk', cryptodev_config]
+ self.add_config_item(self._nodeconfig, '', path)
+
+ def add_dpdk_dev_default_rxq(self, value):
+ path = ['dpdk', 'dev default', 'num-rx-queues']
+ self.add_config_item(self._nodeconfig, value, path)
+
+ def add_dpdk_dev_default_rxd(self, value):
+ path = ['dpdk', 'dev default', 'num-rx-desc']
+ self.add_config_item(self._nodeconfig, value, path)
+
+ def add_dpdk_dev_default_txd(self, value):
+ path = ['dpdk', 'dev default', 'num-tx-desc']
+ self.add_config_item(self._nodeconfig, value, path)
+
+ def add_dpdk_log_level(self, value):
+ path = ['dpdk', 'log-level']
+ self.add_config_item(self._nodeconfig, value, path)
+
+ def add_dpdk_socketmem(self, value):
+ path = ['dpdk', 'socket-mem']
+ self.add_config_item(self._nodeconfig, value, path)
+
+ def add_dpdk_num_mbufs(self, value):
+ path = ['dpdk', 'num-mbufs']
+ self.add_config_item(self._nodeconfig, value, path)
+
+ def add_dpdk_uio_driver(self, value=None):
+ path = ['dpdk', 'uio-driver']
+ self.add_config_item(self._nodeconfig, value, path)
+
+ def add_cpu_main_core(self, value):
+ path = ['cpu', 'main-core']
+ self.add_config_item(self._nodeconfig, value, path)
+
+ def add_cpu_corelist_workers(self, value):
+ path = ['cpu', 'corelist-workers']
+ self.add_config_item(self._nodeconfig, value, path)
+
+ def add_heapsize(self, value):
+ path = ['heapsize']
+ self.add_config_item(self._nodeconfig, value, path)
+
+ def add_ip6_hash_buckets(self, value):
+ path = ['ip6', 'hash-buckets']
+ self.add_config_item(self._nodeconfig, value, path)
+
+ def add_ip6_heap_size(self, value):
+ path = ['ip6', 'heap-size']
+ self.add_config_item(self._nodeconfig, value, path)
+
+ def add_ip_heap_size(self, value):
+ path = ['ip', 'heap-size']
+ self.add_config_item(self._nodeconfig, value, path)
+
+ def add_statseg_size(self, value):
+ path = ['statseg', 'size']
+ self.add_config_item(self._nodeconfig, value, path)
+
+ def add_plugin(self, state, *plugins):
+ for plugin in plugins:
+ path = ['plugins', 'plugin {0}'.format(plugin), state]
+ self.add_config_item(self._nodeconfig, ' ', path)
+
+ def add_dpdk_no_multi_seg(self):
+ path = ['dpdk', 'no-multi-seg']
+ self.add_config_item(self._nodeconfig, '', path)
+
+ def add_dpdk_no_tx_checksum_offload(self):
+ path = ['dpdk', 'no-tx-checksum-offload']
+ self.add_config_item(self._nodeconfig, '', path)
+
+ def dump_config(self, obj=None, level=-1):
+ if obj is None:
+ obj = self._nodeconfig
+ obj = OrderedDict(sorted(obj.items()))
+
+ indent = ' '
+ if level >= 0:
+ self._vpp_config += '{}{{\n'.format(level * indent)
+ if isinstance(obj, dict):
+ for key, val in obj.items():
+ if hasattr(val, '__iter__') and not isinstance(val, str):
+ self._vpp_config += '{}{}\n'.format((level + 1) * indent,
+ key)
+ self.dump_config(val, level + 1)
+ else:
+ self._vpp_config += '{}{} {}\n'.format(
+ (level + 1) * indent,
+ key, val)
+ if level >= 0:
+ self._vpp_config += '{}}}\n'.format(level * indent)
+
+ return self._vpp_config
+
+ @staticmethod
+ def pci_dev_check(pci_dev):
+ pattern = re.compile("^[0-9A-Fa-f]{4}:[0-9A-Fa-f]{2}:"
+ "[0-9A-Fa-f]{2}\\.[0-9A-Fa-f]$")
+ if not pattern.match(pci_dev):
+ raise ValueError('PCI address {addr} is not in valid format '
+ 'xxxx:xx:xx.x'.format(addr=pci_dev))
+ return True
+
+
+class VppSetupEnvHelper(DpdkVnfSetupEnvHelper):
+ APP_NAME = "vpp"
+ CFG_CONFIG = "/etc/vpp/startup.conf"
+ CFG_SCRIPT = ""
+ PIPELINE_COMMAND = ""
+ QAT_DRIVER = "qat_dh895xcc"
+ VNF_TYPE = "IPSEC"
+ VAT_BIN_NAME = 'vpp_api_test'
+
+ def __init__(self, vnfd_helper, ssh_helper, scenario_helper):
+ super(VppSetupEnvHelper, self).__init__(vnfd_helper, ssh_helper,
+ scenario_helper)
+ self.sys_cores = CpuSysCores(self.ssh_helper)
+
+ def kill_vnf(self):
+ ret_code, _, _ = \
+ self.ssh_helper.execute(
+ 'service {name} stop'.format(name=self.APP_NAME))
+ if int(ret_code):
+ raise RuntimeError(
+ 'Failed to stop service {name}'.format(name=self.APP_NAME))
+
+ def tear_down(self):
+ pass
+
+ def start_vpp_service(self):
+ ret_code, _, _ = \
+ self.ssh_helper.execute(
+ 'service {name} restart'.format(name=self.APP_NAME))
+ if int(ret_code):
+ raise RuntimeError(
+ 'Failed to start service {name}'.format(name=self.APP_NAME))
+
+ def _update_vnfd_helper(self, additional_data, iface_key=None):
+ for k, v in additional_data.items():
+ if iface_key is None:
+ if isinstance(v, dict) and k in self.vnfd_helper:
+ self.vnfd_helper[k].update(v)
+ else:
+ self.vnfd_helper[k] = v
+ else:
+ if isinstance(v,
+ dict) and k in self.vnfd_helper.find_virtual_interface(
+ ifname=iface_key):
+ self.vnfd_helper.find_virtual_interface(ifname=iface_key)[
+ k].update(v)
+ else:
+ self.vnfd_helper.find_virtual_interface(ifname=iface_key)[
+ k] = v
+
+ def get_value_by_interface_key(self, interface, key):
+ try:
+ return self.vnfd_helper.find_virtual_interface(
+ ifname=interface).get(key)
+ except (KeyError, ValueError):
+ return None
+
+ def crypto_device_init(self, pci_addr, numvfs):
+ # QAT device must be re-bound to kernel driver before initialization.
+ self.dpdk_bind_helper.load_dpdk_driver(self.QAT_DRIVER)
+
+ # Stop VPP to prevent deadlock.
+ self.kill_vnf()
+
+ current_driver = self.get_pci_dev_driver(pci_addr.replace(':', r'\:'))
+ if current_driver is not None:
+ self.pci_driver_unbind(pci_addr)
+
+ # Bind to kernel driver.
+ self.dpdk_bind_helper.bind(pci_addr, self.QAT_DRIVER.replace('qat_', ''))
+
+ # Initialize QAT VFs.
+ if numvfs > 0:
+ self.set_sriov_numvfs(pci_addr, numvfs)
+
+ def get_sriov_numvfs(self, pf_pci_addr):
+ command = 'cat /sys/bus/pci/devices/{pci}/sriov_numvfs'. \
+ format(pci=pf_pci_addr.replace(':', r'\:'))
+ _, stdout, _ = self.ssh_helper.execute(command)
+ try:
+ return int(stdout)
+ except ValueError:
+ LOG.debug('Reading sriov_numvfs info failed')
+ return 0
+
+ def set_sriov_numvfs(self, pf_pci_addr, numvfs=0):
+ command = "sh -c 'echo {num} | tee /sys/bus/pci/devices/{pci}/sriov_numvfs'". \
+ format(num=numvfs, pci=pf_pci_addr.replace(':', r'\:'))
+ self.ssh_helper.execute(command)
+
+ def pci_driver_unbind(self, pci_addr):
+ command = "sh -c 'echo {pci} | tee /sys/bus/pci/devices/{pcie}/driver/unbind'". \
+ format(pci=pci_addr, pcie=pci_addr.replace(':', r'\:'))
+ self.ssh_helper.execute(command)
+
+ def get_pci_dev_driver(self, pci_addr):
+ cmd = 'lspci -vmmks {0}'.format(pci_addr)
+ ret_code, stdout, _ = self.ssh_helper.execute(cmd)
+ if int(ret_code):
+ raise RuntimeError("'{0}' failed".format(cmd))
+ for line in stdout.splitlines():
+ if not line:
+ continue
+ name = None
+ value = None
+ try:
+ name, value = line.split("\t", 1)
+ except ValueError:
+ if name == "Driver:":
+ return None
+ if name == 'Driver:':
+ return value
+ return None
+
+ def vpp_create_ipsec_tunnels(self, if1_ip_addr, if2_ip_addr, if_name,
+ n_tunnels, n_connections, crypto_alg,
+ crypto_key, integ_alg, integ_key, addrs_ip,
+ spi_1=10000, spi_2=20000):
+ mask_length = 32
+ if n_connections <= n_tunnels:
+ count = 1
+ else:
+ count = int(n_connections / n_tunnels)
+ addr_ip_i = int(ipaddress.ip_address(str(addrs_ip)))
+ dst_start_ip = addr_ip_i
+
+ tmp_fd, tmp_path = tempfile.mkstemp()
+
+ vpp_ifname = self.get_value_by_interface_key(if_name, 'vpp_name')
+ ckey = binascii.hexlify(crypto_key.encode())
+ ikey = binascii.hexlify(integ_key.encode())
+
+ integ = ''
+ if crypto_alg.alg_name != 'aes-gcm-128':
+ integ = 'integ_alg {integ_alg} ' \
+ 'local_integ_key {local_integ_key} ' \
+ 'remote_integ_key {remote_integ_key} ' \
+ .format(integ_alg=integ_alg.alg_name,
+ local_integ_key=ikey,
+ remote_integ_key=ikey)
+ create_tunnels_cmds = 'ipsec_tunnel_if_add_del ' \
+ 'local_spi {local_spi} ' \
+ 'remote_spi {remote_spi} ' \
+ 'crypto_alg {crypto_alg} ' \
+ 'local_crypto_key {local_crypto_key} ' \
+ 'remote_crypto_key {remote_crypto_key} ' \
+ '{integ} ' \
+ 'local_ip {local_ip} ' \
+ 'remote_ip {remote_ip}\n'
+ start_tunnels_cmds = 'ip_add_del_route {raddr}/{mask} via {addr} ipsec{i}\n' \
+ 'exec set interface unnumbered ipsec{i} use {uifc}\n' \
+ 'sw_interface_set_flags ipsec{i} admin-up\n'
+
+ with os.fdopen(tmp_fd, 'w') as tmp_file:
+ for i in range(0, n_tunnels):
+ create_tunnel = create_tunnels_cmds.format(local_spi=spi_1 + i,
+ remote_spi=spi_2 + i,
+ crypto_alg=crypto_alg.alg_name,
+ local_crypto_key=ckey,
+ remote_crypto_key=ckey,
+ integ=integ,
+ local_ip=if1_ip_addr,
+ remote_ip=if2_ip_addr)
+ tmp_file.write(create_tunnel)
+ self.execute_script(tmp_path, json_out=False, copy_on_execute=True)
+ os.remove(tmp_path)
+
+ tmp_fd, tmp_path = tempfile.mkstemp()
+
+ with os.fdopen(tmp_fd, 'w') as tmp_file:
+ for i in range(0, n_tunnels):
+ if count > 1:
+ dst_start_ip = addr_ip_i + i * count
+ dst_end_ip = ipaddress.ip_address(dst_start_ip + count - 1)
+ ips = [ipaddress.ip_address(ip) for ip in
+ [str(ipaddress.ip_address(dst_start_ip)),
+ str(dst_end_ip)]]
+ lowest_ip, highest_ip = min(ips), max(ips)
+ mask_length = self.get_prefix_length(int(lowest_ip),
+ int(highest_ip),
+ lowest_ip.max_prefixlen)
+ # TODO check duplicate route for some IPs
+ elif count == 1:
+ dst_start_ip = addr_ip_i + i
+ start_tunnel = start_tunnels_cmds.format(
+ raddr=str(ipaddress.ip_address(dst_start_ip)),
+ mask=mask_length,
+ addr=if2_ip_addr,
+ i=i, count=count,
+ uifc=vpp_ifname)
+ tmp_file.write(start_tunnel)
+ # TODO add route for remain IPs
+
+ self.execute_script(tmp_path, json_out=False, copy_on_execute=True)
+ os.remove(tmp_path)
+
+ def apply_config(self, vpp_cfg, restart_vpp=True):
+ vpp_config = vpp_cfg.dump_config()
+ ret, _, _ = \
+ self.ssh_helper.execute('echo "{config}" | sudo tee {filename}'.
+ format(config=vpp_config,
+ filename=self.CFG_CONFIG))
+ if ret != 0:
+ raise RuntimeError('Writing config file failed')
+ if restart_vpp:
+ self.start_vpp_service()
+
+ def vpp_route_add(self, network, prefix_len, gateway=None, interface=None,
+ use_sw_index=True, resolve_attempts=10,
+ count=1, vrf=None, lookup_vrf=None, multipath=False,
+ weight=None, local=False):
+ if interface:
+ if use_sw_index:
+ int_cmd = ('sw_if_index {}'.format(
+ self.get_value_by_interface_key(interface,
+ 'vpp_sw_index')))
+ else:
+ int_cmd = interface
+ else:
+ int_cmd = ''
+
+ rap = 'resolve-attempts {}'.format(resolve_attempts) \
+ if resolve_attempts else ''
+
+ via = 'via {}'.format(gateway) if gateway else ''
+
+ cnt = 'count {}'.format(count) \
+ if count else ''
+
+ vrf = 'vrf {}'.format(vrf) if vrf else ''
+
+ lookup_vrf = 'lookup-in-vrf {}'.format(
+ lookup_vrf) if lookup_vrf else ''
+
+ multipath = 'multipath' if multipath else ''
+
+ weight = 'weight {}'.format(weight) if weight else ''
+
+ local = 'local' if local else ''
+
+ with VatTerminal(self.ssh_helper, json_param=False) as vat:
+ vat.vat_terminal_exec_cmd_from_template('add_route.vat',
+ network=network,
+ prefix_length=prefix_len,
+ via=via,
+ vrf=vrf,
+ interface=int_cmd,
+ resolve_attempts=rap,
+ count=cnt,
+ lookup_vrf=lookup_vrf,
+ multipath=multipath,
+ weight=weight,
+ local=local)
+
+ def add_arp_on_dut(self, iface_key, ip_address, mac_address):
+ with VatTerminal(self.ssh_helper) as vat:
+ return vat.vat_terminal_exec_cmd_from_template(
+ 'add_ip_neighbor.vat',
+ sw_if_index=self.get_value_by_interface_key(iface_key,
+ 'vpp_sw_index'),
+ ip_address=ip_address, mac_address=mac_address)
+
+ def set_ip(self, interface, address, prefix_length):
+ with VatTerminal(self.ssh_helper) as vat:
+ return vat.vat_terminal_exec_cmd_from_template(
+ 'add_ip_address.vat',
+ sw_if_index=self.get_value_by_interface_key(interface,
+ 'vpp_sw_index'),
+ address=address, prefix_length=prefix_length)
+
+ def set_interface_state(self, interface, state):
+ sw_if_index = self.get_value_by_interface_key(interface,
+ 'vpp_sw_index')
+
+ if state == 'up':
+ state = 'admin-up link-up'
+ elif state == 'down':
+ state = 'admin-down link-down'
+ else:
+ raise ValueError('Unexpected interface state: {}'.format(state))
+ with VatTerminal(self.ssh_helper) as vat:
+ return vat.vat_terminal_exec_cmd_from_template(
+ 'set_if_state.vat', sw_if_index=sw_if_index, state=state)
+
+ def vpp_set_interface_mtu(self, interface, mtu=9200):
+ sw_if_index = self.get_value_by_interface_key(interface,
+ 'vpp_sw_index')
+ if sw_if_index:
+ with VatTerminal(self.ssh_helper, json_param=False) as vat:
+ vat.vat_terminal_exec_cmd_from_template(
+ "hw_interface_set_mtu.vat", sw_if_index=sw_if_index,
+ mtu=mtu)
+
+ def vpp_interfaces_ready_wait(self, timeout=30):
+ if_ready = False
+ not_ready = []
+ start = time.time()
+ while not if_ready:
+ out = self.vpp_get_interface_data()
+ if time.time() - start > timeout:
+ for interface in out:
+ if interface.get('admin_up_down') == 1:
+ if interface.get('link_up_down') != 1:
+ LOG.debug('%s link-down',
+ interface.get('interface_name'))
+ raise RuntimeError('timeout, not up {0}'.format(not_ready))
+ not_ready = []
+ for interface in out:
+ if interface.get('admin_up_down') == 1:
+ if interface.get('link_up_down') != 1:
+ not_ready.append(interface.get('interface_name'))
+ if not not_ready:
+ if_ready = True
+ else:
+ LOG.debug('Interfaces still in link-down state: %s, '
+ 'waiting...', not_ready)
+ time.sleep(1)
+
+ def vpp_get_interface_data(self, interface=None):
+ with VatTerminal(self.ssh_helper) as vat:
+ response = vat.vat_terminal_exec_cmd_from_template(
+ "interface_dump.vat")
+ data = response[0]
+ if interface is not None:
+ if isinstance(interface, str):
+ param = "interface_name"
+ elif isinstance(interface, int):
+ param = "sw_if_index"
+ else:
+ raise TypeError
+ for data_if in data:
+ if data_if[param] == interface:
+ return data_if
+ return dict()
+ return data
+
+ def update_vpp_interface_data(self):
+ data = {}
+ interface_dump_json = self.execute_script_json_out(
+ "dump_interfaces.vat")
+ interface_list = json.loads(interface_dump_json)
+ for interface in self.vnfd_helper.interfaces:
+ if_mac = interface['virtual-interface']['local_mac']
+ interface_dict = VppSetupEnvHelper.get_vpp_interface_by_mac(
+ interface_list, if_mac)
+ if not interface_dict:
+ LOG.debug('Interface %s not found by MAC %s', interface,
+ if_mac)
+ continue
+ data[interface['virtual-interface']['ifname']] = {
+ 'vpp_name': interface_dict["interface_name"],
+ 'vpp_sw_index': interface_dict["sw_if_index"]
+ }
+ for iface_key, updated_vnfd in data.items():
+ self._update_vnfd_helper(updated_vnfd, iface_key)
+
+ def iface_update_numa(self):
+ iface_numa = {}
+ for interface in self.vnfd_helper.interfaces:
+ cmd = "cat /sys/bus/pci/devices/{}/numa_node".format(
+ interface["virtual-interface"]["vpci"])
+ ret, out, _ = self.ssh_helper.execute(cmd)
+ if ret == 0:
+ try:
+ numa_node = int(out)
+ if numa_node < 0:
+ if self.vnfd_helper["cpuinfo"][-1][3] + 1 == 1:
+ iface_numa[
+ interface['virtual-interface']['ifname']] = {
+ 'numa_node': 0
+ }
+ else:
+ raise ValueError
+ else:
+ iface_numa[
+ interface['virtual-interface']['ifname']] = {
+ 'numa_node': numa_node
+ }
+ except ValueError:
+ LOG.debug(
+ 'Reading numa location failed for: %s',
+ interface["virtual-interface"]["vpci"])
+ for iface_key, updated_vnfd in iface_numa.items():
+ self._update_vnfd_helper(updated_vnfd, iface_key)
+
+ def execute_script(self, vat_name, json_out=True, copy_on_execute=False):
+ if copy_on_execute:
+ self.ssh_helper.put_file(vat_name, vat_name)
+ remote_file_path = vat_name
+ else:
+ vat_path = self.ssh_helper.join_bin_path("vpp", "templates")
+ remote_file_path = '{0}/{1}'.format(vat_path, vat_name)
+
+ cmd = "{vat_bin} {json} in {vat_path} script".format(
+ vat_bin=self.VAT_BIN_NAME,
+ json="json" if json_out is True else "",
+ vat_path=remote_file_path)
+
+ try:
+ return self.ssh_helper.execute(cmd=cmd)
+ except Exception:
+ raise RuntimeError("VAT script execution failed: {0}".format(cmd))
+
+ def execute_script_json_out(self, vat_name):
+ vat_path = self.ssh_helper.join_bin_path("vpp", "templates")
+ remote_file_path = '{0}/{1}'.format(vat_path, vat_name)
+
+ _, stdout, _ = self.execute_script(vat_name, json_out=True)
+ return self.cleanup_vat_json_output(stdout, vat_file=remote_file_path)
+
+ @staticmethod
+ def cleanup_vat_json_output(json_output, vat_file=None):
+ retval = json_output
+ clutter = ['vat#', 'dump_interface_table error: Misc',
+ 'dump_interface_table:6019: JSON output supported only ' \
+ 'for VPE API calls and dump_stats_table']
+ if vat_file:
+ clutter.append("{0}(2):".format(vat_file))
+ for garbage in clutter:
+ retval = retval.replace(garbage, '')
+ return retval.strip()
+
+ @staticmethod
+ def _convert_mac_to_number_list(mac_address):
+ list_mac = []
+ for num in mac_address.split(":"):
+ list_mac.append(int(num, 16))
+ return list_mac
+
+ @staticmethod
+ def get_vpp_interface_by_mac(interfaces_list, mac_address):
+ interface_dict = {}
+ list_mac_address = VppSetupEnvHelper._convert_mac_to_number_list(
+ mac_address)
+ LOG.debug("MAC address %s converted to list %s.", mac_address,
+ list_mac_address)
+ for interface in interfaces_list:
+ # TODO: create vat json integrity checking and move there
+ if "l2_address" not in interface:
+ raise KeyError(
+ "key l2_address not found in interface dict."
+ "Probably input list is not parsed from correct VAT "
+ "json output.")
+ if "l2_address_length" not in interface:
+ raise KeyError(
+ "key l2_address_length not found in interface "
+ "dict. Probably input list is not parsed from correct "
+ "VAT json output.")
+ mac_from_json = interface["l2_address"][:6]
+ if mac_from_json == list_mac_address:
+ if interface["l2_address_length"] != 6:
+ raise ValueError("l2_address_length value is not 6.")
+ interface_dict = interface
+ break
+ return interface_dict
+
+ @staticmethod
+ def get_prefix_length(number1, number2, bits):
+ for i in range(bits):
+ if number1 >> i == number2 >> i:
+ return bits - i
+ return 0
+
+
+class VatTerminal(object):
+
+ __VAT_PROMPT = ("vat# ",)
+ __LINUX_PROMPT = (":~# ", ":~$ ", "~]$ ", "~]# ")
+
+
+ def __init__(self, ssh_helper, json_param=True):
+ json_text = ' json' if json_param else ''
+ self.json = json_param
+ self.ssh_helper = ssh_helper
+ EXEC_RETRY = 3
+
+ try:
+ self._tty = self.ssh_helper.interactive_terminal_open()
+ except Exception:
+ raise RuntimeError("Cannot open interactive terminal")
+
+ for _ in range(EXEC_RETRY):
+ try:
+ self.ssh_helper.interactive_terminal_exec_command(
+ self._tty,
+ 'sudo -S {0}{1}'.format(VppSetupEnvHelper.VAT_BIN_NAME,
+ json_text),
+ self.__VAT_PROMPT)
+ except exceptions.SSHTimeout:
+ continue
+ else:
+ break
+
+ self._exec_failure = False
+ self.vat_stdout = None
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ self.vat_terminal_close()
+
+ def vat_terminal_exec_cmd(self, cmd):
+ try:
+ out = self.ssh_helper.interactive_terminal_exec_command(self._tty,
+ cmd,
+ self.__VAT_PROMPT)
+ self.vat_stdout = out
+ except exceptions.SSHTimeout:
+ self._exec_failure = True
+ raise RuntimeError(
+ "VPP is not running on node. VAT command {0} execution failed".
+ format(cmd))
+ if self.json:
+ obj_start = out.find('{')
+ obj_end = out.rfind('}')
+ array_start = out.find('[')
+ array_end = out.rfind(']')
+
+ if obj_start == -1 and array_start == -1:
+ raise RuntimeError(
+ "VAT command {0}: no JSON data.".format(cmd))
+
+ if obj_start < array_start or array_start == -1:
+ start = obj_start
+ end = obj_end + 1
+ else:
+ start = array_start
+ end = array_end + 1
+ out = out[start:end]
+ json_out = json.loads(out)
+ return json_out
+ else:
+ return None
+
+ def vat_terminal_close(self):
+ if not self._exec_failure:
+ try:
+ self.ssh_helper.interactive_terminal_exec_command(self._tty,
+ 'quit',
+ self.__LINUX_PROMPT)
+ except exceptions.SSHTimeout:
+ raise RuntimeError("Failed to close VAT console")
+ try:
+ self.ssh_helper.interactive_terminal_close(self._tty)
+ except Exception:
+ raise RuntimeError("Cannot close interactive terminal")
+
+ def vat_terminal_exec_cmd_from_template(self, vat_template_file, **args):
+ file_path = os.path.join(constants.YARDSTICK_ROOT_PATH,
+ 'yardstick/resources/templates/',
+ vat_template_file)
+ with open(file_path, 'r') as template_file:
+ cmd_template = template_file.readlines()
+ ret = []
+ for line_tmpl in cmd_template:
+ vat_cmd = line_tmpl.format(**args)
+ ret.append(self.vat_terminal_exec_cmd(vat_cmd.replace('\n', '')))
+ return ret
diff --git a/yardstick/resources/templates/add_ip_address.vat b/yardstick/resources/templates/add_ip_address.vat
new file mode 100644
index 000000000..d59480c33
--- /dev/null
+++ b/yardstick/resources/templates/add_ip_address.vat
@@ -0,0 +1 @@
+sw_interface_add_del_address sw_if_index {sw_if_index} {address}/{prefix_length}
diff --git a/yardstick/resources/templates/add_ip_neighbor.vat b/yardstick/resources/templates/add_ip_neighbor.vat
new file mode 100644
index 000000000..730e7112a
--- /dev/null
+++ b/yardstick/resources/templates/add_ip_neighbor.vat
@@ -0,0 +1 @@
+ip_neighbor_add_del sw_if_index {sw_if_index} dst {ip_address} mac {mac_address}
diff --git a/yardstick/resources/templates/add_route.vat b/yardstick/resources/templates/add_route.vat
new file mode 100644
index 000000000..64c6a6c3b
--- /dev/null
+++ b/yardstick/resources/templates/add_route.vat
@@ -0,0 +1 @@
+ip_add_del_route {network}/{prefix_length} {via} {vrf} {interface} {resolve_attempts} {count} {lookup_vrf} {multipath} {weight} {local} \ No newline at end of file
diff --git a/yardstick/resources/templates/del_route.vat b/yardstick/resources/templates/del_route.vat
new file mode 100644
index 000000000..e7fe4bc1e
--- /dev/null
+++ b/yardstick/resources/templates/del_route.vat
@@ -0,0 +1 @@
+ip_add_del_route {network}/{prefix_length} via {gateway} sw_if_index {sw_if_index} del \ No newline at end of file
diff --git a/yardstick/resources/templates/flush_ip_addresses.vat b/yardstick/resources/templates/flush_ip_addresses.vat
new file mode 100644
index 000000000..f38fcf12c
--- /dev/null
+++ b/yardstick/resources/templates/flush_ip_addresses.vat
@@ -0,0 +1 @@
+sw_interface_add_del_address sw_if_index {sw_if_index} del-all \ No newline at end of file
diff --git a/yardstick/resources/templates/hw_interface_set_mtu.vat b/yardstick/resources/templates/hw_interface_set_mtu.vat
new file mode 100644
index 000000000..645d1a80c
--- /dev/null
+++ b/yardstick/resources/templates/hw_interface_set_mtu.vat
@@ -0,0 +1 @@
+hw_interface_set_mtu sw_if_index {sw_if_index} mtu {mtu}
diff --git a/yardstick/resources/templates/interface_dump.vat b/yardstick/resources/templates/interface_dump.vat
new file mode 100644
index 000000000..850c348f6
--- /dev/null
+++ b/yardstick/resources/templates/interface_dump.vat
@@ -0,0 +1 @@
+sw_interface_dump
diff --git a/yardstick/resources/templates/set_if_state.vat b/yardstick/resources/templates/set_if_state.vat
new file mode 100644
index 000000000..e2c2d4b29
--- /dev/null
+++ b/yardstick/resources/templates/set_if_state.vat
@@ -0,0 +1 @@
+sw_interface_set_flags sw_if_index {sw_if_index} {state}
diff --git a/yardstick/tests/unit/benchmark/contexts/test_heat.py b/yardstick/tests/unit/benchmark/contexts/test_heat.py
index 97e6878a0..96946cded 100644
--- a/yardstick/tests/unit/benchmark/contexts/test_heat.py
+++ b/yardstick/tests/unit/benchmark/contexts/test_heat.py
@@ -82,6 +82,7 @@ class HeatContextTestCase(unittest.TestCase):
self.assertIsNone(self.test_context.template_file)
self.assertIsNone(self.test_context.heat_parameters)
self.assertIsNone(self.test_context.key_filename)
+ self.assertTrue(self.test_context.yardstick_gen_key_file)
@mock.patch.object(yaml_loader, 'read_yaml_file')
@mock.patch('yardstick.benchmark.contexts.heat.PlacementGroup')
@@ -174,6 +175,23 @@ class HeatContextTestCase(unittest.TestCase):
self.assertTrue(self.test_context._flags.no_setup)
self.assertTrue(self.test_context._flags.no_teardown)
+ def test_init_key_filename(self):
+ attrs = {'name': 'foo',
+ 'file': 'pod.yaml',
+ 'task_id': '1234567890',
+ 'server_groups': {},
+ 'networks': {},
+ 'servers': {},
+ 'heat_template': "/root/clearwater.yaml",
+ 'key_filename': '/etc/yardstick/yardstick.pem'}
+
+ with mock.patch.object(openstack_utils, 'get_shade_client'), \
+ mock.patch.object(openstack_utils, 'get_shade_operator_client'):
+ self.test_context.init(attrs)
+
+ self.assertIsNotNone(self.test_context.key_filename)
+ self.assertFalse(self.test_context.yardstick_gen_key_file)
+
@mock.patch('yardstick.benchmark.contexts.heat.HeatTemplate')
def test__add_resources_to_template_no_servers(self, mock_template):
self.test_context._name = 'ctx'
@@ -374,6 +392,25 @@ class HeatContextTestCase(unittest.TestCase):
self.assertTrue(mock_manager.mock_calls.index(mock_call_gen_keys) <
mock_manager.mock_calls.index(mock_call_add_resources))
+ @mock.patch.object(heat, 'HeatTemplate')
+ @mock.patch.object(ssh.SSH, 'gen_keys')
+ @mock.patch.object(heat.HeatContext, '_create_new_stack')
+ def test_deploy_with_key_filename_provided(self, mock_create_new_stack,
+ mock_gen_keys, *args):
+ self.test_context._name = 'foo'
+ self.test_context._task_id = '1234567890'
+ self.test_context._name_task_id = '{}-{}'.format(
+ self.test_context._name, self.test_context._task_id[:8])
+ self.test_context.template_file = '/bar/baz/some-heat-file'
+ self.test_context.heat_parameters = {'image': 'cirros'}
+ self.test_context.yardstick_gen_key_file = False
+ self.test_context.key_filename = '/etc/yardstick/yardstick.pem'
+ self.test_context.get_neutron_info = mock.MagicMock()
+ self.test_context.deploy()
+
+ mock_create_new_stack.assert_called()
+ mock_gen_keys.assert_not_called()
+
def test_check_for_context(self):
pass
# check that the context exists
diff --git a/yardstick/tests/unit/network_services/helpers/test_cpu.py b/yardstick/tests/unit/network_services/helpers/test_cpu.py
index 871fbf8c9..a1c0826fb 100644
--- a/yardstick/tests/unit/network_services/helpers/test_cpu.py
+++ b/yardstick/tests/unit/network_services/helpers/test_cpu.py
@@ -119,3 +119,97 @@ class TestCpuSysCores(unittest.TestCase):
vnf_cfg = {'lb_config': 'SW', 'lb_count': 1, 'worker_config':
'1C/1T', 'worker_threads': 1}
self.assertEqual(-1, cpu_topo.validate_cpu_cfg(vnf_cfg))
+
+ def test_get_cpu_layout(self):
+ with mock.patch("yardstick.ssh.SSH") as ssh:
+ ssh_mock = mock.Mock(autospec=ssh.SSH)
+ ssh_mock.execute = \
+ mock.Mock(
+ return_value=(1, "# CPU,Core,Socket,Node,,L1d,L1i,L2,L3\n'"
+ "0,0,0,0,,0,0,0,0\n"
+ "1,1,0,0,,1,1,1,0\n", ""))
+ ssh_mock.put = \
+ mock.Mock(return_value=(1, "", ""))
+ cpu_topo = CpuSysCores(ssh_mock)
+ subprocess.check_output = mock.Mock(return_value=0)
+ self.assertEqual({'cpuinfo': [[0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [1, 1, 0, 0, 0, 1, 1, 1, 0]]},
+ cpu_topo.get_cpu_layout())
+
+ def test__str2int(self):
+ self.assertEqual(1, CpuSysCores._str2int("1"))
+
+ def test__str2int_error(self):
+ self.assertEqual(0, CpuSysCores._str2int("err"))
+
+ def test_smt_enabled(self):
+ self.assertEqual(False, CpuSysCores.smt_enabled(
+ {'cpuinfo': [[0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [1, 1, 0, 0, 0, 1, 1, 1, 0]]}))
+
+ def test_is_smt_enabled(self):
+ with mock.patch("yardstick.ssh.SSH") as ssh:
+ ssh_mock = mock.Mock(autospec=ssh.SSH)
+ cpu_topo = CpuSysCores(ssh_mock)
+ cpu_topo.cpuinfo = {'cpuinfo': [[0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [1, 1, 0, 0, 0, 1, 1, 1, 0]]}
+ self.assertEqual(False, cpu_topo.is_smt_enabled())
+
+ def test_cpu_list_per_node(self):
+ with mock.patch("yardstick.ssh.SSH") as ssh:
+ ssh_mock = mock.Mock(autospec=ssh.SSH)
+ cpu_topo = CpuSysCores(ssh_mock)
+ cpu_topo.cpuinfo = {'cpuinfo': [[0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [1, 1, 0, 0, 0, 1, 1, 1, 0]]}
+ self.assertEqual([0, 1], cpu_topo.cpu_list_per_node(0, False))
+
+ def test_cpu_list_per_node_error(self):
+ with mock.patch("yardstick.ssh.SSH") as ssh:
+ ssh_mock = mock.Mock(autospec=ssh.SSH)
+ cpu_topo = CpuSysCores(ssh_mock)
+ cpu_topo.cpuinfo = {'err': [[0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [1, 1, 0, 0, 0, 1, 1, 1, 0]]}
+ with self.assertRaises(RuntimeError) as raised:
+ cpu_topo.cpu_list_per_node(0, False)
+ self.assertIn('Node cpuinfo not available.', str(raised.exception))
+
+ def test_cpu_list_per_node_smt_error(self):
+ with mock.patch("yardstick.ssh.SSH") as ssh:
+ ssh_mock = mock.Mock(autospec=ssh.SSH)
+ cpu_topo = CpuSysCores(ssh_mock)
+ cpu_topo.cpuinfo = {'cpuinfo': [[0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [1, 1, 0, 0, 0, 1, 1, 1, 0]]}
+ with self.assertRaises(RuntimeError) as raised:
+ cpu_topo.cpu_list_per_node(0, True)
+ self.assertIn('SMT is not enabled.', str(raised.exception))
+
+ def test_cpu_slice_of_list_per_node(self):
+ with mock.patch("yardstick.ssh.SSH") as ssh:
+ ssh_mock = mock.Mock(autospec=ssh.SSH)
+ cpu_topo = CpuSysCores(ssh_mock)
+ cpu_topo.cpuinfo = {'cpuinfo': [[0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [1, 1, 0, 0, 0, 1, 1, 1, 0]]}
+ self.assertEqual([1],
+ cpu_topo.cpu_slice_of_list_per_node(0, 1, 0,
+ False))
+
+ def test_cpu_slice_of_list_per_node_error(self):
+ with mock.patch("yardstick.ssh.SSH") as ssh:
+ ssh_mock = mock.Mock(autospec=ssh.SSH)
+ cpu_topo = CpuSysCores(ssh_mock)
+ cpu_topo.cpuinfo = {'cpuinfo': [[0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [1, 1, 0, 0, 0, 1, 1, 1, 0]]}
+ with self.assertRaises(RuntimeError) as raised:
+ cpu_topo.cpu_slice_of_list_per_node(1, 1, 1, False)
+ self.assertIn('cpu_cnt + skip_cnt > length(cpu list).',
+ str(raised.exception))
+
+ def test_cpu_list_per_node_str(self):
+ with mock.patch("yardstick.ssh.SSH") as ssh:
+ ssh_mock = mock.Mock(autospec=ssh.SSH)
+ cpu_topo = CpuSysCores(ssh_mock)
+ cpu_topo.cpuinfo = {'cpuinfo': [[0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [1, 1, 0, 0, 0, 1, 1, 1, 0]]}
+ self.assertEqual("1",
+ cpu_topo.cpu_list_per_node_str(0, 1, 1, ',',
+ False))
diff --git a/yardstick/tests/unit/network_services/helpers/vpp_helpers/__init__.py b/yardstick/tests/unit/network_services/helpers/vpp_helpers/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/yardstick/tests/unit/network_services/helpers/vpp_helpers/__init__.py
diff --git a/yardstick/tests/unit/network_services/helpers/vpp_helpers/test_multiple_loss_ratio_search.py b/yardstick/tests/unit/network_services/helpers/vpp_helpers/test_multiple_loss_ratio_search.py
new file mode 100644
index 000000000..d3145546a
--- /dev/null
+++ b/yardstick/tests/unit/network_services/helpers/vpp_helpers/test_multiple_loss_ratio_search.py
@@ -0,0 +1,2164 @@
+# Copyright (c) 2019 Viosoft 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.
+
+import unittest
+
+import mock
+
+from yardstick.network_services.helpers.vpp_helpers.multiple_loss_ratio_search import \
+ MultipleLossRatioSearch
+from yardstick.network_services.helpers.vpp_helpers.ndr_pdr_result import \
+ NdrPdrResult
+from yardstick.network_services.helpers.vpp_helpers.receive_rate_interval import \
+ ReceiveRateInterval
+from yardstick.network_services.helpers.vpp_helpers.receive_rate_measurement import \
+ ReceiveRateMeasurement
+from yardstick.network_services.traffic_profile.rfc2544 import PortPgIDMap
+
+
+class TestMultipleLossRatioSearch(unittest.TestCase):
+
+ def test___init__(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ self.assertEqual(True, algorithm.latency)
+ self.assertEqual(64, algorithm.pkt_size)
+ self.assertEqual(30, algorithm.final_trial_duration)
+ self.assertEqual(0.005, algorithm.final_relative_width)
+ self.assertEqual(2, algorithm.number_of_intermediate_phases)
+ self.assertEqual(1, algorithm.initial_trial_duration)
+ self.assertEqual(720, algorithm.timeout)
+ self.assertEqual(1, algorithm.doublings)
+
+ def test_double_relative_width(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ self.assertEqual(0.00997, algorithm.double_relative_width(0.005))
+
+ def test_double_step_down(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ self.assertEqual(99003.0, algorithm.double_step_down(0.005, 100000))
+
+ def test_expand_down(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ self.assertEqual(99003.0, algorithm.expand_down(0.005, 1, 100000))
+
+ def test_double_step_up(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ self.assertEqual(101007.0401907013,
+ algorithm.double_step_up(0.005, 100000))
+
+ def test_expand_up(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ self.assertEqual(101007.0401907013,
+ algorithm.expand_up(0.005, 1, 100000))
+
+ def test_half_relative_width(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ self.assertEqual(0.0025031328369998773,
+ algorithm.half_relative_width(0.005))
+
+ def test_half_step_up(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ self.assertEqual(100250.94142341711,
+ algorithm.half_step_up(0.005, 100000))
+
+ def test_init_generator(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock(),
+ mock.Mock(), mock.Mock()))
+ self.assertEqual(ports, algorithm.ports)
+ self.assertEqual(port_pg_id, algorithm.port_pg_id)
+
+ def test_collect_kpi(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ algorithm.init_generator(ports, port_pg_id, mock.Mock, mock.Mock,
+ mock.Mock())
+ self.assertIsNone(algorithm.collect_kpi({}, 100000))
+
+ def test_narrow_down_ndr_and_pdr(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock(), mock.Mock,
+ mock.Mock()))
+ with mock.patch.object(algorithm, 'measure') as \
+ mock_measure, \
+ mock.patch.object(algorithm, 'ndrpdr') as \
+ mock_ndrpdr:
+ ndr_measured_low = ReceiveRateMeasurement(10, 13880000, 13879927,
+ 0)
+ ndr_measured_high = ReceiveRateMeasurement(10, 14880000, 14879927,
+ 0)
+ ndr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_low = ReceiveRateMeasurement(10, 11880000, 11879927,
+ 0)
+ pdr_measured_high = ReceiveRateMeasurement(10, 12880000, 12879927,
+ 0)
+ pdr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_interval = ReceiveRateInterval(ndr_measured_low,
+ ndr_measured_high)
+ pdr_interval = ReceiveRateInterval(pdr_measured_low,
+ pdr_measured_high)
+ starting_result = NdrPdrResult(ndr_interval, pdr_interval)
+ mock_measure.return_value = ReceiveRateMeasurement(1, 14880000,
+ 14879927, 0)
+ mock_ndrpdr.return_value = MultipleLossRatioSearch.ProgressState(
+ starting_result, 2, 30, 0.005, 0.0,
+ 4857361, 4977343)
+ self.assertEqual(
+ {'Result_NDR_LOWER': {'bandwidth_total_Gbps': 0.9327310944,
+ 'rate_total_pps': 1387992.7},
+ 'Result_NDR_UPPER': {
+ 'bandwidth_total_Gbps': 0.9999310943999999,
+ 'rate_total_pps': 1487992.7},
+ 'Result_NDR_packets_lost': {'packet_loss_ratio': 0.0,
+ 'packets_lost': 0.0},
+ 'Result_PDR_LOWER': {
+ 'bandwidth_total_Gbps': 0.7983310943999999,
+ 'rate_total_pps': 1187992.7},
+ 'Result_PDR_UPPER': {'bandwidth_total_Gbps': 0.8655310944,
+ 'rate_total_pps': 1287992.7},
+ 'Result_PDR_packets_lost': {'packet_loss_ratio': 0.0,
+ 'packets_lost': 0.0},
+ 'Result_stream0_NDR_LOWER': {'avg_latency': 3081.0,
+ 'max_latency': 3962.0,
+ 'min_latency': 1000.0},
+ 'Result_stream0_PDR_LOWER': {'avg_latency': 3081.0,
+ 'max_latency': 3962.0,
+ 'min_latency': 1000.0},
+ 'Result_stream1_NDR_LOWER': {'avg_latency': 3149.0,
+ 'max_latency': 3730.0,
+ 'min_latency': 500.0},
+ 'Result_stream1_PDR_LOWER': {'avg_latency': 3149.0,
+ 'max_latency': 3730.0,
+ 'min_latency': 500.0}},
+ algorithm.narrow_down_ndr_and_pdr(12880000, 15880000, 0.0))
+
+ def test__measure_and_update_state(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ starting_interval = ReceiveRateInterval(measured_low, measured_high)
+ starting_result = NdrPdrResult(starting_interval, starting_interval)
+ previous_state = MultipleLossRatioSearch.ProgressState(starting_result,
+ 2, 30, 0.005,
+ 0.0, 4857361,
+ 4977343)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock(), mock.Mock,
+ mock.Mock()))
+ with mock.patch.object(algorithm, 'measure') as \
+ mock_measure:
+ mock_measure.return_value = ReceiveRateMeasurement(1,
+ 4626121.09635,
+ 4626100, 13074)
+ state = algorithm._measure_and_update_state(previous_state,
+ 4626121.09635)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertEqual(1, state.result.ndr_interval.measured_low.duration)
+ self.assertEqual(4626121.09635,
+ state.result.ndr_interval.measured_low.target_tr)
+ self.assertEqual(4626100,
+ state.result.ndr_interval.measured_low.transmit_count)
+ self.assertEqual(13074,
+ state.result.ndr_interval.measured_low.loss_count)
+ self.assertEqual(4613026,
+ state.result.ndr_interval.measured_low.receive_count)
+ self.assertEqual(4626100,
+ state.result.ndr_interval.measured_low.transmit_rate)
+ self.assertEqual(13074.0,
+ state.result.ndr_interval.measured_low.loss_rate)
+ self.assertEqual(4613026.0,
+ state.result.ndr_interval.measured_low.receive_rate)
+ self.assertEqual(0.00283,
+ state.result.ndr_interval.measured_low.loss_fraction)
+ self.assertEqual(1, state.result.ndr_interval.measured_high.duration)
+ self.assertEqual(4857361,
+ state.result.ndr_interval.measured_high.target_tr)
+ self.assertEqual(4857339,
+ state.result.ndr_interval.measured_high.transmit_count)
+ self.assertEqual(84965,
+ state.result.ndr_interval.measured_high.loss_count)
+ self.assertEqual(4772374,
+ state.result.ndr_interval.measured_high.receive_count)
+ self.assertEqual(4857339,
+ state.result.ndr_interval.measured_high.transmit_rate)
+ self.assertEqual(84965.0,
+ state.result.ndr_interval.measured_high.loss_rate)
+ self.assertEqual(4772374.0,
+ state.result.ndr_interval.measured_high.receive_rate)
+ self.assertEqual(0.01749,
+ state.result.ndr_interval.measured_high.loss_fraction)
+ self.assertEqual(1, state.result.pdr_interval.measured_low.duration)
+ self.assertEqual(4626121.09635,
+ state.result.pdr_interval.measured_low.target_tr)
+ self.assertEqual(4626100,
+ state.result.pdr_interval.measured_low.transmit_count)
+ self.assertEqual(13074,
+ state.result.pdr_interval.measured_low.loss_count)
+ self.assertEqual(4613026,
+ state.result.pdr_interval.measured_low.receive_count)
+ self.assertEqual(4626100,
+ state.result.pdr_interval.measured_low.transmit_rate)
+ self.assertEqual(13074.0,
+ state.result.pdr_interval.measured_low.loss_rate)
+ self.assertEqual(4613026.0,
+ state.result.pdr_interval.measured_low.receive_rate)
+ self.assertEqual(0.00283,
+ state.result.pdr_interval.measured_low.loss_fraction)
+ self.assertEqual(1, state.result.pdr_interval.measured_high.duration)
+ self.assertEqual(4857361,
+ state.result.pdr_interval.measured_high.target_tr)
+ self.assertEqual(4857339,
+ state.result.pdr_interval.measured_high.transmit_count)
+ self.assertEqual(84965,
+ state.result.pdr_interval.measured_high.loss_count)
+ self.assertEqual(4772374,
+ state.result.pdr_interval.measured_high.receive_count)
+ self.assertEqual(4857339,
+ state.result.pdr_interval.measured_high.transmit_rate)
+ self.assertEqual(84965.0,
+ state.result.pdr_interval.measured_high.loss_rate)
+ self.assertEqual(4772374.0,
+ state.result.pdr_interval.measured_high.receive_rate)
+ self.assertEqual(0.01749,
+ state.result.pdr_interval.measured_high.loss_fraction)
+ self.assertEqual(2, state.phases)
+ self.assertEqual(30, state.duration)
+ self.assertEqual(0.005, state.width_goal)
+ self.assertEqual(0.0, state.packet_loss_ratio)
+ self.assertEqual(4857361, state.minimum_transmit_rate)
+ self.assertEqual(4977343, state.maximum_transmit_rate)
+
+ def test_new_interval(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ measured = ReceiveRateMeasurement(1, 3972540.4108, 21758482, 0)
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ receive_rate_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ result = algorithm._new_interval(receive_rate_interval, measured, 0.0)
+ self.assertIsInstance(result, ReceiveRateInterval)
+ self.assertEqual(1, result.measured_low.duration)
+ self.assertEqual(3972540.4108, result.measured_low.target_tr)
+ self.assertEqual(21758482, result.measured_low.transmit_count)
+ self.assertEqual(0, result.measured_low.loss_count)
+ self.assertEqual(21758482, result.measured_low.receive_count)
+ self.assertEqual(21758482, result.measured_low.transmit_rate)
+ self.assertEqual(0.0, result.measured_low.loss_rate)
+ self.assertEqual(21758482.0, result.measured_low.receive_rate)
+ self.assertEqual(0.0, result.measured_low.loss_fraction)
+ self.assertEqual(1, result.measured_high.duration)
+ self.assertEqual(4857361, result.measured_high.target_tr)
+ self.assertEqual(4857339, result.measured_high.transmit_count)
+ self.assertEqual(84965, result.measured_high.loss_count)
+ self.assertEqual(4772374, result.measured_high.receive_count)
+ self.assertEqual(4857339, result.measured_high.transmit_rate)
+ self.assertEqual(84965.0, result.measured_high.loss_rate)
+ self.assertEqual(4772374.0, result.measured_high.receive_rate)
+ self.assertEqual(0.01749, result.measured_high.loss_fraction)
+
+ def test_new_interval_zero(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ measured = ReceiveRateMeasurement(1, 4977343, 21758482, 0)
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ receive_rate_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ result = algorithm._new_interval(receive_rate_interval, measured, 0.0)
+ self.assertIsInstance(result, ReceiveRateInterval)
+ self.assertEqual(1, result.measured_low.duration)
+ self.assertEqual(4857361.0, result.measured_low.target_tr)
+ self.assertEqual(4857339, result.measured_low.transmit_count)
+ self.assertEqual(84965, result.measured_low.loss_count)
+ self.assertEqual(4772374, result.measured_low.receive_count)
+ self.assertEqual(4857339.0, result.measured_low.transmit_rate)
+ self.assertEqual(84965.0, result.measured_low.loss_rate)
+ self.assertEqual(4772374.0, result.measured_low.receive_rate)
+ self.assertEqual(0.01749, result.measured_low.loss_fraction)
+ self.assertEqual(1, result.measured_high.duration)
+ self.assertEqual(4977343.0, result.measured_high.target_tr)
+ self.assertEqual(21758482, result.measured_high.transmit_count)
+ self.assertEqual(0, result.measured_high.loss_count)
+ self.assertEqual(21758482, result.measured_high.receive_count)
+ self.assertEqual(21758482.0, result.measured_high.transmit_rate)
+ self.assertEqual(0.0, result.measured_high.loss_rate)
+ self.assertEqual(21758482.0, result.measured_high.receive_rate)
+ self.assertEqual(0.0, result.measured_high.loss_fraction)
+
+ def test_new_interval_one(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ measured = ReceiveRateMeasurement(1, 5000000, 2175848, 0)
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ receive_rate_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ result = algorithm._new_interval(receive_rate_interval, measured, 0.0)
+ self.assertIsInstance(result, ReceiveRateInterval)
+ self.assertEqual(1, result.measured_low.duration)
+ self.assertEqual(4857361.0, result.measured_low.target_tr)
+ self.assertEqual(4857339, result.measured_low.transmit_count)
+ self.assertEqual(84965, result.measured_low.loss_count)
+ self.assertEqual(4772374, result.measured_low.receive_count)
+ self.assertEqual(4857339.0, result.measured_low.transmit_rate)
+ self.assertEqual(84965.0, result.measured_low.loss_rate)
+ self.assertEqual(4772374.0, result.measured_low.receive_rate)
+ self.assertEqual(0.01749, result.measured_low.loss_fraction)
+ self.assertEqual(1, result.measured_high.duration)
+ self.assertEqual(4977343.0, result.measured_high.target_tr)
+ self.assertEqual(4977320, result.measured_high.transmit_count)
+ self.assertEqual(119959, result.measured_high.loss_count)
+ self.assertEqual(4857361, result.measured_high.receive_count)
+ self.assertEqual(4977320.0, result.measured_high.transmit_rate)
+ self.assertEqual(119959.0, result.measured_high.loss_rate)
+ self.assertEqual(4857361.0, result.measured_high.receive_rate)
+ self.assertEqual(0.0241, result.measured_high.loss_fraction)
+
+ def test_new_interval_valid_1st(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ measured = ReceiveRateMeasurement(1, 4000000, 2175848, 0)
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ receive_rate_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ result = algorithm._new_interval(receive_rate_interval, measured, 0.5)
+ self.assertIsInstance(result, ReceiveRateInterval)
+ self.assertEqual(1, result.measured_low.duration)
+ self.assertEqual(4857361.0, result.measured_low.target_tr)
+ self.assertEqual(4857339, result.measured_low.transmit_count)
+ self.assertEqual(84965, result.measured_low.loss_count)
+ self.assertEqual(4772374, result.measured_low.receive_count)
+ self.assertEqual(4857339.0, result.measured_low.transmit_rate)
+ self.assertEqual(84965.0, result.measured_low.loss_rate)
+ self.assertEqual(4772374.0, result.measured_low.receive_rate)
+ self.assertEqual(0.01749, result.measured_low.loss_fraction)
+ self.assertEqual(1, result.measured_high.duration)
+ self.assertEqual(4977343.0, result.measured_high.target_tr)
+ self.assertEqual(4977320, result.measured_high.transmit_count)
+ self.assertEqual(119959, result.measured_high.loss_count)
+ self.assertEqual(4857361, result.measured_high.receive_count)
+ self.assertEqual(4977320.0, result.measured_high.transmit_rate)
+ self.assertEqual(119959.0, result.measured_high.loss_rate)
+ self.assertEqual(4857361.0, result.measured_high.receive_rate)
+ self.assertEqual(0.0241, result.measured_high.loss_fraction)
+
+ def test_new_interval_valid_1st_loss(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ measured = ReceiveRateMeasurement(1, 4000000, 2175848, 1000000)
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ receive_rate_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ result = algorithm._new_interval(receive_rate_interval, measured, 0.02)
+ self.assertIsInstance(result, ReceiveRateInterval)
+ self.assertEqual(1, result.measured_low.duration)
+ self.assertEqual(4000000.0, result.measured_low.target_tr)
+ self.assertEqual(2175848, result.measured_low.transmit_count)
+ self.assertEqual(1000000, result.measured_low.loss_count)
+ self.assertEqual(1175848, result.measured_low.receive_count)
+ self.assertEqual(2175848.0, result.measured_low.transmit_rate)
+ self.assertEqual(1000000.0, result.measured_low.loss_rate)
+ self.assertEqual(1175848.0, result.measured_low.receive_rate)
+ self.assertEqual(0.45959, result.measured_low.loss_fraction)
+ self.assertEqual(1, result.measured_high.duration)
+ self.assertEqual(4977343.0, result.measured_high.target_tr)
+ self.assertEqual(4977320, result.measured_high.transmit_count)
+ self.assertEqual(119959, result.measured_high.loss_count)
+ self.assertEqual(4857361, result.measured_high.receive_count)
+ self.assertEqual(4977320.0, result.measured_high.transmit_rate)
+ self.assertEqual(119959.0, result.measured_high.loss_rate)
+ self.assertEqual(4857361.0, result.measured_high.receive_rate)
+ self.assertEqual(0.0241, result.measured_high.loss_fraction)
+
+ def test_new_interval_valid_2nd(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ measured = ReceiveRateMeasurement(1, 5000000, 2175848, 0)
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ receive_rate_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ result = algorithm._new_interval(receive_rate_interval, measured, 0.5)
+ self.assertIsInstance(result, ReceiveRateInterval)
+ self.assertEqual(1, result.measured_low.duration)
+ self.assertEqual(4977343.0, result.measured_low.target_tr)
+ self.assertEqual(4977320, result.measured_low.transmit_count)
+ self.assertEqual(119959, result.measured_low.loss_count)
+ self.assertEqual(4857361, result.measured_low.receive_count)
+ self.assertEqual(4977320.0, result.measured_low.transmit_rate)
+ self.assertEqual(119959.0, result.measured_low.loss_rate)
+ self.assertEqual(4857361.0, result.measured_low.receive_rate)
+ self.assertEqual(0.0241, result.measured_low.loss_fraction)
+ self.assertEqual(1, result.measured_high.duration)
+ self.assertEqual(5000000.0, result.measured_high.target_tr)
+ self.assertEqual(2175848, result.measured_high.transmit_count)
+ self.assertEqual(0, result.measured_high.loss_count)
+ self.assertEqual(2175848, result.measured_high.receive_count)
+ self.assertEqual(2175848.0, result.measured_high.transmit_rate)
+ self.assertEqual(0.0, result.measured_high.loss_rate)
+ self.assertEqual(2175848.0, result.measured_high.receive_rate)
+ self.assertEqual(0.0, result.measured_high.loss_fraction)
+
+ def test_new_interval_valid_3rd(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ measured = ReceiveRateMeasurement(1, 4867361, 2175848, 0)
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ receive_rate_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ result = algorithm._new_interval(receive_rate_interval, measured, 0.5)
+ self.assertIsInstance(result, ReceiveRateInterval)
+ self.assertEqual(1, result.measured_low.duration)
+ self.assertEqual(4867361.0, result.measured_low.target_tr)
+ self.assertEqual(2175848, result.measured_low.transmit_count)
+ self.assertEqual(0, result.measured_low.loss_count)
+ self.assertEqual(2175848, result.measured_low.receive_count)
+ self.assertEqual(2175848.0, result.measured_low.transmit_rate)
+ self.assertEqual(0.0, result.measured_low.loss_rate)
+ self.assertEqual(2175848.0, result.measured_low.receive_rate)
+ self.assertEqual(0.0, result.measured_low.loss_fraction)
+ self.assertEqual(1, result.measured_high.duration)
+ self.assertEqual(4977343.0, result.measured_high.target_tr)
+ self.assertEqual(4977320, result.measured_high.transmit_count)
+ self.assertEqual(119959, result.measured_high.loss_count)
+ self.assertEqual(4857361, result.measured_high.receive_count)
+ self.assertEqual(4977320.0, result.measured_high.transmit_rate)
+ self.assertEqual(119959.0, result.measured_high.loss_rate)
+ self.assertEqual(4857361.0, result.measured_high.receive_rate)
+ self.assertEqual(0.0241, result.measured_high.loss_fraction)
+
+ def test_new_interval_valid_3rd_loss(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ measured = ReceiveRateMeasurement(1, 4867361, 2175848, 1000000)
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ receive_rate_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ result = algorithm._new_interval(receive_rate_interval, measured, 0.2)
+ self.assertIsInstance(result, ReceiveRateInterval)
+ self.assertEqual(1, result.measured_low.duration)
+ self.assertEqual(4857361.0, result.measured_low.target_tr)
+ self.assertEqual(4857339, result.measured_low.transmit_count)
+ self.assertEqual(84965, result.measured_low.loss_count)
+ self.assertEqual(4772374, result.measured_low.receive_count)
+ self.assertEqual(4857339.0, result.measured_low.transmit_rate)
+ self.assertEqual(84965.0, result.measured_low.loss_rate)
+ self.assertEqual(4772374.0, result.measured_low.receive_rate)
+ self.assertEqual(0.01749, result.measured_low.loss_fraction)
+ self.assertEqual(1, result.measured_high.duration)
+ self.assertEqual(4867361.0, result.measured_high.target_tr)
+ self.assertEqual(2175848, result.measured_high.transmit_count)
+ self.assertEqual(1000000, result.measured_high.loss_count)
+ self.assertEqual(1175848, result.measured_high.receive_count)
+ self.assertEqual(2175848.0, result.measured_high.transmit_rate)
+ self.assertEqual(1000000.0, result.measured_high.loss_rate)
+ self.assertEqual(1175848.0, result.measured_high.receive_rate)
+ self.assertEqual(0.45959, result.measured_high.loss_fraction)
+
+ def test_ndrpdr(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock(), mock.Mock,
+ mock.Mock()))
+ with mock.patch.object(algorithm, 'measure') as \
+ mock_measure:
+ measured_low = ReceiveRateMeasurement(30, 14880000, 14879927, 0)
+ measured_high = ReceiveRateMeasurement(30, 14880000, 14879927, 0)
+ measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ starting_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ starting_result = NdrPdrResult(starting_interval,
+ starting_interval)
+ mock_measure.return_value = ReceiveRateMeasurement(1, 14880000,
+ 14879927, 0)
+ previous_state = MultipleLossRatioSearch.ProgressState(
+ starting_result, -1, 30, 0.005, 0.0, 14880000,
+ 14880000)
+ state = algorithm.ndrpdr(previous_state)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertEqual(30, state.result.ndr_interval.measured_low.duration)
+ self.assertEqual(14880000,
+ state.result.ndr_interval.measured_low.target_tr)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_low.transmit_count)
+ self.assertEqual(0, state.result.ndr_interval.measured_low.loss_count)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_low.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0, state.result.ndr_interval.measured_low.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.ndr_interval.measured_high.duration)
+ self.assertEqual(14880000,
+ state.result.ndr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_high.transmit_count)
+ self.assertEqual(0, state.result.ndr_interval.measured_high.loss_count)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_high.transmit_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_high.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_high.receive_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_high.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_low.duration)
+ self.assertEqual(14880000,
+ state.result.pdr_interval.measured_low.target_tr)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_low.transmit_count)
+ self.assertEqual(0, state.result.pdr_interval.measured_low.loss_count)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_low.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0, state.result.pdr_interval.measured_low.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_high.duration)
+ self.assertEqual(14880000,
+ state.result.pdr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_high.transmit_count)
+ self.assertEqual(0, state.result.pdr_interval.measured_high.loss_count)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_high.transmit_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_high.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_high.receive_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_high.loss_fraction)
+ self.assertEqual(-1, state.phases)
+ self.assertEqual(30, state.duration)
+ self.assertEqual(0.005, state.width_goal)
+ self.assertEqual(0.0, state.packet_loss_ratio)
+ self.assertEqual(14880000, state.minimum_transmit_rate)
+ self.assertEqual(14880000, state.maximum_transmit_rate)
+
+ def test_ndrpdr_ndr_rel_width(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock(), mock.Mock,
+ mock.Mock()))
+ with mock.patch.object(algorithm, 'measure') as \
+ mock_measure, \
+ mock.patch.object(algorithm, '_measure_and_update_state') as \
+ mock__measure_and_update_state:
+ measured_low = ReceiveRateMeasurement(30, 880000, 879927, 0)
+ measured_high = ReceiveRateMeasurement(30, 14880000, 14879927, 0)
+ measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ starting_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ ending_interval = ReceiveRateInterval(measured_high, measured_high)
+ starting_result = NdrPdrResult(starting_interval,
+ starting_interval)
+ ending_result = NdrPdrResult(ending_interval, ending_interval)
+ mock_measure.return_value = ReceiveRateMeasurement(1, 14880000,
+ 14879927, 0)
+ mock__measure_and_update_state.return_value = \
+ MultipleLossRatioSearch.ProgressState(ending_result, -1, 30,
+ 0.005, 0.0, 14880000,
+ 14880000)
+ previous_state = MultipleLossRatioSearch.ProgressState(
+ starting_result, -1, 30, 0.005, 0.0, 14880000,
+ 14880000)
+ state = algorithm.ndrpdr(previous_state)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertEqual(30, state.result.ndr_interval.measured_low.duration)
+ self.assertEqual(14880000,
+ state.result.ndr_interval.measured_low.target_tr)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_low.transmit_count)
+ self.assertEqual(0, state.result.ndr_interval.measured_low.loss_count)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_low.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0, state.result.ndr_interval.measured_low.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.ndr_interval.measured_high.duration)
+ self.assertEqual(14880000,
+ state.result.ndr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_high.transmit_count)
+ self.assertEqual(0, state.result.ndr_interval.measured_high.loss_count)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_high.transmit_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_high.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_high.receive_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_high.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_low.duration)
+ self.assertEqual(14880000,
+ state.result.pdr_interval.measured_low.target_tr)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_low.transmit_count)
+ self.assertEqual(0, state.result.pdr_interval.measured_low.loss_count)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_low.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0, state.result.pdr_interval.measured_low.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_high.duration)
+ self.assertEqual(14880000,
+ state.result.pdr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_high.transmit_count)
+ self.assertEqual(0, state.result.pdr_interval.measured_high.loss_count)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_high.transmit_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_high.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_high.receive_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_high.loss_fraction)
+ self.assertEqual(-1, state.phases)
+ self.assertEqual(30, state.duration)
+ self.assertEqual(0.005, state.width_goal)
+ self.assertEqual(0.0, state.packet_loss_ratio)
+ self.assertEqual(14880000, state.minimum_transmit_rate)
+ self.assertEqual(14880000, state.maximum_transmit_rate)
+
+ def test_ndrpdr_pdr_rel_width(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock(), mock.Mock,
+ mock.Mock()))
+ with mock.patch.object(algorithm, 'measure') as \
+ mock_measure, \
+ mock.patch.object(algorithm, '_measure_and_update_state') as \
+ mock__measure_and_update_state:
+ ndr_measured_low = ReceiveRateMeasurement(30, 14880000, 14879927,
+ 0)
+ ndr_measured_high = ReceiveRateMeasurement(30, 14880000, 14879927,
+ 0)
+ ndr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_low = ReceiveRateMeasurement(30, 880000, 879927, 0)
+ pdr_measured_high = ReceiveRateMeasurement(30, 14880000, 14879927,
+ 0)
+ pdr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_interval = ReceiveRateInterval(ndr_measured_low,
+ ndr_measured_high)
+ pdr_interval = ReceiveRateInterval(pdr_measured_low,
+ pdr_measured_high)
+ starting_result = NdrPdrResult(ndr_interval, pdr_interval)
+ ending_result = NdrPdrResult(ndr_interval, ndr_interval)
+ mock_measure.return_value = ReceiveRateMeasurement(1, 14880000,
+ 14879927, 0)
+ mock__measure_and_update_state.return_value = \
+ MultipleLossRatioSearch.ProgressState(ending_result, -1, 30,
+ 0.005, 0.0, 14880000,
+ 14880000)
+ previous_state = MultipleLossRatioSearch.ProgressState(
+ starting_result, -1, 30, 0.005, 0.0, 14880000,
+ 14880000)
+ state = algorithm.ndrpdr(previous_state)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertEqual(30, state.result.ndr_interval.measured_low.duration)
+ self.assertEqual(14880000,
+ state.result.ndr_interval.measured_low.target_tr)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_low.transmit_count)
+ self.assertEqual(0, state.result.ndr_interval.measured_low.loss_count)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_low.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0, state.result.ndr_interval.measured_low.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.ndr_interval.measured_high.duration)
+ self.assertEqual(14880000,
+ state.result.ndr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_high.transmit_count)
+ self.assertEqual(0, state.result.ndr_interval.measured_high.loss_count)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_high.transmit_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_high.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_high.receive_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_high.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_low.duration)
+ self.assertEqual(14880000,
+ state.result.pdr_interval.measured_low.target_tr)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_low.transmit_count)
+ self.assertEqual(0, state.result.pdr_interval.measured_low.loss_count)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_low.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0, state.result.pdr_interval.measured_low.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_high.duration)
+ self.assertEqual(14880000,
+ state.result.pdr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_high.transmit_count)
+ self.assertEqual(0, state.result.pdr_interval.measured_high.loss_count)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_high.transmit_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_high.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_high.receive_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_high.loss_fraction)
+ self.assertEqual(-1, state.phases)
+ self.assertEqual(30, state.duration)
+ self.assertEqual(0.005, state.width_goal)
+ self.assertEqual(0.0, state.packet_loss_ratio)
+ self.assertEqual(14880000, state.minimum_transmit_rate)
+ self.assertEqual(14880000, state.maximum_transmit_rate)
+
+ def test_ndrpdr_ndr_lo_duration(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock(), mock.Mock,
+ mock.Mock()))
+ with mock.patch.object(algorithm, 'measure') as \
+ mock_measure, \
+ mock.patch.object(algorithm, '_measure_and_update_state') as \
+ mock__measure_and_update_state:
+ measured_low = ReceiveRateMeasurement(30, 14880000, 14879927, 0)
+ measured_high = ReceiveRateMeasurement(30, 14880000, 14879927, 100)
+ measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ starting_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ starting_result = NdrPdrResult(starting_interval,
+ starting_interval)
+ mock_measure.return_value = ReceiveRateMeasurement(1, 14880000,
+ 14879927, 0)
+ mock__measure_and_update_state.return_value = \
+ MultipleLossRatioSearch.ProgressState(starting_result, -1, 30,
+ 0.005, 0.0, 14880000,
+ 14880000)
+ previous_state = MultipleLossRatioSearch.ProgressState(
+ starting_result, -1, 50, 0.005, 0.0, 14880000,
+ 14880000)
+ state = algorithm.ndrpdr(previous_state)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertEqual(30, state.result.ndr_interval.measured_low.duration)
+ self.assertEqual(14880000,
+ state.result.ndr_interval.measured_low.target_tr)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_low.transmit_count)
+ self.assertEqual(0, state.result.ndr_interval.measured_low.loss_count)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_low.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0, state.result.ndr_interval.measured_low.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.ndr_interval.measured_high.duration)
+ self.assertEqual(14880000,
+ state.result.ndr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_high.transmit_count)
+ self.assertEqual(100,
+ state.result.ndr_interval.measured_high.loss_count)
+ self.assertEqual(14879827,
+ state.result.ndr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_high.transmit_rate)
+ self.assertEqual(3.33333,
+ state.result.ndr_interval.measured_high.loss_rate)
+ self.assertEqual(495994.23333,
+ state.result.ndr_interval.measured_high.receive_rate)
+ self.assertEqual(1e-05,
+ state.result.ndr_interval.measured_high.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_low.duration)
+ self.assertEqual(14880000,
+ state.result.pdr_interval.measured_low.target_tr)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_low.transmit_count)
+ self.assertEqual(0, state.result.pdr_interval.measured_low.loss_count)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_low.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0, state.result.pdr_interval.measured_low.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_high.duration)
+ self.assertEqual(14880000,
+ state.result.pdr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_high.transmit_count)
+ self.assertEqual(100,
+ state.result.pdr_interval.measured_high.loss_count)
+ self.assertEqual(14879827,
+ state.result.pdr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_high.transmit_rate)
+ self.assertEqual(3.33333,
+ state.result.pdr_interval.measured_high.loss_rate)
+ self.assertEqual(495994.23333,
+ state.result.pdr_interval.measured_high.receive_rate)
+ self.assertEqual(1e-05,
+ state.result.pdr_interval.measured_high.loss_fraction)
+ self.assertEqual(-1, state.phases)
+ self.assertEqual(30, state.duration)
+ self.assertEqual(0.005, state.width_goal)
+ self.assertEqual(0.0, state.packet_loss_ratio)
+ self.assertEqual(14880000, state.minimum_transmit_rate)
+ self.assertEqual(14880000, state.maximum_transmit_rate)
+
+ def test_ndrpdr_ndr_hi_duration(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock(), mock.Mock,
+ mock.Mock()))
+ with mock.patch.object(algorithm, 'measure') as \
+ mock_measure, \
+ mock.patch.object(algorithm, '_measure_and_update_state') as \
+ mock__measure_and_update_state:
+ measured_low = ReceiveRateMeasurement(60, 14880000, 14879927, 0)
+ measured_high = ReceiveRateMeasurement(30, 14880000, 14879927, 100)
+ measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ starting_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ starting_result = NdrPdrResult(starting_interval,
+ starting_interval)
+ mock_measure.return_value = ReceiveRateMeasurement(1, 14880000,
+ 14879927, 0)
+ mock__measure_and_update_state.return_value = \
+ MultipleLossRatioSearch.ProgressState(starting_result, -1, 30,
+ 0.005, 0.0, 14880000,
+ 14880000)
+ previous_state = MultipleLossRatioSearch.ProgressState(
+ starting_result, -1, 50, 0.005, 0.0, 14880000,
+ 14880000)
+ state = algorithm.ndrpdr(previous_state)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertEqual(60.0, state.result.ndr_interval.measured_low.duration)
+ self.assertEqual(14880000,
+ state.result.ndr_interval.measured_low.target_tr)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_low.transmit_count)
+ self.assertEqual(0, state.result.ndr_interval.measured_low.loss_count)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_low.receive_count)
+ self.assertEqual(247998.78333,
+ state.result.ndr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0, state.result.ndr_interval.measured_low.loss_rate)
+ self.assertEqual(247998.78333,
+ state.result.ndr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.ndr_interval.measured_high.duration)
+ self.assertEqual(14880000,
+ state.result.ndr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_high.transmit_count)
+ self.assertEqual(100,
+ state.result.ndr_interval.measured_high.loss_count)
+ self.assertEqual(14879827,
+ state.result.ndr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_high.transmit_rate)
+ self.assertEqual(3.33333,
+ state.result.ndr_interval.measured_high.loss_rate)
+ self.assertEqual(495994.23333,
+ state.result.ndr_interval.measured_high.receive_rate)
+ self.assertEqual(1e-05,
+ state.result.ndr_interval.measured_high.loss_fraction)
+ self.assertEqual(60.0, state.result.pdr_interval.measured_low.duration)
+ self.assertEqual(14880000,
+ state.result.pdr_interval.measured_low.target_tr)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_low.transmit_count)
+ self.assertEqual(0, state.result.pdr_interval.measured_low.loss_count)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_low.receive_count)
+ self.assertEqual(247998.78333,
+ state.result.pdr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0, state.result.pdr_interval.measured_low.loss_rate)
+ self.assertEqual(247998.78333,
+ state.result.pdr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_high.duration)
+ self.assertEqual(14880000,
+ state.result.pdr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_high.transmit_count)
+ self.assertEqual(100,
+ state.result.pdr_interval.measured_high.loss_count)
+ self.assertEqual(14879827,
+ state.result.pdr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_high.transmit_rate)
+ self.assertEqual(3.33333,
+ state.result.pdr_interval.measured_high.loss_rate)
+ self.assertEqual(495994.23333,
+ state.result.pdr_interval.measured_high.receive_rate)
+ self.assertEqual(1e-05,
+ state.result.pdr_interval.measured_high.loss_fraction)
+ self.assertEqual(-1, state.phases)
+ self.assertEqual(30, state.duration)
+ self.assertEqual(0.005, state.width_goal)
+ self.assertEqual(0.0, state.packet_loss_ratio)
+ self.assertEqual(14880000, state.minimum_transmit_rate)
+ self.assertEqual(14880000, state.maximum_transmit_rate)
+
+ def test_ndrpdr_error(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=0)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock(), mock.Mock,
+ mock.Mock()))
+ with mock.patch.object(algorithm, 'measure') as \
+ mock_measure:
+ measured_low = ReceiveRateMeasurement(30, 14880000, 14879927, 0)
+ measured_high = ReceiveRateMeasurement(30, 14880000, 14879927, 0)
+ measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ starting_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ starting_result = NdrPdrResult(starting_interval,
+ starting_interval)
+ mock_measure.return_value = ReceiveRateMeasurement(1, 14880000,
+ 14879927, 0)
+ previous_state = MultipleLossRatioSearch.ProgressState(
+ starting_result, -1, 30, 0.005, 0.0, 14880000,
+ 14880000)
+ with self.assertRaises(RuntimeError) as raised:
+ algorithm.ndrpdr(previous_state)
+
+ self.assertIn('Optimized search takes too long.',
+ str(raised.exception))
+
+ def test_ndrpdr_update_state_ndr_hi(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock(), mock.Mock,
+ mock.Mock()))
+ with mock.patch.object(algorithm, 'measure') as \
+ mock_measure, \
+ mock.patch.object(algorithm, '_measure_and_update_state') as \
+ mock__measure_and_update_state:
+ ndr_measured_low = ReceiveRateMeasurement(30, 10880000, 10879927,
+ 0)
+ ndr_measured_high = ReceiveRateMeasurement(30, 12880000, 12879927,
+ 0)
+ ndr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_low = ReceiveRateMeasurement(30, 12880000, 12879927,
+ 0)
+ pdr_measured_high = ReceiveRateMeasurement(30, 14880000, 14879927,
+ 0)
+ pdr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_interval = ReceiveRateInterval(ndr_measured_low,
+ ndr_measured_high)
+ pdr_interval = ReceiveRateInterval(pdr_measured_low,
+ pdr_measured_high)
+ starting_result = NdrPdrResult(ndr_interval, pdr_interval)
+ ending_result = NdrPdrResult(pdr_interval, pdr_interval)
+ mock_measure.return_value = ReceiveRateMeasurement(1, 14880000,
+ 14879927, 0)
+ mock__measure_and_update_state.return_value = \
+ MultipleLossRatioSearch.ProgressState(ending_result, -1, 30,
+ 0.2, 0.0, 14880000,
+ 14880000)
+ previous_state = MultipleLossRatioSearch.ProgressState(
+ starting_result, -1, 30, 0.005, 0.0, 14880000,
+ 14880000)
+ state = algorithm.ndrpdr(previous_state)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertEqual(30, state.result.ndr_interval.measured_low.duration)
+ self.assertEqual(12880000.0,
+ state.result.ndr_interval.measured_low.target_tr)
+ self.assertEqual(12879927,
+ state.result.ndr_interval.measured_low.transmit_count)
+ self.assertEqual(0, state.result.ndr_interval.measured_low.loss_count)
+ self.assertEqual(12879927,
+ state.result.ndr_interval.measured_low.receive_count)
+ self.assertEqual(429330.9,
+ state.result.ndr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0, state.result.ndr_interval.measured_low.loss_rate)
+ self.assertEqual(429330.9,
+ state.result.ndr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.ndr_interval.measured_high.duration)
+ self.assertEqual(14880000.0,
+ state.result.ndr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_high.transmit_count)
+ self.assertEqual(0, state.result.ndr_interval.measured_high.loss_count)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_high.transmit_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_high.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_high.receive_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_high.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_low.duration)
+ self.assertEqual(12880000.0,
+ state.result.pdr_interval.measured_low.target_tr)
+ self.assertEqual(12879927,
+ state.result.pdr_interval.measured_low.transmit_count)
+ self.assertEqual(0, state.result.pdr_interval.measured_low.loss_count)
+ self.assertEqual(12879927,
+ state.result.pdr_interval.measured_low.receive_count)
+ self.assertEqual(429330.9,
+ state.result.pdr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0, state.result.pdr_interval.measured_low.loss_rate)
+ self.assertEqual(429330.9,
+ state.result.pdr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_high.duration)
+ self.assertEqual(14880000,
+ state.result.pdr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_high.transmit_count)
+ self.assertEqual(0, state.result.pdr_interval.measured_high.loss_count)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_high.transmit_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_high.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_high.receive_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_high.loss_fraction)
+ self.assertEqual(-1, state.phases)
+ self.assertEqual(30, state.duration)
+ self.assertEqual(0.2, state.width_goal)
+ self.assertEqual(0.0, state.packet_loss_ratio)
+ self.assertEqual(14880000, state.minimum_transmit_rate)
+ self.assertEqual(14880000, state.maximum_transmit_rate)
+
+ def test_ndrpdr_update_state_ndr_hi_duration(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock(), mock.Mock,
+ mock.Mock()))
+ with mock.patch.object(algorithm, 'measure') as \
+ mock_measure, \
+ mock.patch.object(algorithm, '_measure_and_update_state') as \
+ mock__measure_and_update_state:
+ ndr_measured_low = ReceiveRateMeasurement(30, 10880000, 10879927,
+ 0)
+ ndr_measured_high = ReceiveRateMeasurement(30, 12880000, 12879927,
+ 0)
+ ndr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_low = ReceiveRateMeasurement(30, 12880000, 12879927,
+ 0)
+ pdr_measured_high = ReceiveRateMeasurement(30, 14880000, 14879927,
+ 0)
+ pdr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_interval = ReceiveRateInterval(ndr_measured_low,
+ ndr_measured_high)
+ pdr_interval = ReceiveRateInterval(pdr_measured_low,
+ pdr_measured_high)
+ starting_result = NdrPdrResult(ndr_interval, pdr_interval)
+ ending_result = NdrPdrResult(pdr_interval, pdr_interval)
+ mock_measure.return_value = ReceiveRateMeasurement(1, 14880000,
+ 14879927, 0)
+ mock__measure_and_update_state.return_value = \
+ MultipleLossRatioSearch.ProgressState(ending_result, -1, 30,
+ 0.2, 0.0, 14880000,
+ 14880000)
+ previous_state = MultipleLossRatioSearch.ProgressState(
+ starting_result, -1, 50, 0.005, 0.0, 4880000,
+ 10880000)
+ state = algorithm.ndrpdr(previous_state)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertEqual(30, state.result.ndr_interval.measured_low.duration)
+ self.assertEqual(12880000.0,
+ state.result.ndr_interval.measured_low.target_tr)
+ self.assertEqual(12879927,
+ state.result.ndr_interval.measured_low.transmit_count)
+ self.assertEqual(0, state.result.ndr_interval.measured_low.loss_count)
+ self.assertEqual(12879927,
+ state.result.ndr_interval.measured_low.receive_count)
+ self.assertEqual(429330.9,
+ state.result.ndr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0, state.result.ndr_interval.measured_low.loss_rate)
+ self.assertEqual(429330.9,
+ state.result.ndr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.ndr_interval.measured_high.duration)
+ self.assertEqual(14880000.0,
+ state.result.ndr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_high.transmit_count)
+ self.assertEqual(0, state.result.ndr_interval.measured_high.loss_count)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_high.transmit_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_high.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_high.receive_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_high.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_low.duration)
+ self.assertEqual(12880000.0,
+ state.result.pdr_interval.measured_low.target_tr)
+ self.assertEqual(12879927,
+ state.result.pdr_interval.measured_low.transmit_count)
+ self.assertEqual(0, state.result.pdr_interval.measured_low.loss_count)
+ self.assertEqual(12879927,
+ state.result.pdr_interval.measured_low.receive_count)
+ self.assertEqual(429330.9,
+ state.result.pdr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0, state.result.pdr_interval.measured_low.loss_rate)
+ self.assertEqual(429330.9,
+ state.result.pdr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_high.duration)
+ self.assertEqual(14880000,
+ state.result.pdr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_high.transmit_count)
+ self.assertEqual(0, state.result.pdr_interval.measured_high.loss_count)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_high.transmit_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_high.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_high.receive_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_high.loss_fraction)
+ self.assertEqual(-1, state.phases)
+ self.assertEqual(30, state.duration)
+ self.assertEqual(0.2, state.width_goal)
+ self.assertEqual(0.0, state.packet_loss_ratio)
+ self.assertEqual(14880000, state.minimum_transmit_rate)
+ self.assertEqual(14880000, state.maximum_transmit_rate)
+
+ def test_ndrpdr_update_state_ndr_lo(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock(), mock.Mock,
+ mock.Mock()))
+ with mock.patch.object(algorithm, 'measure') as \
+ mock_measure, \
+ mock.patch.object(algorithm, '_measure_and_update_state') as \
+ mock__measure_and_update_state:
+ ndr_measured_low = ReceiveRateMeasurement(30, 10880000, 10879927,
+ 100000)
+ ndr_measured_high = ReceiveRateMeasurement(30, 12880000, 12879927,
+ 100000)
+ ndr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_low = ReceiveRateMeasurement(30, 12880000, 12879927,
+ 100000)
+ pdr_measured_high = ReceiveRateMeasurement(30, 14880000, 14879927,
+ 100000)
+ pdr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_interval = ReceiveRateInterval(ndr_measured_low,
+ ndr_measured_high)
+ pdr_interval = ReceiveRateInterval(pdr_measured_low,
+ pdr_measured_high)
+ starting_result = NdrPdrResult(ndr_interval, pdr_interval)
+ ending_result = NdrPdrResult(pdr_interval, pdr_interval)
+ mock_measure.return_value = ReceiveRateMeasurement(1, 14880000,
+ 14879927, 0)
+ mock__measure_and_update_state.return_value = \
+ MultipleLossRatioSearch.ProgressState(ending_result, -1, 30,
+ 0.2, 0.0, 14880000,
+ 14880000)
+ previous_state = MultipleLossRatioSearch.ProgressState(
+ starting_result, -1, 30, 0.005, 0.0, 100000,
+ 14880000)
+ state = algorithm.ndrpdr(previous_state)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertEqual(30, state.result.ndr_interval.measured_low.duration)
+ self.assertEqual(12880000.0,
+ state.result.ndr_interval.measured_low.target_tr)
+ self.assertEqual(12879927,
+ state.result.ndr_interval.measured_low.transmit_count)
+ self.assertEqual(100000,
+ state.result.ndr_interval.measured_low.loss_count)
+ self.assertEqual(12779927,
+ state.result.ndr_interval.measured_low.receive_count)
+ self.assertEqual(429330.9,
+ state.result.ndr_interval.measured_low.transmit_rate)
+ self.assertEqual(3333.33333,
+ state.result.ndr_interval.measured_low.loss_rate)
+ self.assertEqual(425997.56667,
+ state.result.ndr_interval.measured_low.receive_rate)
+ self.assertEqual(0.00776,
+ state.result.ndr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.ndr_interval.measured_high.duration)
+ self.assertEqual(14880000.0,
+ state.result.ndr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_high.transmit_count)
+ self.assertEqual(100000,
+ state.result.ndr_interval.measured_high.loss_count)
+ self.assertEqual(14779927,
+ state.result.ndr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_high.transmit_rate)
+ self.assertEqual(3333.33333,
+ state.result.ndr_interval.measured_high.loss_rate)
+ self.assertEqual(492664.23333,
+ state.result.ndr_interval.measured_high.receive_rate)
+ self.assertEqual(0.00672,
+ state.result.ndr_interval.measured_high.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_low.duration)
+ self.assertEqual(12880000.0,
+ state.result.pdr_interval.measured_low.target_tr)
+ self.assertEqual(12879927,
+ state.result.pdr_interval.measured_low.transmit_count)
+ self.assertEqual(100000,
+ state.result.pdr_interval.measured_low.loss_count)
+ self.assertEqual(12779927,
+ state.result.pdr_interval.measured_low.receive_count)
+ self.assertEqual(429330.9,
+ state.result.pdr_interval.measured_low.transmit_rate)
+ self.assertEqual(3333.33333,
+ state.result.pdr_interval.measured_low.loss_rate)
+ self.assertEqual(425997.56667,
+ state.result.pdr_interval.measured_low.receive_rate)
+ self.assertEqual(0.00776,
+ state.result.pdr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_high.duration)
+ self.assertEqual(14880000,
+ state.result.pdr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_high.transmit_count)
+ self.assertEqual(100000,
+ state.result.pdr_interval.measured_high.loss_count)
+ self.assertEqual(14779927,
+ state.result.pdr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_high.transmit_rate)
+ self.assertEqual(3333.33333,
+ state.result.pdr_interval.measured_high.loss_rate)
+ self.assertEqual(492664.23333,
+ state.result.pdr_interval.measured_high.receive_rate)
+ self.assertEqual(0.00672,
+ state.result.pdr_interval.measured_high.loss_fraction)
+ self.assertEqual(-1, state.phases)
+ self.assertEqual(30, state.duration)
+ self.assertEqual(0.2, state.width_goal)
+ self.assertEqual(0.0, state.packet_loss_ratio)
+ self.assertEqual(14880000, state.minimum_transmit_rate)
+ self.assertEqual(14880000, state.maximum_transmit_rate)
+
+ def test_ndrpdr_update_state_pdr_lo(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock(), mock.Mock,
+ mock.Mock()))
+ with mock.patch.object(algorithm, 'measure') as \
+ mock_measure, \
+ mock.patch.object(algorithm, '_measure_and_update_state') as \
+ mock__measure_and_update_state:
+ ndr_measured_low = ReceiveRateMeasurement(30, 10880000, 10879927,
+ 0)
+ ndr_measured_high = ReceiveRateMeasurement(30, 12880000, 12879927,
+ 0)
+ ndr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_low = ReceiveRateMeasurement(30, 12880000, 12879927,
+ 100000)
+ pdr_measured_high = ReceiveRateMeasurement(30, 14880000, 14879927,
+ 100000)
+ pdr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_interval = ReceiveRateInterval(ndr_measured_low,
+ ndr_measured_high)
+ pdr_interval = ReceiveRateInterval(pdr_measured_low,
+ pdr_measured_high)
+ starting_result = NdrPdrResult(ndr_interval, pdr_interval)
+ ending_result = NdrPdrResult(pdr_interval, pdr_interval)
+ mock_measure.return_value = ReceiveRateMeasurement(1, 14880000,
+ 14879927, 0)
+ mock__measure_and_update_state.return_value = \
+ MultipleLossRatioSearch.ProgressState(ending_result, -1, 30,
+ 0.2, 0.0, 14880000,
+ 14880000)
+ previous_state = MultipleLossRatioSearch.ProgressState(
+ starting_result, -1, 30, 0.005, 0.0, 100000,
+ 14880000)
+ state = algorithm.ndrpdr(previous_state)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertEqual(30, state.result.ndr_interval.measured_low.duration)
+ self.assertEqual(12880000.0,
+ state.result.ndr_interval.measured_low.target_tr)
+ self.assertEqual(12879927,
+ state.result.ndr_interval.measured_low.transmit_count)
+ self.assertEqual(100000,
+ state.result.ndr_interval.measured_low.loss_count)
+ self.assertEqual(12779927,
+ state.result.ndr_interval.measured_low.receive_count)
+ self.assertEqual(429330.9,
+ state.result.ndr_interval.measured_low.transmit_rate)
+ self.assertEqual(3333.33333,
+ state.result.ndr_interval.measured_low.loss_rate)
+ self.assertEqual(425997.56667,
+ state.result.ndr_interval.measured_low.receive_rate)
+ self.assertEqual(0.00776,
+ state.result.ndr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.ndr_interval.measured_high.duration)
+ self.assertEqual(14880000.0,
+ state.result.ndr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_high.transmit_count)
+ self.assertEqual(100000,
+ state.result.ndr_interval.measured_high.loss_count)
+ self.assertEqual(14779927,
+ state.result.ndr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_high.transmit_rate)
+ self.assertEqual(3333.33333,
+ state.result.ndr_interval.measured_high.loss_rate)
+ self.assertEqual(492664.23333,
+ state.result.ndr_interval.measured_high.receive_rate)
+ self.assertEqual(0.00672,
+ state.result.ndr_interval.measured_high.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_low.duration)
+ self.assertEqual(12880000.0,
+ state.result.pdr_interval.measured_low.target_tr)
+ self.assertEqual(12879927,
+ state.result.pdr_interval.measured_low.transmit_count)
+ self.assertEqual(100000,
+ state.result.pdr_interval.measured_low.loss_count)
+ self.assertEqual(12779927,
+ state.result.pdr_interval.measured_low.receive_count)
+ self.assertEqual(429330.9,
+ state.result.pdr_interval.measured_low.transmit_rate)
+ self.assertEqual(3333.33333,
+ state.result.pdr_interval.measured_low.loss_rate)
+ self.assertEqual(425997.56667,
+ state.result.pdr_interval.measured_low.receive_rate)
+ self.assertEqual(0.00776,
+ state.result.pdr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_high.duration)
+ self.assertEqual(14880000,
+ state.result.pdr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_high.transmit_count)
+ self.assertEqual(100000,
+ state.result.pdr_interval.measured_high.loss_count)
+ self.assertEqual(14779927,
+ state.result.pdr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_high.transmit_rate)
+ self.assertEqual(3333.33333,
+ state.result.pdr_interval.measured_high.loss_rate)
+ self.assertEqual(492664.23333,
+ state.result.pdr_interval.measured_high.receive_rate)
+ self.assertEqual(0.00672,
+ state.result.pdr_interval.measured_high.loss_fraction)
+ self.assertEqual(-1, state.phases)
+ self.assertEqual(30, state.duration)
+ self.assertEqual(0.2, state.width_goal)
+ self.assertEqual(0.0, state.packet_loss_ratio)
+ self.assertEqual(14880000, state.minimum_transmit_rate)
+ self.assertEqual(14880000, state.maximum_transmit_rate)
+
+ def test_ndrpdr_update_state_pdr_lo_duration(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock(), mock.Mock,
+ mock.Mock()))
+ with mock.patch.object(algorithm, 'measure') as \
+ mock_measure, \
+ mock.patch.object(algorithm, '_measure_and_update_state') as \
+ mock__measure_and_update_state:
+ ndr_measured_low = ReceiveRateMeasurement(30, 10880000, 10879927,
+ 0)
+ ndr_measured_high = ReceiveRateMeasurement(30, 12880000, 12879927,
+ 0)
+ ndr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_low = ReceiveRateMeasurement(30, 12880000, 12879927,
+ 100000)
+ pdr_measured_high = ReceiveRateMeasurement(30, 14880000, 14879927,
+ 100000)
+ pdr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_interval = ReceiveRateInterval(ndr_measured_low,
+ ndr_measured_high)
+ pdr_interval = ReceiveRateInterval(pdr_measured_low,
+ pdr_measured_high)
+ starting_result = NdrPdrResult(ndr_interval, pdr_interval)
+ ending_result = NdrPdrResult(pdr_interval, pdr_interval)
+ mock_measure.return_value = ReceiveRateMeasurement(1, 14880000,
+ 14879927, 0)
+ mock__measure_and_update_state.return_value = \
+ MultipleLossRatioSearch.ProgressState(ending_result, -1, 30,
+ 0.2, 0.0, 14880000,
+ 14880000)
+ previous_state = MultipleLossRatioSearch.ProgressState(
+ starting_result, -1, 50, 0.005, 0.0, 14880000,
+ 14880000)
+ state = algorithm.ndrpdr(previous_state)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertEqual(30, state.result.ndr_interval.measured_low.duration)
+ self.assertEqual(12880000.0,
+ state.result.ndr_interval.measured_low.target_tr)
+ self.assertEqual(12879927,
+ state.result.ndr_interval.measured_low.transmit_count)
+ self.assertEqual(100000,
+ state.result.ndr_interval.measured_low.loss_count)
+ self.assertEqual(12779927,
+ state.result.ndr_interval.measured_low.receive_count)
+ self.assertEqual(429330.9,
+ state.result.ndr_interval.measured_low.transmit_rate)
+ self.assertEqual(3333.33333,
+ state.result.ndr_interval.measured_low.loss_rate)
+ self.assertEqual(425997.56667,
+ state.result.ndr_interval.measured_low.receive_rate)
+ self.assertEqual(0.00776,
+ state.result.ndr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.ndr_interval.measured_high.duration)
+ self.assertEqual(14880000.0,
+ state.result.ndr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_high.transmit_count)
+ self.assertEqual(100000,
+ state.result.ndr_interval.measured_high.loss_count)
+ self.assertEqual(14779927,
+ state.result.ndr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_high.transmit_rate)
+ self.assertEqual(3333.33333,
+ state.result.ndr_interval.measured_high.loss_rate)
+ self.assertEqual(492664.23333,
+ state.result.ndr_interval.measured_high.receive_rate)
+ self.assertEqual(0.00672,
+ state.result.ndr_interval.measured_high.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_low.duration)
+ self.assertEqual(12880000.0,
+ state.result.pdr_interval.measured_low.target_tr)
+ self.assertEqual(12879927,
+ state.result.pdr_interval.measured_low.transmit_count)
+ self.assertEqual(100000,
+ state.result.pdr_interval.measured_low.loss_count)
+ self.assertEqual(12779927,
+ state.result.pdr_interval.measured_low.receive_count)
+ self.assertEqual(429330.9,
+ state.result.pdr_interval.measured_low.transmit_rate)
+ self.assertEqual(3333.33333,
+ state.result.pdr_interval.measured_low.loss_rate)
+ self.assertEqual(425997.56667,
+ state.result.pdr_interval.measured_low.receive_rate)
+ self.assertEqual(0.00776,
+ state.result.pdr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_high.duration)
+ self.assertEqual(14880000,
+ state.result.pdr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_high.transmit_count)
+ self.assertEqual(100000,
+ state.result.pdr_interval.measured_high.loss_count)
+ self.assertEqual(14779927,
+ state.result.pdr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_high.transmit_rate)
+ self.assertEqual(3333.33333,
+ state.result.pdr_interval.measured_high.loss_rate)
+ self.assertEqual(492664.23333,
+ state.result.pdr_interval.measured_high.receive_rate)
+ self.assertEqual(0.00672,
+ state.result.pdr_interval.measured_high.loss_fraction)
+ self.assertEqual(-1, state.phases)
+ self.assertEqual(30, state.duration)
+ self.assertEqual(0.2, state.width_goal)
+ self.assertEqual(0.0, state.packet_loss_ratio)
+ self.assertEqual(14880000, state.minimum_transmit_rate)
+ self.assertEqual(14880000, state.maximum_transmit_rate)
+
+ def test_ndrpdr_update_state_pdr_hi(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock(), mock.Mock,
+ mock.Mock()))
+ with mock.patch.object(algorithm, 'measure') as \
+ mock_measure, \
+ mock.patch.object(algorithm, '_measure_and_update_state') as \
+ mock__measure_and_update_state:
+ ndr_measured_low = ReceiveRateMeasurement(30, 10880000, 10879927,
+ 0)
+ ndr_measured_high = ReceiveRateMeasurement(30, 12880000, 12879927,
+ 100000)
+ ndr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_low = ReceiveRateMeasurement(30, 12880000, 12879927,
+ 0)
+ pdr_measured_high = ReceiveRateMeasurement(30, 13880000, 14879927,
+ 0)
+ pdr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_interval = ReceiveRateInterval(ndr_measured_low,
+ ndr_measured_high)
+ pdr_interval = ReceiveRateInterval(pdr_measured_low,
+ pdr_measured_high)
+ starting_result = NdrPdrResult(ndr_interval, pdr_interval)
+ ending_result = NdrPdrResult(ndr_interval, ndr_interval)
+ mock_measure.return_value = ReceiveRateMeasurement(1, 14880000,
+ 14879927, 0)
+ mock__measure_and_update_state.return_value = \
+ MultipleLossRatioSearch.ProgressState(ending_result, -1, 30,
+ 0.2, 0.0, 14880000,
+ 14880000)
+ previous_state = MultipleLossRatioSearch.ProgressState(
+ starting_result, -1, 30, 0.005, 0.0, 100000,
+ 14880000)
+ state = algorithm.ndrpdr(previous_state)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertEqual(30, state.result.ndr_interval.measured_low.duration)
+ self.assertEqual(10880000.0,
+ state.result.ndr_interval.measured_low.target_tr)
+ self.assertEqual(10879927,
+ state.result.ndr_interval.measured_low.transmit_count)
+ self.assertEqual(0,
+ state.result.ndr_interval.measured_low.loss_count)
+ self.assertEqual(10879927,
+ state.result.ndr_interval.measured_low.receive_count)
+ self.assertEqual(362664.23333,
+ state.result.ndr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_low.loss_rate)
+ self.assertEqual(362664.23333,
+ state.result.ndr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.ndr_interval.measured_high.duration)
+ self.assertEqual(12880000.0,
+ state.result.ndr_interval.measured_high.target_tr)
+ self.assertEqual(12879927,
+ state.result.ndr_interval.measured_high.transmit_count)
+ self.assertEqual(100000,
+ state.result.ndr_interval.measured_high.loss_count)
+ self.assertEqual(12779927,
+ state.result.ndr_interval.measured_high.receive_count)
+ self.assertEqual(429330.9,
+ state.result.ndr_interval.measured_high.transmit_rate)
+ self.assertEqual(3333.33333,
+ state.result.ndr_interval.measured_high.loss_rate)
+ self.assertEqual(425997.56667,
+ state.result.ndr_interval.measured_high.receive_rate)
+ self.assertEqual(0.00776,
+ state.result.ndr_interval.measured_high.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_low.duration)
+ self.assertEqual(10880000.0,
+ state.result.pdr_interval.measured_low.target_tr)
+ self.assertEqual(10879927,
+ state.result.pdr_interval.measured_low.transmit_count)
+ self.assertEqual(0,
+ state.result.pdr_interval.measured_low.loss_count)
+ self.assertEqual(10879927,
+ state.result.pdr_interval.measured_low.receive_count)
+ self.assertEqual(362664.23333,
+ state.result.pdr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_low.loss_rate)
+ self.assertEqual(362664.23333,
+ state.result.pdr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_high.duration)
+ self.assertEqual(12880000,
+ state.result.pdr_interval.measured_high.target_tr)
+ self.assertEqual(12879927,
+ state.result.pdr_interval.measured_high.transmit_count)
+ self.assertEqual(100000,
+ state.result.pdr_interval.measured_high.loss_count)
+ self.assertEqual(12779927,
+ state.result.pdr_interval.measured_high.receive_count)
+ self.assertEqual(429330.9,
+ state.result.pdr_interval.measured_high.transmit_rate)
+ self.assertEqual(3333.33333,
+ state.result.pdr_interval.measured_high.loss_rate)
+ self.assertEqual(425997.56667,
+ state.result.pdr_interval.measured_high.receive_rate)
+ self.assertEqual(0.00776,
+ state.result.pdr_interval.measured_high.loss_fraction)
+ self.assertEqual(-1, state.phases)
+ self.assertEqual(30, state.duration)
+ self.assertEqual(0.2, state.width_goal)
+ self.assertEqual(0.0, state.packet_loss_ratio)
+ self.assertEqual(14880000, state.minimum_transmit_rate)
+ self.assertEqual(14880000, state.maximum_transmit_rate)
+
+ def test_ndrpdr_update_state_pdr_hi_duration(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock(), mock.Mock,
+ mock.Mock()))
+ with mock.patch.object(algorithm, 'measure') as \
+ mock_measure, \
+ mock.patch.object(algorithm, '_measure_and_update_state') as \
+ mock__measure_and_update_state:
+ ndr_measured_low = ReceiveRateMeasurement(30, 10880000, 10879927,
+ 0)
+ ndr_measured_high = ReceiveRateMeasurement(30, 12880000, 12879927,
+ 100000)
+ ndr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_low = ReceiveRateMeasurement(30, 12880000, 12879927,
+ 0)
+ pdr_measured_high = ReceiveRateMeasurement(30, 13880000, 14879927,
+ 0)
+ pdr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_interval = ReceiveRateInterval(ndr_measured_low,
+ ndr_measured_high)
+ pdr_interval = ReceiveRateInterval(pdr_measured_low,
+ pdr_measured_high)
+ starting_result = NdrPdrResult(ndr_interval, pdr_interval)
+ ending_result = NdrPdrResult(ndr_interval, ndr_interval)
+ mock_measure.return_value = ReceiveRateMeasurement(1, 14880000,
+ 14879927, 0)
+ mock__measure_and_update_state.return_value = \
+ MultipleLossRatioSearch.ProgressState(ending_result, -1, 30,
+ 0.2, 0.0, 14880000,
+ 14880000)
+ previous_state = MultipleLossRatioSearch.ProgressState(
+ starting_result, -1, 50, 0.005, 0.0, 100000,
+ 10880000)
+ state = algorithm.ndrpdr(previous_state)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertEqual(30, state.result.ndr_interval.measured_low.duration)
+ self.assertEqual(10880000.0,
+ state.result.ndr_interval.measured_low.target_tr)
+ self.assertEqual(10879927,
+ state.result.ndr_interval.measured_low.transmit_count)
+ self.assertEqual(0,
+ state.result.ndr_interval.measured_low.loss_count)
+ self.assertEqual(10879927,
+ state.result.ndr_interval.measured_low.receive_count)
+ self.assertEqual(362664.23333,
+ state.result.ndr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_low.loss_rate)
+ self.assertEqual(362664.23333,
+ state.result.ndr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.ndr_interval.measured_high.duration)
+ self.assertEqual(12880000.0,
+ state.result.ndr_interval.measured_high.target_tr)
+ self.assertEqual(12879927,
+ state.result.ndr_interval.measured_high.transmit_count)
+ self.assertEqual(100000,
+ state.result.ndr_interval.measured_high.loss_count)
+ self.assertEqual(12779927,
+ state.result.ndr_interval.measured_high.receive_count)
+ self.assertEqual(429330.9,
+ state.result.ndr_interval.measured_high.transmit_rate)
+ self.assertEqual(3333.33333,
+ state.result.ndr_interval.measured_high.loss_rate)
+ self.assertEqual(425997.56667,
+ state.result.ndr_interval.measured_high.receive_rate)
+ self.assertEqual(0.00776,
+ state.result.ndr_interval.measured_high.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_low.duration)
+ self.assertEqual(10880000.0,
+ state.result.pdr_interval.measured_low.target_tr)
+ self.assertEqual(10879927,
+ state.result.pdr_interval.measured_low.transmit_count)
+ self.assertEqual(0,
+ state.result.pdr_interval.measured_low.loss_count)
+ self.assertEqual(10879927,
+ state.result.pdr_interval.measured_low.receive_count)
+ self.assertEqual(362664.23333,
+ state.result.pdr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_low.loss_rate)
+ self.assertEqual(362664.23333,
+ state.result.pdr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_high.duration)
+ self.assertEqual(12880000,
+ state.result.pdr_interval.measured_high.target_tr)
+ self.assertEqual(12879927,
+ state.result.pdr_interval.measured_high.transmit_count)
+ self.assertEqual(100000,
+ state.result.pdr_interval.measured_high.loss_count)
+ self.assertEqual(12779927,
+ state.result.pdr_interval.measured_high.receive_count)
+ self.assertEqual(429330.9,
+ state.result.pdr_interval.measured_high.transmit_rate)
+ self.assertEqual(3333.33333,
+ state.result.pdr_interval.measured_high.loss_rate)
+ self.assertEqual(425997.56667,
+ state.result.pdr_interval.measured_high.receive_rate)
+ self.assertEqual(0.00776,
+ state.result.pdr_interval.measured_high.loss_fraction)
+ self.assertEqual(-1, state.phases)
+ self.assertEqual(30, state.duration)
+ self.assertEqual(0.2, state.width_goal)
+ self.assertEqual(0.0, state.packet_loss_ratio)
+ self.assertEqual(14880000, state.minimum_transmit_rate)
+ self.assertEqual(14880000, state.maximum_transmit_rate)
+
+ def test_measure(self):
+ measurer = mock.MagicMock()
+ measurer.sent = 102563094
+ measurer.loss = 30502
+ algorithm = MultipleLossRatioSearch(measurer=measurer, latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.MagicMock(),
+ mock.Mock, mock.Mock()))
+ measurement = algorithm.measure(30, 3418770.3425, True)
+ self.assertIsInstance(measurement, ReceiveRateMeasurement)
+ self.assertEqual(30, measurement.duration)
+ self.assertEqual(3418770.3425, measurement.target_tr)
+ self.assertEqual(102563094, measurement.transmit_count)
+ self.assertEqual(30502, measurement.loss_count)
+ self.assertEqual(102532592, measurement.receive_count)
+ self.assertEqual(3418769.8, measurement.transmit_rate)
+ self.assertEqual(1016.73333, measurement.loss_rate)
+ self.assertEqual(3417753.06667, measurement.receive_rate)
+ self.assertEqual(0.0003, measurement.loss_fraction)
+
+ def test_perform_additional_measurements_based_on_ndrpdr_result(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock, mock.Mock,
+ mock.Mock()))
+ result = mock.MagicMock()
+ result.ndr_interval.measured_low.target_tr.return_result = 100000
+ self.assertIsNone(
+ algorithm.perform_additional_measurements_based_on_ndrpdr_result(
+ result))
+
+ def test_display_single_bound(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ result_samples = {}
+ self.assertIsNone(
+ algorithm.display_single_bound(result_samples, 'NDR_LOWER',
+ 4857361, 64,
+ ['20/849/1069', '40/69/183']))
+ self.assertEqual(
+ {'Result_NDR_LOWER': {'bandwidth_total_Gbps': 3.264146592,
+ 'rate_total_pps': 4857361.0},
+ 'Result_stream0_NDR_LOWER': {'avg_latency': 849.0,
+ 'max_latency': 1069.0,
+ 'min_latency': 20.0},
+ 'Result_stream1_NDR_LOWER': {'avg_latency': 69.0,
+ 'max_latency': 183.0,
+ 'min_latency': 40.0}},
+ result_samples)
+
+ def test_check_ndrpdr_interval_validity(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ result_samples = {}
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 0)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 0)
+ receive_rate_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ self.assertEqual('Minimal rate loss fraction 0.0 reach target 0.0',
+ algorithm.check_ndrpdr_interval_validity(
+ result_samples, 'NDR_LOWER',
+ receive_rate_interval))
+ self.assertEqual(
+ {'Result_NDR_LOWER_packets_lost': {'packet_loss_ratio': 0.0,
+ 'packets_lost': 0.0}},
+ result_samples)
+
+ def test_check_ndrpdr_interval_validity_fail(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ result_samples = {}
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ receive_rate_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ self.assertEqual(
+ 'Minimal rate loss fraction 0.01749 does not reach target 0.005\n84965 packets lost.',
+ algorithm.check_ndrpdr_interval_validity(result_samples,
+ 'NDR_LOWER',
+ receive_rate_interval,
+ 0.005))
+ self.assertEqual({'Result_NDR_LOWER_packets_lost': {
+ 'packet_loss_ratio': 0.01749,
+ 'packets_lost': 84965.0}}, result_samples)
diff --git a/yardstick/tests/unit/network_services/helpers/vpp_helpers/test_ndr_pdr_result.py b/yardstick/tests/unit/network_services/helpers/vpp_helpers/test_ndr_pdr_result.py
new file mode 100644
index 000000000..ea9c39a03
--- /dev/null
+++ b/yardstick/tests/unit/network_services/helpers/vpp_helpers/test_ndr_pdr_result.py
@@ -0,0 +1,91 @@
+# Copyright (c) 2019 Viosoft 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.
+
+import unittest
+
+import mock
+
+from yardstick.network_services.helpers.vpp_helpers.ndr_pdr_result import \
+ NdrPdrResult
+from yardstick.network_services.helpers.vpp_helpers.receive_rate_interval import \
+ ReceiveRateInterval
+from yardstick.network_services.helpers.vpp_helpers.receive_rate_measurement import \
+ ReceiveRateMeasurement
+
+
+class TestNdrPdrResult(unittest.TestCase):
+
+ def test___init__(self):
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ starting_interval = ReceiveRateInterval(measured_low, measured_high)
+ ndrpdr_result = NdrPdrResult(starting_interval, starting_interval)
+ self.assertIsInstance(ndrpdr_result.ndr_interval, ReceiveRateInterval)
+ self.assertIsInstance(ndrpdr_result.pdr_interval, ReceiveRateInterval)
+
+ def test___init__ndr_error(self):
+ starting_interval = mock.MagicMock()
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ end_interval = ReceiveRateInterval(measured_low, measured_high)
+ with self.assertRaises(TypeError) as raised:
+ NdrPdrResult(starting_interval, end_interval)
+ self.assertIn('ndr_interval, is not a ReceiveRateInterval: ',
+ str(raised.exception))
+
+ def test___init__pdr_error(self):
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ starting_interval = ReceiveRateInterval(measured_low, measured_high)
+ end_interval = mock.MagicMock()
+ with self.assertRaises(TypeError) as raised:
+ NdrPdrResult(starting_interval, end_interval)
+ self.assertIn('pdr_interval, is not a ReceiveRateInterval: ',
+ str(raised.exception))
+
+ def test_width_in_goals(self):
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ starting_interval = ReceiveRateInterval(measured_low, measured_high)
+ ndrpdr_result = NdrPdrResult(starting_interval, starting_interval)
+ self.assertEqual('ndr 4.86887; pdr 4.86887',
+ ndrpdr_result.width_in_goals(0.005))
+
+ def test___str__(self):
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ starting_interval = ReceiveRateInterval(measured_low, measured_high)
+ ndrpdr_result = NdrPdrResult(starting_interval, starting_interval)
+ self.assertEqual(
+ 'NDR=[d=1.0,Tr=4857361.0,Df=0.01749;d=1.0,Tr=4977343.0,Df=0.0241);'
+ 'PDR=[d=1.0,Tr=4857361.0,Df=0.01749;d=1.0,Tr=4977343.0,Df=0.0241)',
+ ndrpdr_result.__str__())
+
+ def test___repr__(self):
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ starting_interval = ReceiveRateInterval(measured_low, measured_high)
+ ndrpdr_result = NdrPdrResult(starting_interval, starting_interval)
+ self.assertEqual(
+ 'NdrPdrResult(ndr_interval=ReceiveRateInterval(measured_low=' \
+ 'ReceiveRateMeasurement(duration=1.0,target_tr=4857361.0,' \
+ 'transmit_count=4857339,loss_count=84965),measured_high=' \
+ 'ReceiveRateMeasurement(duration=1.0,target_tr=4977343.0,' \
+ 'transmit_count=4977320,loss_count=119959)),pdr_interval=' \
+ 'ReceiveRateInterval(measured_low=ReceiveRateMeasurement' \
+ '(duration=1.0,target_tr=4857361.0,transmit_count=4857339,' \
+ 'loss_count=84965),measured_high=ReceiveRateMeasurement' \
+ '(duration=1.0,target_tr=4977343.0,transmit_count=4977320,' \
+ 'loss_count=119959)))',
+ ndrpdr_result.__repr__())
diff --git a/yardstick/tests/unit/network_services/helpers/vpp_helpers/test_receive_rate_interval.py b/yardstick/tests/unit/network_services/helpers/vpp_helpers/test_receive_rate_interval.py
new file mode 100644
index 000000000..bbf241613
--- /dev/null
+++ b/yardstick/tests/unit/network_services/helpers/vpp_helpers/test_receive_rate_interval.py
@@ -0,0 +1,100 @@
+# Copyright (c) 2019 Viosoft 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.
+
+import unittest
+
+import mock
+
+from yardstick.network_services.helpers.vpp_helpers.receive_rate_interval import \
+ ReceiveRateInterval
+from yardstick.network_services.helpers.vpp_helpers.receive_rate_measurement import \
+ ReceiveRateMeasurement
+
+
+class TestReceiveRateInterval(unittest.TestCase):
+
+ def test__init__(self):
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ receive_rate_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ self.assertIsInstance(receive_rate_interval.measured_low,
+ ReceiveRateMeasurement)
+ self.assertIsInstance(receive_rate_interval.measured_high,
+ ReceiveRateMeasurement)
+
+ def test__init__measured_low_error(self):
+ measured_low = mock.MagicMock()
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ with self.assertRaises(TypeError) as raised:
+ ReceiveRateInterval(measured_low, measured_high)
+ self.assertIn('measured_low is not a ReceiveRateMeasurement: ',
+ str(raised.exception))
+
+ def test__init__measured_high_error(self):
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = mock.MagicMock()
+ with self.assertRaises(TypeError) as raised:
+ ReceiveRateInterval(measured_low, measured_high)
+ self.assertIn('measured_high is not a ReceiveRateMeasurement: ',
+ str(raised.exception))
+
+ def test_sort(self):
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ receive_rate_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ self.assertIsNone(receive_rate_interval.sort())
+ self.assertEqual(119982.0, receive_rate_interval.abs_tr_width)
+ self.assertEqual(0.02411,
+ receive_rate_interval.rel_tr_width)
+
+ def test_sort_swap(self):
+ measured_low = ReceiveRateMeasurement(1, 14857361, 14857339, 184965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ receive_rate_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ self.assertIsNone(receive_rate_interval.sort())
+ self.assertEqual(9880018.0, receive_rate_interval.abs_tr_width)
+ self.assertEqual(0.66499,
+ receive_rate_interval.rel_tr_width)
+
+ def test_width_in_goals(self):
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ receive_rate_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ self.assertEqual(4.86887,
+ receive_rate_interval.width_in_goals(0.005))
+
+ def test___str__(self):
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ receive_rate_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ self.assertEqual(
+ '[d=1.0,Tr=4857361.0,Df=0.01749;d=1.0,Tr=4977343.0,Df=0.0241)',
+ receive_rate_interval.__str__())
+
+ def test___repr__(self):
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ receive_rate_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ self.assertEqual('ReceiveRateInterval(measured_low=' \
+ 'ReceiveRateMeasurement(duration=1.0,target_tr=4857361.0,' \
+ 'transmit_count=4857339,loss_count=84965),measured_high=' \
+ 'ReceiveRateMeasurement(duration=1.0,target_tr=4977343.0,' \
+ 'transmit_count=4977320,loss_count=119959))',
+ receive_rate_interval.__repr__())
diff --git a/yardstick/tests/unit/network_services/helpers/vpp_helpers/test_receive_rate_measurement.py b/yardstick/tests/unit/network_services/helpers/vpp_helpers/test_receive_rate_measurement.py
new file mode 100644
index 000000000..d4e2d7920
--- /dev/null
+++ b/yardstick/tests/unit/network_services/helpers/vpp_helpers/test_receive_rate_measurement.py
@@ -0,0 +1,44 @@
+# Copyright (c) 2019 Viosoft 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.
+
+import unittest
+
+from yardstick.network_services.helpers.vpp_helpers.receive_rate_measurement import \
+ ReceiveRateMeasurement
+
+
+class TestReceiveRateMeasurement(unittest.TestCase):
+
+ def test__init__(self):
+ measured = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ self.assertEqual(1, measured.duration)
+ self.assertEqual(4857361, measured.target_tr)
+ self.assertEqual(4857339, measured.transmit_count)
+ self.assertEqual(84965, measured.loss_count)
+ self.assertEqual(4772374, measured.receive_count)
+ self.assertEqual(4857339, measured.transmit_rate)
+ self.assertEqual(84965.0, measured.loss_rate)
+ self.assertEqual(4772374.0, measured.receive_rate)
+ self.assertEqual(0.01749, measured.loss_fraction)
+
+ def test___str__(self):
+ measured = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ self.assertEqual('d=1.0,Tr=4857361.0,Df=0.01749',
+ measured.__str__())
+
+ def test___repr__(self):
+ measured = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ self.assertEqual('ReceiveRateMeasurement(duration=1.0,' \
+ 'target_tr=4857361.0,transmit_count=4857339,loss_count=84965)',
+ measured.__repr__())
diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_sip.py b/yardstick/tests/unit/network_services/traffic_profile/test_sip.py
new file mode 100644
index 000000000..bf26ee44d
--- /dev/null
+++ b/yardstick/tests/unit/network_services/traffic_profile/test_sip.py
@@ -0,0 +1,51 @@
+# Copyright (c) 2019 Viosoft 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.
+
+import unittest
+import mock
+
+from yardstick.network_services.traffic_profile import sip
+
+
+class TestSipProfile(unittest.TestCase):
+
+ TRAFFIC_PROFILE = {
+ "schema": "nsb:traffic_profile:0.1",
+ "name": "sip",
+ "description": "Traffic profile to run sip",
+ "traffic_profile": {
+ "traffic_type": "SipProfile",
+ "frame_rate": 100, # pps
+ "duration": 10,
+ "enable_latency": False}}
+
+ def setUp(self):
+ self.sip_profile = sip.SipProfile(self.TRAFFIC_PROFILE)
+
+ def test___init__(self):
+ self.assertIsNone(self.sip_profile.generator)
+
+ def test_execute_traffic(self):
+ self.sip_profile.generator = None
+ mock_traffic_generator = mock.Mock()
+ self.sip_profile.execute_traffic(mock_traffic_generator)
+ self.assertIsNotNone(self.sip_profile.generator)
+
+ def test_is_ended_true(self):
+ self.sip_profile.generator = mock.Mock(return_value=True)
+ self.assertTrue(self.sip_profile.is_ended())
+
+ def test_is_ended_false(self):
+ self.sip_profile.generator = None
+ self.assertFalse(self.sip_profile.is_ended())
diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_vpp_rfc2544.py b/yardstick/tests/unit/network_services/traffic_profile/test_vpp_rfc2544.py
index 4e5a0f708..8ad17b547 100644
--- a/yardstick/tests/unit/network_services/traffic_profile/test_vpp_rfc2544.py
+++ b/yardstick/tests/unit/network_services/traffic_profile/test_vpp_rfc2544.py
@@ -18,8 +18,17 @@ from trex_stl_lib import trex_stl_packet_builder_scapy
from trex_stl_lib import trex_stl_streams
from yardstick.common import constants
+from yardstick.network_services.helpers.vpp_helpers.multiple_loss_ratio_search import \
+ MultipleLossRatioSearch
+from yardstick.network_services.helpers.vpp_helpers.ndr_pdr_result import \
+ NdrPdrResult
+from yardstick.network_services.helpers.vpp_helpers.receive_rate_interval import \
+ ReceiveRateInterval
+from yardstick.network_services.helpers.vpp_helpers.receive_rate_measurement import \
+ ReceiveRateMeasurement
from yardstick.network_services.traffic_profile import base as tp_base
from yardstick.network_services.traffic_profile import rfc2544, vpp_rfc2544
+from yardstick.network_services.traffic_profile.rfc2544 import PortPgIDMap
from yardstick.tests.unit import base
@@ -129,6 +138,7 @@ class TestVppRFC2544Profile(base.BaseUnitTestCase):
self.assertEqual(vpp_rfc2544_profile.max_rate,
vpp_rfc2544_profile.rate)
self.assertEqual(0, vpp_rfc2544_profile.min_rate)
+ self.assertEqual(2, vpp_rfc2544_profile.number_of_intermediate_phases)
self.assertEqual(30, vpp_rfc2544_profile.duration)
self.assertEqual(0.1, vpp_rfc2544_profile.precision)
self.assertEqual(1.0, vpp_rfc2544_profile.lower_bound)
@@ -287,6 +297,7 @@ class TestVppRFC2544Profile(base.BaseUnitTestCase):
vpp_rfc2544_profile = vpp_rfc2544.VppRFC2544Profile(
self.TRAFFIC_PROFILE_MAX_RATE)
vpp_rfc2544_profile.init_queue(mock.MagicMock())
+ vpp_rfc2544_profile.pkt_size = 64
vpp_rfc2544_profile.params = {
'downlink_0': 'profile1',
'uplink_0': 'profile2'}
@@ -480,6 +491,7 @@ class TestVppRFC2544Profile(base.BaseUnitTestCase):
mock_latency.side_effect = ['latency1', 'latency2']
vpp_rfc2544_profile = vpp_rfc2544.VppRFC2544Profile(
self.TRAFFIC_PROFILE_MAX_RATE)
+ vpp_rfc2544_profile.pkt_size = 64
vpp_rfc2544_profile.port_pg_id = rfc2544.PortPgIDMap()
vpp_rfc2544_profile.port_pg_id.add_port(1)
with mock.patch.object(vpp_rfc2544_profile, '_create_single_packet') as \
@@ -523,10 +535,69 @@ class TestVppRFC2544Profile(base.BaseUnitTestCase):
def test_binary_search_with_optimized(self):
vpp_rfc2544_profile = vpp_rfc2544.VppRFC2544Profile(
self.TRAFFIC_PROFILE)
+ vpp_rfc2544_profile.pkt_size = 64
+ vpp_rfc2544_profile.init_queue(mock.MagicMock())
mock_generator = mock.MagicMock()
- self.assertIsNone(
- vpp_rfc2544_profile.binary_search_with_optimized(mock_generator,
- 30, 720, ''))
+ mock_generator.vnfd_helper.interfaces = [
+ {"name": "xe0"}, {"name": "xe0"}
+ ]
+
+ vpp_rfc2544_profile.ports = [0, 1]
+ vpp_rfc2544_profile.port_pg_id = PortPgIDMap()
+ vpp_rfc2544_profile.port_pg_id.add_port(0)
+ vpp_rfc2544_profile.port_pg_id.add_port(1)
+ vpp_rfc2544_profile.profiles = mock.MagicMock()
+ vpp_rfc2544_profile.test_data = mock.MagicMock()
+ vpp_rfc2544_profile.queue = mock.MagicMock()
+
+ with mock.patch.object(MultipleLossRatioSearch, 'measure') as \
+ mock_measure, \
+ mock.patch.object(MultipleLossRatioSearch, 'ndrpdr') as \
+ mock_ndrpdr:
+ measured_low = ReceiveRateMeasurement(1, 14880000, 14879927, 0)
+ measured_high = ReceiveRateMeasurement(1, 14880000, 14879927, 0)
+ measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ starting_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ starting_result = NdrPdrResult(starting_interval,
+ starting_interval)
+ mock_measure.return_value = ReceiveRateMeasurement(1, 14880000,
+ 14879927, 0)
+ mock_ndrpdr.return_value = MultipleLossRatioSearch.ProgressState(
+ starting_result, 2, 30, 0.005, 0.0,
+ 4857361, 4977343)
+
+ result_samples = vpp_rfc2544_profile.binary_search_with_optimized(
+ traffic_generator=mock_generator, duration=30,
+ timeout=720,
+ test_data={})
+
+ expected = {'Result_NDR_LOWER': {'bandwidth_total_Gbps': 9.999310944,
+ 'rate_total_pps': 14879927.0},
+ 'Result_NDR_UPPER': {'bandwidth_total_Gbps': 9.999310944,
+ 'rate_total_pps': 14879927.0},
+ 'Result_NDR_packets_lost': {'packet_loss_ratio': 0.0,
+ 'packets_lost': 0.0},
+ 'Result_PDR_LOWER': {'bandwidth_total_Gbps': 9.999310944,
+ 'rate_total_pps': 14879927.0},
+ 'Result_PDR_UPPER': {'bandwidth_total_Gbps': 9.999310944,
+ 'rate_total_pps': 14879927.0},
+ 'Result_PDR_packets_lost': {'packet_loss_ratio': 0.0,
+ 'packets_lost': 0.0},
+ 'Result_stream0_NDR_LOWER': {'avg_latency': 3081.0,
+ 'max_latency': 3962.0,
+ 'min_latency': 1000.0},
+ 'Result_stream0_PDR_LOWER': {'avg_latency': 3081.0,
+ 'max_latency': 3962.0,
+ 'min_latency': 1000.0},
+ 'Result_stream1_NDR_LOWER': {'avg_latency': 3149.0,
+ 'max_latency': 3730.0,
+ 'min_latency': 500.0},
+ 'Result_stream1_PDR_LOWER': {'avg_latency': 3149.0,
+ 'max_latency': 3730.0,
+ 'min_latency': 500.0}}
+ self.assertEqual(expected, result_samples)
def test_binary_search(self):
vpp_rfc2544_profile = vpp_rfc2544.VppRFC2544Profile(
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_ipsec_vnf.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_ipsec_vnf.py
new file mode 100644
index 000000000..00dc4a5d1
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_ipsec_vnf.py
@@ -0,0 +1,2151 @@
+# Copyright (c) 2019 Viosoft 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.
+
+import unittest
+from multiprocessing import Process
+
+import mock
+
+from yardstick.benchmark.contexts import base as ctx_base
+from yardstick.common import utils
+from yardstick.network_services.helpers import cpu
+from yardstick.network_services.nfvi.resource import ResourceProfile
+from yardstick.network_services.vnf_generic.vnf import ipsec_vnf, vpp_helpers
+from yardstick.network_services.vnf_generic.vnf.base import VnfdHelper
+from yardstick.network_services.vnf_generic.vnf.ipsec_vnf import CryptoAlg, \
+ IntegAlg, VipsecApproxSetupEnvHelper
+from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import \
+ mock_ssh
+
+SSH_HELPER = 'yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper'
+
+NAME = 'vnf__1'
+
+
+class TestCryptoAlg(unittest.TestCase):
+
+ def test__init__(self):
+ encr_alg = CryptoAlg.AES_GCM_128
+ self.assertEqual('aes-gcm-128', encr_alg.alg_name)
+ self.assertEqual('AES-GCM', encr_alg.scapy_name)
+ self.assertEqual(20, encr_alg.key_len)
+
+
+class TestIntegAlg(unittest.TestCase):
+
+ def test__init__(self):
+ auth_alg = IntegAlg.AES_GCM_128
+ self.assertEqual('aes-gcm-128', auth_alg.alg_name)
+ self.assertEqual('AES-GCM', auth_alg.scapy_name)
+ self.assertEqual(20, auth_alg.key_len)
+
+
+@mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.Process")
+class TestVipsecApproxVnf(unittest.TestCase):
+ VNFD = {'vnfd:vnfd-catalog':
+ {'vnfd':
+ [{
+ "benchmark": {
+ "kpi": [
+ "packets_in",
+ "packets_fwd",
+ "packets_dropped"
+ ]
+ },
+ "connection-point": [
+ {
+ "name": "xe0",
+ "type": "VPORT"
+ },
+ {
+ "name": "xe1",
+ "type": "VPORT"
+ }
+ ],
+ "description": "VPP IPsec",
+ "id": "VipsecApproxVnf",
+ "mgmt-interface": {
+ "ip": "10.10.10.101",
+ "password": "r00t",
+ "user": "root",
+ "vdu-id": "ipsecvnf-baremetal"
+ },
+ "name": "IpsecVnf",
+ "short-name": "IpsecVnf",
+ "vdu": [
+ {
+ "description": "VPP Ipsec",
+ "external-interface": [
+ {
+ "name": "xe0",
+ "virtual-interface": {
+ "dpdk_port_num": 0,
+ "driver": "igb_uio",
+ "dst_ip": "192.168.100.1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "ifname": "xe0",
+ "local_ip": "192.168.100.2",
+ "local_mac": "90:e2:ba:7c:41:a8",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "vnf__0",
+ "peer_ifname": "xe0",
+ "peer_intf": {
+ "dpdk_port_num": 0,
+ "driver": "igb_uio",
+ "dst_ip": "192.168.100.2",
+ "dst_mac": "90:e2:ba:7c:41:a8",
+ "ifname": "xe0",
+ "local_ip": "192.168.100.1",
+ "local_mac": "90:e2:ba:7c:30:e8",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "tg__0",
+ "peer_ifname": "xe0",
+ "peer_name": "vnf__0",
+ "vld_id": "uplink_0",
+ "vpci": "0000:81:00.0"
+ },
+ "peer_name": "tg__0",
+ "vld_id": "uplink_0",
+ "vpci": "0000:ff:06.0"
+ },
+ "vnfd-connection-point-ref": "xe0"
+ },
+ {
+ "name": "xe1",
+ "virtual-interface": {
+ "dpdk_port_num": 1,
+ "driver": "igb_uio",
+ "dst_ip": "1.1.1.2",
+ "dst_mac": "0a:b1:ec:fd:a2:66",
+ "ifname": "xe1",
+ "local_ip": "1.1.1.1",
+ "local_mac": "4e:90:85:d3:c5:13",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "vnf__0",
+ "peer_ifname": "xe1",
+ "peer_intf": {
+ "driver": "igb_uio",
+ "dst_ip": "1.1.1.1",
+ "dst_mac": "4e:90:85:d3:c5:13",
+ "ifname": "xe1",
+ "local_ip": "1.1.1.2",
+ "local_mac": "0a:b1:ec:fd:a2:66",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "vnf__1",
+ "peer_ifname": "xe1",
+ "peer_name": "vnf__0",
+ "vld_id": "ciphertext",
+ "vpci": "0000:00:07.0"
+ },
+ "peer_name": "vnf__1",
+ "vld_id": "ciphertext",
+ "vpci": "0000:ff:07.0"
+ },
+ "vnfd-connection-point-ref": "xe1"
+ }
+ ],
+ "id": "ipsecvnf-baremetal",
+ "name": "ipsecvnf-baremetal",
+ "routing_table": []
+ }
+ ]
+ }
+ ]}}
+
+ VNFD_ERROR = {'vnfd:vnfd-catalog':
+ {'vnfd':
+ [{
+ "benchmark": {
+ "kpi": [
+ "packets_in",
+ "packets_fwd",
+ "packets_dropped"
+ ]
+ },
+ "connection-point": [
+ {
+ "name": "xe0",
+ "type": "VPORT"
+ },
+ {
+ "name": "xe1",
+ "type": "VPORT"
+ }
+ ],
+ "description": "VPP IPsec",
+ "id": "VipsecApproxVnf",
+ "mgmt-interface": {
+ "ip": "10.10.10.101",
+ "password": "r00t",
+ "user": "root",
+ "vdu-id": "ipsecvnf-baremetal"
+ },
+ "name": "IpsecVnf",
+ "short-name": "IpsecVnf",
+ "vdu": [
+ {
+ "description": "VPP Ipsec",
+ "external-interface": [
+ {
+ "name": "xe0",
+ "virtual-interface": {
+ "dpdk_port_num": 0,
+ "driver": "igb_uio",
+ "dst_ip": "192.168.100.1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "ifname": "xe0",
+ "local_ip": "192.168.100.2",
+ "local_mac": "90:e2:ba:7c:41:a8",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "vnf__0",
+ "peer_ifname": "xe0",
+ "peer_intf": {
+ "dpdk_port_num": 0,
+ "driver": "igb_uio",
+ "dst_ip": "192.168.100.2",
+ "dst_mac": "90:e2:ba:7c:41:a8",
+ "ifname": "xe0",
+ "local_ip": "192.168.100.1",
+ "local_mac": "90:e2:ba:7c:30:e8",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "tg__0",
+ "peer_ifname": "xe0",
+ "peer_name": "vnf__0",
+ "vld_id": "uplink_0",
+ "vpci": "0000:81:00.0"
+ },
+ "peer_name": "tg__0",
+ "vld_id": "uplink_1",
+ "vpci": "0000:ff:06.0"
+ },
+ "vnfd-connection-point-ref": "xe0"
+ },
+ {
+ "name": "xe1",
+ "virtual-interface": {
+ "dpdk_port_num": 1,
+ "driver": "igb_uio",
+ "dst_ip": "1.1.1.2",
+ "dst_mac": "0a:b1:ec:fd:a2:66",
+ "ifname": "xe1",
+ "local_ip": "1.1.1.1",
+ "local_mac": "4e:90:85:d3:c5:13",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "vnf__1",
+ "peer_ifname": "xe1",
+ "peer_intf": {
+ "driver": "igb_uio",
+ "dst_ip": "1.1.1.1",
+ "dst_mac": "4e:90:85:d3:c5:13",
+ "ifname": "xe1",
+ "local_ip": "1.1.1.2",
+ "local_mac": "0a:b1:ec:fd:a2:66",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "vnf__1",
+ "peer_ifname": "xe1",
+ "peer_name": "vnf__0",
+ "vld_id": "ciphertext",
+ "vpci": "0000:00:07.0"
+ },
+ "peer_name": "vnf__1",
+ "vld_id": "ciphertext",
+ "vpci": "0000:ff:07.0"
+ },
+ "vnfd-connection-point-ref": "xe1"
+ }
+ ],
+ "id": "ipsecvnf-baremetal",
+ "name": "ipsecvnf-baremetal",
+ "routing_table": []
+ }
+ ]
+ }
+ ]}}
+
+ scenario_cfg = {
+ "nodes": {
+ "tg__0": "trafficgen.yardstick-5486cc2f",
+ "vnf__0": "vnf0.yardstick-5486cc2f",
+ "vnf__1": "vnf1.yardstick-5486cc2f"
+ },
+ "options": {
+ "flow": {
+ "count": 1,
+ "dst_ip": [
+ "20.0.0.0-20.0.0.100"
+ ],
+ "src_ip": [
+ "10.0.0.0-10.0.0.100"
+ ]
+ },
+ "framesize": {
+ "downlink": {
+ "64B": 100
+ },
+ "uplink": {
+ "64B": 100
+ }
+ },
+ "rfc2544": {
+ "allowed_drop_rate": "0.0 - 0.005"
+ },
+ "tg__0": {
+ "collectd": {
+ "interval": 1
+ },
+ "queues_per_port": 7
+ },
+ "traffic_type": 4,
+ "vnf__0": {
+ "collectd": {
+ "interval": 1
+ },
+ "vnf_config": {
+ "crypto_type": "SW_cryptodev",
+ "rxq": 1,
+ "worker_config": "1C/1T",
+ "worker_threads": 4
+ }
+ },
+ "vnf__1": {
+ "collectd": {
+ "interval": 1
+ },
+ "vnf_config": {
+ "crypto_type": "SW_cryptodev",
+ "rxq": 1,
+ "worker_config": "1C/1T",
+ "worker_threads": 4
+ }
+ },
+ "vpp_config": {
+ "crypto_algorithms": "aes-gcm",
+ "tunnel": 1
+ }
+ },
+ "runner": {
+ "duration": 500,
+ "interval": 10,
+ "object":
+ "yardstick.benchmark.scenarios.networking.vnf_generic.NetworkServiceTestCase",
+ "output_config": {
+ "DEFAULT": {
+ "debug": "False",
+ "dispatcher": [
+ "influxdb"
+ ]
+ },
+ "dispatcher_file": {
+ "debug": "False",
+ "dispatcher": "influxdb",
+ "file_path": "/tmp/yardstick.out"
+ },
+ "dispatcher_http": {
+ "debug": "False",
+ "dispatcher": "influxdb",
+ "target": "http://127.0.0.1:8000/results",
+ "timeout": "20"
+ },
+ "dispatcher_influxdb": {
+ "db_name": "yardstick",
+ "debug": "False",
+ "dispatcher": "influxdb",
+ "password": "r00t",
+ "target": "http://192.168.100.3:8086",
+ "timeout": "20",
+ "username": "root"
+ },
+ "nsb": {
+ "bin_path": "/opt/nsb_bin",
+ "debug": "False",
+ "dispatcher": "influxdb",
+ "trex_client_lib": "/opt/nsb_bin/trex_client/stl",
+ "trex_path": "/opt/nsb_bin/trex/scripts"
+ }
+ },
+ "runner_id": 1105,
+ "type": "Duration"
+ },
+ "task_id": "5486cc2f-d4d3-4feb-b0df-5e0bcd584c9e",
+ "task_path": "samples/vnf_samples/nsut/ipsec",
+ "tc": "tc_baremetal_rfc2544_ipv4_1flow_sw_aesgcm_4cores_64B_trex",
+ "topology": "vpp-tg-topology-2.yaml",
+ "traffic_profile": "../../traffic_profiles/ipv4_throughput_latency_vpp.yaml",
+ "type": "NSPerf"
+ }
+
+ context_cfg = {
+ "networks": {},
+ "nodes": {
+ "tg__0": {
+ "VNF model": "../../vnf_descriptors/tg_vpp_tpl.yaml",
+ "ctx_type": "Node",
+ "interfaces": {
+ "xe0": {
+ "dpdk_port_num": 0,
+ "driver": "igb_uio",
+ "dst_ip": "192.168.100.2",
+ "dst_mac": "90:e2:ba:7c:41:a8",
+ "ifname": "xe0",
+ "local_ip": "192.168.100.1",
+ "local_mac": "90:e2:ba:7c:30:e8",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "tg__0",
+ "peer_ifname": "xe0",
+ "peer_intf": {
+ "dpdk_port_num": 0,
+ "driver": "igb_uio",
+ "dst_ip": "192.168.100.1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "ifname": "xe0",
+ "local_ip": "192.168.100.2",
+ "local_mac": "90:e2:ba:7c:41:a8",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "vnf__0",
+ "peer_ifname": "xe0",
+ "peer_name": "tg__0",
+ "vld_id": "uplink_0",
+ "vpci": "0000:00:06.0"
+ },
+ "peer_name": "vnf__0",
+ "vld_id": "uplink_0",
+ "vpci": "0000:81:00.0"
+ },
+ "xe1": {
+ "dpdk_port_num": 1,
+ "driver": "igb_uio",
+ "dst_ip": "192.168.101.2",
+ "dst_mac": "90:e2:ba:7c:41:a9",
+ "ifname": "xe1",
+ "local_ip": "192.168.101.1",
+ "local_mac": "90:e2:ba:7c:30:e9",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "tg__0",
+ "peer_ifname": "xe0",
+ "peer_intf": {
+ "dpdk_port_num": 1,
+ "driver": "igb_uio",
+ "dst_ip": "192.168.101.1",
+ "dst_mac": "90:e2:ba:7c:30:e9",
+ "ifname": "xe0",
+ "local_ip": "192.168.101.2",
+ "local_mac": "90:e2:ba:7c:41:a9",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "vnf__1",
+ "peer_ifname": "xe1",
+ "peer_name": "tg__0",
+ "vld_id": "downlink_0",
+ "vpci": "0000:00:06.0"
+ },
+ "peer_name": "vnf__1",
+ "vld_id": "downlink_0",
+ "vpci": "0000:81:00.1"
+ }
+ },
+ "ip": "10.10.10.10",
+ "member-vnf-index": "1",
+ "name": "trafficgen.yardstick-5486cc2f",
+ "password": "r00t",
+ "port": 22,
+ "role": "TrafficGen",
+ "user": "root",
+ "username": "root",
+ "vnfd-id-ref": "tg__0"
+ },
+ "vnf__0": {
+ "VNF model": "../../vnf_descriptors/vpp_vnfd.yaml",
+ "ctx_type": "Node",
+ "interfaces": {
+ "xe0": {
+ "dpdk_port_num": 0,
+ "driver": "igb_uio",
+ "dst_ip": "192.168.100.1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "ifname": "xe0",
+ "local_ip": "192.168.100.2",
+ "local_mac": "90:e2:ba:7c:41:a8",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "vnf__0",
+ "peer_ifname": "xe0",
+ "peer_intf": {
+ "dpdk_port_num": 0,
+ "driver": "igb_uio",
+ "dst_ip": "192.168.100.2",
+ "dst_mac": "90:e2:ba:7c:41:a8",
+ "ifname": "xe0",
+ "local_ip": "192.168.100.1",
+ "local_mac": "90:e2:ba:7c:30:e8",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "tg__0",
+ "peer_ifname": "xe0",
+ "peer_name": "vnf__0",
+ "vld_id": "uplink_0",
+ "vpci": "0000:81:00.0"
+ },
+ "peer_name": "tg__0",
+ "vld_id": "uplink_0",
+ "vpci": "0000:00:06.0"
+ },
+ "xe1": {
+ "dpdk_port_num": 1,
+ "driver": "igb_uio",
+ "dst_ip": "1.1.1.2",
+ "dst_mac": "0a:b1:ec:fd:a2:66",
+ "ifname": "xe1",
+ "local_ip": "1.1.1.1",
+ "local_mac": "4e:90:85:d3:c5:13",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "vnf__0",
+ "peer_ifname": "xe1",
+ "peer_intf": {
+ "dpdk_port_num": 1,
+ "driver": "igb_uio",
+ "dst_ip": "1.1.1.1",
+ "dst_mac": "4e:90:85:d3:c5:13",
+ "ifname": "xe1",
+ "local_ip": "1.1.1.2",
+ "local_mac": "0a:b1:ec:fd:a2:66",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "vnf__1",
+ "peer_ifname": "xe1",
+ "peer_name": "vnf__0",
+ "vld_id": "ciphertext",
+ "vpci": "0000:00:07.0"
+ },
+ "peer_name": "vnf__1",
+ "vld_id": "ciphertext",
+ "vpci": "0000:00:07.0"
+ }
+ },
+ "ip": "10.10.10.101",
+ "member-vnf-index": "2",
+ "name": "vnf0.yardstick-5486cc2f",
+ "password": "r00t",
+ "port": 22,
+ "role": "VirtualNetworkFunction",
+ "user": "root",
+ "username": "root",
+ "vnfd-id-ref": "vnf__0"
+ },
+ "vnf__1": {
+ "VNF model": "../../vnf_descriptors/vpp_vnfd.yaml",
+ "ctx_type": "Node",
+ "interfaces": {
+ "xe0": {
+ "dpdk_port_num": 0,
+ "driver": "igb_uio",
+ "dst_ip": "192.168.101.1",
+ "dst_mac": "90:e2:ba:7c:30:e9",
+ "ifname": "xe0",
+ "local_ip": "192.168.101.2",
+ "local_mac": "90:e2:ba:7c:41:a9",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "vnf__1",
+ "peer_ifname": "xe1",
+ "peer_intf": {
+ "dpdk_port_num": 1,
+ "driver": "igb_uio",
+ "dst_ip": "192.168.101.2",
+ "dst_mac": "90:e2:ba:7c:41:a9",
+ "ifname": "xe1",
+ "local_ip": "192.168.101.1",
+ "local_mac": "90:e2:ba:7c:30:e9",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "tg__0",
+ "peer_ifname": "xe0",
+ "peer_name": "vnf__1",
+ "vld_id": "downlink_0",
+ "vpci": "0000:81:00.1"
+ },
+ "peer_name": "tg__0",
+ "vld_id": "downlink_0",
+ "vpci": "0000:00:06.0"
+ },
+ "xe1": {
+ "dpdk_port_num": 1,
+ "driver": "igb_uio",
+ "dst_ip": "1.1.1.1",
+ "dst_mac": "4e:90:85:d3:c5:13",
+ "ifname": "xe1",
+ "local_ip": "1.1.1.2",
+ "local_mac": "0a:b1:ec:fd:a2:66",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "vnf__1",
+ "peer_ifname": "xe1",
+ "peer_intf": {
+ "dpdk_port_num": 1,
+ "driver": "igb_uio",
+ "dst_ip": "1.1.1.2",
+ "dst_mac": "0a:b1:ec:fd:a2:66",
+ "ifname": "xe1",
+ "local_ip": "1.1.1.1",
+ "local_mac": "4e:90:85:d3:c5:13",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "vnf__0",
+ "peer_ifname": "xe1",
+ "peer_name": "vnf__1",
+ "vld_id": "ciphertext",
+ "vpci": "0000:00:07.0"
+ },
+ "peer_name": "vnf__0",
+ "vld_id": "ciphertext",
+ "vpci": "0000:00:07.0"
+ }
+ },
+ "ip": "10.10.10.102",
+ "member-vnf-index": "3",
+ "name": "vnf1.yardstick-5486cc2f",
+ "password": "r00t",
+ "port": 22,
+ "role": "VirtualNetworkFunction",
+ "user": "root",
+ "username": "root",
+ "vnfd-id-ref": "vnf__1"
+ }
+ }
+ }
+
+ def test___init__(self, *args):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ vipsec_vnf = ipsec_vnf.VipsecApproxVnf(NAME, vnfd)
+ self.assertIsNone(vipsec_vnf._vnf_process)
+
+ @mock.patch(SSH_HELPER)
+ def test__run(self, ssh, *args):
+ mock_ssh(ssh)
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ vipsec_vnf = ipsec_vnf.VipsecApproxVnf(NAME, vnfd)
+ vipsec_vnf._build_config = mock.MagicMock()
+ vipsec_vnf.setup_helper.kill_vnf = mock.MagicMock()
+ vipsec_vnf.setup_helper.create_ipsec_tunnels = mock.MagicMock()
+ vipsec_vnf.queue_wrapper = mock.MagicMock()
+ vipsec_vnf.scenario_helper.scenario_cfg = self.scenario_cfg
+ vipsec_vnf.vnf_cfg = {'lb_config': 'SW',
+ 'lb_count': 1,
+ 'worker_config': '1C/1T',
+ 'worker_threads': 1}
+ vipsec_vnf.all_options = {'traffic_type': '4',
+ 'topology': 'nsb_test_case.yaml'}
+ vipsec_vnf._run()
+ # vipsec_vnf.setup_helper.ssh_helper.execute.assert_called_once()
+
+ @mock.patch(SSH_HELPER)
+ def test_wait_for_instantiate(self, ssh, *args):
+ mock_ssh(ssh)
+
+ mock_process = mock.Mock(autospec=Process)
+ mock_process.is_alive.return_value = True
+ mock_process.exitcode = 432
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ vipsec_vnf = ipsec_vnf.VipsecApproxVnf(NAME, vnfd)
+ vipsec_vnf.resource_helper.resource = mock.MagicMock()
+ vipsec_vnf.setup_helper = mock.MagicMock()
+ vipsec_vnf.setup_helper.check_status.return_value = True
+ vipsec_vnf._vnf_process = mock_process
+ vipsec_vnf.WAIT_TIME = 0
+ self.assertEqual(vipsec_vnf.wait_for_instantiate(), 432)
+
+ @mock.patch(SSH_HELPER)
+ def test_wait_for_instantiate_crash(self, ssh, *args):
+ mock_ssh(ssh)
+
+ mock_process = mock.Mock(autospec=Process)
+ mock_process.is_alive.return_value = False
+ mock_process.exitcode = 432
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ vipsec_vnf = ipsec_vnf.VipsecApproxVnf(NAME, vnfd)
+ vipsec_vnf.resource_helper.resource = mock.MagicMock()
+ vipsec_vnf.setup_helper = mock.MagicMock()
+ vipsec_vnf.setup_helper.check_status.return_value = False
+ vipsec_vnf._vnf_process = mock_process
+ vipsec_vnf.WAIT_TIME = 0
+ vipsec_vnf.WAIT_TIME_FOR_SCRIPT = 0
+
+ with self.assertRaises(RuntimeError) as raised:
+ vipsec_vnf.wait_for_instantiate()
+
+ self.assertIn('VNF process died', str(raised.exception))
+
+ @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server',
+ return_value='mock_node')
+ @mock.patch.object(ipsec_vnf.VipsecApproxSetupEnvHelper,
+ 'get_vpp_statistics',
+ return_value={'packets_in': 0, 'packets_fwd': 0,
+ 'packets_dropped': 0})
+ @mock.patch(SSH_HELPER)
+ def test_collect_kpi(self, ssh, *args):
+ mock_ssh(ssh)
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ vipsec_vnf = ipsec_vnf.VipsecApproxVnf(NAME, vnfd)
+ vipsec_vnf.scenario_helper.scenario_cfg = {
+ 'nodes': {vipsec_vnf.name: "mock"}
+ }
+ result = {
+ 'collect_stats': {'packets_in': 0, 'packets_fwd': 0,
+ 'packets_dropped': 0},
+ 'physical_node': 'mock_node'
+ }
+ self.assertEqual(result, vipsec_vnf.collect_kpi())
+
+ @mock.patch.object(utils, 'find_relative_file')
+ @mock.patch(
+ "yardstick.network_services.vnf_generic.vnf.sample_vnf.Context")
+ @mock.patch(SSH_HELPER)
+ def test_instantiate(self, ssh, *args):
+ mock_ssh(ssh)
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ vipsec_vnf = ipsec_vnf.VipsecApproxVnf(NAME, vnfd)
+ vipsec_vnf.deploy_helper = mock.MagicMock()
+ vipsec_vnf.resource_helper = mock.MagicMock()
+ vipsec_vnf._build_config = mock.MagicMock()
+ vipsec_vnf.WAIT_TIME = 0
+ self.scenario_cfg.update({"nodes": {"vnf__1": ""}})
+ self.assertIsNone(vipsec_vnf.instantiate(self.scenario_cfg,
+ self.context_cfg))
+
+ @mock.patch.object(ipsec_vnf.VipsecApproxSetupEnvHelper, 'kill_vnf',
+ return_value='')
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time")
+ @mock.patch(SSH_HELPER)
+ def test_terminate(self, ssh, *args):
+ mock_ssh(ssh)
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ vipsec_vnf = ipsec_vnf.VipsecApproxVnf(NAME, vnfd)
+ vipsec_vnf._vnf_process = mock.MagicMock()
+ vipsec_vnf._vnf_process.terminate = mock.Mock()
+ self.assertIsNone(vipsec_vnf.terminate())
+
+
+class TestVipsecApproxSetupEnvHelper(unittest.TestCase):
+ ALL_OPTIONS = {
+ "flow": {
+ "count": 1,
+ "dst_ip": [
+ "20.0.0.0-20.0.0.100"
+ ],
+ "src_ip": [
+ "10.0.0.0-10.0.0.100"
+ ]
+ },
+ "framesize": {
+ "downlink": {
+ "64B": 100
+ },
+ "uplink": {
+ "64B": 100
+ }
+ },
+ "rfc2544": {
+ "allowed_drop_rate": "0.0 - 0.005"
+ },
+ "tg__0": {
+ "collectd": {
+ "interval": 1
+ },
+ "queues_per_port": 7
+ },
+ "traffic_type": 4,
+ "vnf__0": {
+ "collectd": {
+ "interval": 1
+ },
+ "vnf_config": {
+ "crypto_type": "SW_cryptodev",
+ "rxq": 1,
+ "worker_config": "1C/1T",
+ "worker_threads": 4
+ }
+ },
+ "vnf__1": {
+ "collectd": {
+ "interval": 1
+ },
+ "vnf_config": {
+ "crypto_type": "SW_cryptodev",
+ "rxq": 1,
+ "worker_config": "1C/1T",
+ "worker_threads": 4
+ }
+ },
+ "vpp_config": {
+ "crypto_algorithms": "aes-gcm",
+ "tunnel": 1
+ }
+ }
+
+ ALL_OPTIONS_CBC_ALGORITHMS = {
+ "flow": {
+ "count": 1,
+ "dst_ip": [
+ "20.0.0.0-20.0.0.100"
+ ],
+ "src_ip": [
+ "10.0.0.0-10.0.0.100"
+ ]
+ },
+ "framesize": {
+ "downlink": {
+ "64B": 100
+ },
+ "uplink": {
+ "64B": 100
+ }
+ },
+ "rfc2544": {
+ "allowed_drop_rate": "0.0 - 0.005"
+ },
+ "tg__0": {
+ "collectd": {
+ "interval": 1
+ },
+ "queues_per_port": 7
+ },
+ "traffic_type": 4,
+ "vnf__0": {
+ "collectd": {
+ "interval": 1
+ },
+ "vnf_config": {
+ "crypto_type": "SW_cryptodev",
+ "rxq": 1,
+ "worker_config": "1C/1T",
+ "worker_threads": 4
+ }
+ },
+ "vnf__1": {
+ "collectd": {
+ "interval": 1
+ },
+ "vnf_config": {
+ "crypto_type": "SW_cryptodev",
+ "rxq": 1,
+ "worker_config": "1C/1T",
+ "worker_threads": 4
+ }
+ },
+ "vpp_config": {
+ "crypto_algorithms": "cbc-sha1",
+ "tunnel": 1
+ }
+ }
+
+ ALL_OPTIONS_ERROR = {
+ "flow_error": {
+ "count": 1,
+ "dst_ip": [
+ "20.0.0.0-20.0.0.100"
+ ],
+ "src_ip": [
+ "10.0.0.0-10.0.0.100"
+ ]
+ },
+ "framesize": {
+ "downlink": {
+ "64B": 100
+ },
+ "uplink": {
+ "64B": 100
+ }
+ },
+ "rfc2544": {
+ "allowed_drop_rate": "0.0 - 0.005"
+ },
+ "tg__0": {
+ "collectd": {
+ "interval": 1
+ },
+ "queues_per_port": 7
+ },
+ "traffic_type": 4,
+ "vnf__0": {
+ "collectd": {
+ "interval": 1
+ },
+ "vnf_config": {
+ "crypto_type": "SW_cryptodev",
+ "rxq": 1,
+ "worker_config": "1C/1T",
+ "worker_threads": 4
+ }
+ },
+ "vnf__1": {
+ "collectd": {
+ "interval": 1
+ },
+ "vnf_config": {
+ "crypto_type": "SW_cryptodev",
+ "rxq": 1,
+ "worker_config": "1C/1T",
+ "worker_threads": 4
+ }
+ },
+ "vpp_config": {
+ "crypto_algorithms": "aes-gcm",
+ "tunnel": 1
+ }
+ }
+
+ OPTIONS = {
+ "collectd": {
+ "interval": 1
+ },
+ "vnf_config": {
+ "crypto_type": "SW_cryptodev",
+ "rxq": 1,
+ "worker_config": "1C/1T",
+ "worker_threads": 4
+ }
+ }
+
+ OPTIONS_HW = {
+ "collectd": {
+ "interval": 1
+ },
+ "vnf_config": {
+ "crypto_type": "HW_cryptodev",
+ "rxq": 1,
+ "worker_config": "1C/1T",
+ "worker_threads": 4
+ }
+ }
+
+ CPU_LAYOUT = {'cpuinfo': [[0, 0, 0, 0, 0, 0, 0, 0],
+ [1, 0, 0, 0, 0, 1, 1, 0],
+ [2, 1, 0, 0, 0, 2, 2, 1],
+ [3, 1, 0, 0, 0, 3, 3, 1],
+ [4, 2, 0, 0, 0, 4, 4, 2],
+ [5, 2, 0, 0, 0, 5, 5, 2],
+ [6, 3, 0, 0, 0, 6, 6, 3],
+ [7, 3, 0, 0, 0, 7, 7, 3],
+ [8, 4, 0, 0, 0, 8, 8, 4],
+ [9, 5, 0, 1, 0, 9, 9, 4],
+ [10, 6, 0, 1, 0, 10, 10, 5],
+ [11, 6, 0, 1, 0, 11, 11, 5],
+ [12, 7, 0, 1, 0, 12, 12, 6],
+ [13, 7, 0, 1, 0, 13, 13, 6],
+ [14, 8, 0, 1, 0, 14, 14, 7],
+ [15, 8, 0, 1, 0, 15, 15, 7],
+ [16, 9, 0, 1, 0, 16, 16, 8],
+ [17, 9, 0, 1, 0, 17, 17, 8]]}
+ CPU_SMT = {'cpuinfo': [[0, 0, 0, 0, 0, 0, 0, 0],
+ [1, 0, 0, 0, 0, 1, 1, 0],
+ [2, 1, 0, 0, 0, 2, 2, 1],
+ [3, 1, 0, 0, 0, 3, 3, 1],
+ [4, 2, 0, 0, 0, 4, 4, 2],
+ [5, 2, 0, 0, 0, 5, 5, 2],
+ [6, 3, 0, 0, 0, 6, 6, 3],
+ [7, 3, 0, 0, 0, 7, 7, 3],
+ [8, 4, 0, 0, 0, 8, 8, 4],
+ [9, 5, 0, 1, 0, 0, 0, 0],
+ [10, 6, 0, 1, 0, 1, 1, 0],
+ [11, 6, 0, 1, 0, 2, 2, 1],
+ [12, 7, 0, 1, 0, 3, 3, 1],
+ [13, 7, 0, 1, 0, 4, 4, 2],
+ [14, 8, 0, 1, 0, 5, 5, 2],
+ [15, 8, 0, 1, 0, 6, 6, 3],
+ [16, 9, 0, 1, 0, 7, 7, 3],
+ [17, 9, 0, 1, 0, 8, 8, 4]]}
+
+ VPP_INTERFACES_DUMP = [
+ {
+ "sw_if_index": 0,
+ "sup_sw_if_index": 0,
+ "l2_address_length": 0,
+ "l2_address": [0, 0, 0, 0, 0, 0, 0, 0],
+ "interface_name": "local0",
+ "admin_up_down": 0,
+ "link_up_down": 0,
+ "link_duplex": 0,
+ "link_speed": 0,
+ "mtu": 0,
+ "sub_id": 0,
+ "sub_dot1ad": 0,
+ "sub_number_of_tags": 0,
+ "sub_outer_vlan_id": 0,
+ "sub_inner_vlan_id": 0,
+ "sub_exact_match": 0,
+ "sub_default": 0,
+ "sub_outer_vlan_id_any": 0,
+ "sub_inner_vlan_id_any": 0,
+ "vtr_op": 0,
+ "vtr_push_dot1q": 0,
+ "vtr_tag1": 0,
+ "vtr_tag2": 0
+ },
+ {
+ "sw_if_index": 1,
+ "sup_sw_if_index": 1,
+ "l2_address_length": 6,
+ "l2_address": [144, 226, 186, 124, 65, 168, 0, 0],
+ "interface_name": "TenGigabitEthernetff/6/0",
+ "admin_up_down": 0,
+ "link_up_down": 0,
+ "link_duplex": 2,
+ "link_speed": 32,
+ "mtu": 9202,
+ "sub_id": 0,
+ "sub_dot1ad": 0,
+ "sub_number_of_tags": 0,
+ "sub_outer_vlan_id": 0,
+ "sub_inner_vlan_id": 0,
+ "sub_exact_match": 0,
+ "sub_default": 0,
+ "sub_outer_vlan_id_any": 0,
+ "sub_inner_vlan_id_any": 0,
+ "vtr_op": 0,
+ "vtr_push_dot1q": 0,
+ "vtr_tag1": 0,
+ "vtr_tag2": 0
+ },
+ {
+ "sw_if_index": 2,
+ "sup_sw_if_index": 2,
+ "l2_address_length": 6,
+ "l2_address": [78, 144, 133, 211, 197, 19, 0, 0],
+ "interface_name": "VirtualFunctionEthernetff/7/0",
+ "admin_up_down": 0,
+ "link_up_down": 0,
+ "link_duplex": 2,
+ "link_speed": 32,
+ "mtu": 9206,
+ "sub_id": 0,
+ "sub_dot1ad": 0,
+ "sub_number_of_tags": 0,
+ "sub_outer_vlan_id": 0,
+ "sub_inner_vlan_id": 0,
+ "sub_exact_match": 0,
+ "sub_default": 0,
+ "sub_outer_vlan_id_any": 0,
+ "sub_inner_vlan_id_any": 0,
+ "vtr_op": 0,
+ "vtr_push_dot1q": 0,
+ "vtr_tag1": 0,
+ "vtr_tag2": 0
+ }
+ ]
+
+ VPP_INTERFACES_STATUS = \
+ ' Name Idx State MTU (L3/IP4/IP6/MPLS)' \
+ 'Counter Count \n' \
+ 'TenGigabitEthernetff/6/0 1 up 9000/0/0/0 \n' \
+ 'VirtualFunctionEthernetff/7/0 2 up 9000/0/0/0 \n' \
+ 'ipsec0 2 up 9000/0/0/0 \n' \
+ 'local0 0 down 0/0/0/0 '
+
+ VPP_INTERFACES_STATUS_FALSE = \
+ ' Name Idx State MTU (L3/IP4/IP6/MPLS)' \
+ 'Counter Count \n' \
+ 'TenGigabitEthernetff/6/0 1 down 9000/0/0/0 \n' \
+ 'VirtualFunctionEthernetff/7/0 2 down 9000/0/0/0 \n' \
+ 'ipsec0 2 down 9000/0/0/0 \n' \
+ 'local0 0 down 0/0/0/0 '
+
+ def test__get_crypto_type(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+ self.assertEqual('SW_cryptodev',
+ ipsec_approx_setup_helper._get_crypto_type())
+
+ def test__get_crypto_algorithms(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ scenario_helper.all_options = self.ALL_OPTIONS
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+ self.assertEqual('aes-gcm',
+ ipsec_approx_setup_helper._get_crypto_algorithms())
+
+ def test__get_n_tunnels(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ scenario_helper.all_options = self.ALL_OPTIONS
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+ self.assertEqual(1, ipsec_approx_setup_helper._get_n_tunnels())
+
+ def test__get_n_connections(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ scenario_helper.all_options = self.ALL_OPTIONS
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+ self.assertEqual(1, ipsec_approx_setup_helper._get_n_connections())
+
+ def test__get_n_connections_error(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ scenario_helper.all_options = self.ALL_OPTIONS_ERROR
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+ with self.assertRaises(KeyError) as raised:
+ ipsec_approx_setup_helper._get_n_connections()
+ self.assertIn(
+ 'Missing flow definition in scenario section of the task definition file',
+ str(raised.exception))
+
+ def test__get_flow_src_start_ip(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ scenario_helper.all_options = self.ALL_OPTIONS
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+ self.assertEqual('10.0.0.0',
+ ipsec_approx_setup_helper._get_flow_src_start_ip())
+
+ def test__get_flow_src_start_ip_vnf1(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD_ERROR['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ scenario_helper.all_options = self.ALL_OPTIONS
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+ self.assertEqual('20.0.0.0',
+ ipsec_approx_setup_helper._get_flow_src_start_ip())
+
+ def test__get_flow_src_start_ip_error(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ scenario_helper.all_options = self.ALL_OPTIONS_ERROR
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+ with self.assertRaises(KeyError) as raised:
+ ipsec_approx_setup_helper._get_flow_src_start_ip()
+ self.assertIn(
+ 'Missing flow definition in scenario section of the task definition file',
+ str(raised.exception))
+
+ def test__get_flow_dst_start_ip(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ scenario_helper.all_options = self.ALL_OPTIONS
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+ self.assertEqual('20.0.0.0',
+ ipsec_approx_setup_helper._get_flow_dst_start_ip())
+
+ def test__get_flow_dst_start_ip_vnf1(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD_ERROR['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ scenario_helper.all_options = self.ALL_OPTIONS
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+ self.assertEqual('10.0.0.0',
+ ipsec_approx_setup_helper._get_flow_dst_start_ip())
+
+ def test__get_flow_dst_start_ip_error(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ scenario_helper.all_options = self.ALL_OPTIONS_ERROR
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+ with self.assertRaises(KeyError) as raised:
+ ipsec_approx_setup_helper._get_flow_dst_start_ip()
+ self.assertIn(
+ 'Missing flow definition in scenario section of the task definition file',
+ str(raised.exception))
+
+ def test_build_config(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '0', ''
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS
+ scenario_helper.all_options = self.ALL_OPTIONS
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'execute_script_json_out') as \
+ mock_execute_script_json_out:
+ mock_get_cpu_layout.return_value = self.CPU_LAYOUT
+ mock_execute_script_json_out.return_value = str(
+ self.VPP_INTERFACES_DUMP).replace("\'", "\"")
+ ipsec_approx_setup_helper.sys_cores = cpu.CpuSysCores(ssh_helper)
+ ipsec_approx_setup_helper.sys_cores.cpuinfo = self.CPU_LAYOUT
+ ipsec_approx_setup_helper._update_vnfd_helper(
+ ipsec_approx_setup_helper.sys_cores.get_cpu_layout())
+ ipsec_approx_setup_helper.update_vpp_interface_data()
+ ipsec_approx_setup_helper.iface_update_numa()
+ self.assertIsNone(ipsec_approx_setup_helper.build_config())
+ self.assertEqual(0,
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe0', 'numa_node'))
+ self.assertEqual('TenGigabitEthernetff/6/0',
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe0', 'vpp_name'))
+ self.assertEqual(1,
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe0', 'vpp_sw_index'))
+ self.assertEqual(0,
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe1', 'numa_node'))
+ self.assertEqual('VirtualFunctionEthernetff/7/0',
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe1', 'vpp_name'))
+ self.assertEqual(2,
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe1', 'vpp_sw_index'))
+ self.assertGreaterEqual(ssh_helper.execute.call_count, 4)
+
+ def test_build_config_cbc_algorithms(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '0', ''
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS
+ scenario_helper.all_options = self.ALL_OPTIONS_CBC_ALGORITHMS
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'execute_script_json_out') as \
+ mock_execute_script_json_out:
+ mock_get_cpu_layout.return_value = self.CPU_LAYOUT
+ mock_execute_script_json_out.return_value = str(
+ self.VPP_INTERFACES_DUMP).replace("\'", "\"")
+ ipsec_approx_setup_helper.sys_cores = cpu.CpuSysCores(ssh_helper)
+ ipsec_approx_setup_helper.sys_cores.cpuinfo = self.CPU_LAYOUT
+ ipsec_approx_setup_helper._update_vnfd_helper(
+ ipsec_approx_setup_helper.sys_cores.get_cpu_layout())
+ ipsec_approx_setup_helper.update_vpp_interface_data()
+ ipsec_approx_setup_helper.iface_update_numa()
+ self.assertIsNone(ipsec_approx_setup_helper.build_config())
+ self.assertEqual(0,
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe0', 'numa_node'))
+ self.assertEqual('TenGigabitEthernetff/6/0',
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe0', 'vpp_name'))
+ self.assertEqual(1,
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe0', 'vpp_sw_index'))
+ self.assertEqual(0,
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe1', 'numa_node'))
+ self.assertEqual('VirtualFunctionEthernetff/7/0',
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe1', 'vpp_name'))
+ self.assertEqual(2,
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe1', 'vpp_sw_index'))
+ self.assertGreaterEqual(ssh_helper.execute.call_count, 4)
+
+ @mock.patch.object(utils, 'setup_hugepages')
+ def test_setup_vnf_environment(self, *args):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '0', ''
+ scenario_helper = mock.Mock()
+ scenario_helper.nodes = [None, None]
+ scenario_helper.options = self.OPTIONS
+ scenario_helper.all_options = self.ALL_OPTIONS
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'execute_script_json_out') as \
+ mock_execute_script_json_out:
+ mock_get_cpu_layout.return_value = self.CPU_LAYOUT
+ mock_execute_script_json_out.return_value = str(
+ self.VPP_INTERFACES_DUMP).replace("\'", "\"")
+ self.assertIsInstance(
+ ipsec_approx_setup_helper.setup_vnf_environment(),
+ ResourceProfile)
+ self.assertEqual(0,
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe0', 'numa_node'))
+ self.assertEqual('TenGigabitEthernetff/6/0',
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe0', 'vpp_name'))
+ self.assertEqual(1,
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe0', 'vpp_sw_index'))
+ self.assertEqual(0,
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe1', 'numa_node'))
+ self.assertEqual('VirtualFunctionEthernetff/7/0',
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe1', 'vpp_name'))
+ self.assertEqual(2,
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe1', 'vpp_sw_index'))
+ self.assertGreaterEqual(ssh_helper.execute.call_count, 4)
+
+ @mock.patch.object(utils, 'setup_hugepages')
+ def test_setup_vnf_environment_hw(self, *args):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '0', ''
+ scenario_helper = mock.Mock()
+ scenario_helper.nodes = [None, None]
+ scenario_helper.options = self.OPTIONS_HW
+ scenario_helper.all_options = self.ALL_OPTIONS
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'execute_script_json_out') as \
+ mock_execute_script_json_out:
+ mock_get_cpu_layout.return_value = self.CPU_LAYOUT
+ mock_execute_script_json_out.return_value = str(
+ self.VPP_INTERFACES_DUMP).replace("\'", "\"")
+ self.assertIsInstance(
+ ipsec_approx_setup_helper.setup_vnf_environment(),
+ ResourceProfile)
+ self.assertEqual(0,
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe0', 'numa_node'))
+ self.assertEqual('TenGigabitEthernetff/6/0',
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe0', 'vpp_name'))
+ self.assertEqual(1,
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe0', 'vpp_sw_index'))
+ self.assertEqual(0,
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe1', 'numa_node'))
+ self.assertEqual('VirtualFunctionEthernetff/7/0',
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe1', 'vpp_name'))
+ self.assertEqual(2,
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe1', 'vpp_sw_index'))
+ self.assertGreaterEqual(ssh_helper.execute.call_count, 4)
+
+ def test_calculate_frame_size(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+ self.assertEqual(16984 / 48,
+ ipsec_approx_setup_helper.calculate_frame_size(
+ {'64B': 28, '570B': 16, '1518B': 4}))
+
+ def test_calculate_frame_size_64(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+ self.assertEqual(64,
+ ipsec_approx_setup_helper.calculate_frame_size({}))
+
+ def test_calculate_frame_size_64_error(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+ self.assertEqual(64,
+ ipsec_approx_setup_helper.calculate_frame_size(
+ {'64B': -28, '570B': 16, '1518B': 4}))
+
+ def test_check_status(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, self.VPP_INTERFACES_STATUS, ''
+ scenario_helper = mock.Mock()
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+ self.assertTrue(ipsec_approx_setup_helper.check_status())
+
+ def test_check_status_false(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, self.VPP_INTERFACES_STATUS_FALSE, ''
+ scenario_helper = mock.Mock()
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+ self.assertFalse(ipsec_approx_setup_helper.check_status())
+
+ def test_get_vpp_statistics(self):
+ def execute(cmd):
+ if 'TenGigabitEthernetff/6/0' in cmd:
+ return 0, output_xe0, ''
+ elif 'VirtualFunctionEthernetff/7/0' in cmd:
+ return 0, output_xe1, ''
+ return 0, '0', ''
+
+ output_xe0 = \
+ ' Name Idx State MTU (L3/IP4/IP6/MPLS)' \
+ ' Counter Count \n' \
+ 'TenGigabitEthernetff/6/0 1 up 9200/0/0/0 ' \
+ 'rx packets 23373568\n' \
+ ' ' \
+ 'rx bytes 1402414080\n' \
+ ' ' \
+ 'tx packets 20476416\n' \
+ ' ' \
+ 'tx bytes 1228584960\n' \
+ ' ' \
+ 'ip4 23373568\n' \
+ ' ' \
+ 'rx-miss 27789925'
+ output_xe1 = \
+ ' Name Idx State MTU (L3/IP4/IP6/MPLS)' \
+ ' Counter Count \n' \
+ 'VirtualFunctionEthernetff/7/0 2 up 9200/0/0/0 ' \
+ 'rx packets 23373568\n' \
+ ' ' \
+ 'rx bytes 1402414080\n' \
+ ' ' \
+ 'tx packets 20476416\n' \
+ ' ' \
+ 'tx bytes 1228584960\n' \
+ ' ' \
+ 'ip4 23373568\n' \
+ ' ' \
+ 'rx-miss 27789925'
+
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ ssh_helper.execute = execute
+ scenario_helper = mock.Mock()
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'execute_script_json_out') as \
+ mock_execute_script_json_out:
+ mock_get_cpu_layout.return_value = self.CPU_LAYOUT
+ mock_execute_script_json_out.return_value = str(
+ self.VPP_INTERFACES_DUMP).replace("\'", "\"")
+ sys_cores = cpu.CpuSysCores(ssh_helper)
+ ipsec_approx_setup_helper._update_vnfd_helper(
+ sys_cores.get_cpu_layout())
+ ipsec_approx_setup_helper.update_vpp_interface_data()
+ ipsec_approx_setup_helper.iface_update_numa()
+ self.assertEqual({'xe0': {'packets_dropped': 27789925,
+ 'packets_fwd': 20476416,
+ 'packets_in': 23373568},
+ 'xe1': {'packets_dropped': 27789925,
+ 'packets_fwd': 20476416,
+ 'packets_in': 23373568}},
+ ipsec_approx_setup_helper.get_vpp_statistics())
+
+ def test_parser_vpp_stats(self):
+ output = \
+ ' Name Idx State MTU (L3/IP4/IP6/MPLS)' \
+ 'Counter Count \n' \
+ 'TenGigabitEthernetff/6/0 1 up 9200/0/0/0 ' \
+ 'rx packets 23373568\n' \
+ ' ' \
+ 'rx bytes 1402414080\n' \
+ ' ' \
+ 'tx packets 20476416\n' \
+ ' ' \
+ 'tx bytes 1228584960\n' \
+ ' ' \
+ 'ip4 23373568\n' \
+ ' ' \
+ 'rx-miss 27789925'
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+ self.assertEqual({'xe0': {'packets_dropped': 27789925,
+ 'packets_fwd': 20476416,
+ 'packets_in': 23373568}},
+ ipsec_approx_setup_helper.parser_vpp_stats('xe0',
+ 'TenGigabitEthernetff/6/0',
+ output))
+
+ def test_parser_vpp_stats_no_miss(self):
+ output = \
+ ' Name Idx State ' \
+ 'Counter Count \n' \
+ 'TenGigabitEthernetff/6/0 1 up ' \
+ 'rx packets 23373568\n' \
+ ' ' \
+ 'rx bytes 1402414080\n' \
+ ' ' \
+ 'tx packets 20476416\n' \
+ ' ' \
+ 'tx bytes 1228584960\n' \
+ ' ' \
+ 'ip4 23373568'
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+ self.assertEqual({'xe0': {'packets_dropped': 2897152,
+ 'packets_fwd': 20476416,
+ 'packets_in': 23373568}},
+ ipsec_approx_setup_helper.parser_vpp_stats('xe0',
+ 'TenGigabitEthernetff/6/0',
+ output))
+
+ def test_create_ipsec_tunnels(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '0', ''
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS
+ scenario_helper.all_options = self.ALL_OPTIONS
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'execute_script_json_out') as \
+ mock_execute_script_json_out, \
+ mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'vpp_get_interface_data') as \
+ mock_ipsec_approx_setup_helper:
+ mock_get_cpu_layout.return_value = self.CPU_LAYOUT
+ mock_execute_script_json_out.return_value = str(
+ self.VPP_INTERFACES_DUMP).replace("\'", "\"")
+ mock_vat_terminal_exec_cmd_from_template.return_value = self.VPP_INTERFACES_DUMP
+ mock_ipsec_approx_setup_helper.return_value = self.VPP_INTERFACES_DUMP
+ sys_cores = cpu.CpuSysCores(ssh_helper)
+ ipsec_approx_setup_helper._update_vnfd_helper(
+ sys_cores.get_cpu_layout())
+ ipsec_approx_setup_helper.update_vpp_interface_data()
+ ipsec_approx_setup_helper.iface_update_numa()
+ self.assertIsNone(ipsec_approx_setup_helper.create_ipsec_tunnels())
+ self.assertGreaterEqual(
+ mock_vat_terminal_exec_cmd_from_template.call_count, 9)
+
+ def test_create_ipsec_tunnels_cbc_algorithms(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '0', ''
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS
+ scenario_helper.all_options = self.ALL_OPTIONS_CBC_ALGORITHMS
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'execute_script_json_out') as \
+ mock_execute_script_json_out, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'find_encrypted_data_interface') as \
+ mock_find_encrypted_data_interface, \
+ mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'vpp_get_interface_data') as \
+ mock_ipsec_approx_setup_helper:
+ mock_get_cpu_layout.return_value = self.CPU_LAYOUT
+ mock_execute_script_json_out.return_value = str(
+ self.VPP_INTERFACES_DUMP).replace("\'", "\"")
+ mock_find_encrypted_data_interface.return_value = {
+ 'dpdk_port_num': 0,
+ 'driver': 'igb_uio',
+ 'dst_ip': '192.168.100.1',
+ 'dst_mac': '90:e2:ba:7c:30:e8',
+ 'ifname': 'xe0',
+ 'local_ip': '192.168.100.2',
+ 'local_mac': '90:e2:ba:7c:41:a8',
+ 'netmask': '255.255.255.0',
+ 'network': {},
+ 'node_name': 'vnf__1',
+ 'numa_node': 0,
+ 'peer_ifname': 'xe0',
+ 'peer_intf': {'dpdk_port_num': 0,
+ 'driver': 'igb_uio',
+ 'dst_ip': '192.168.100.2',
+ 'dst_mac': '90:e2:ba:7c:41:a8',
+ 'ifname': 'xe0',
+ 'local_ip': '192.168.100.1',
+ 'local_mac': '90:e2:ba:7c:30:e8',
+ 'netmask': '255.255.255.0',
+ 'network': {},
+ 'node_name': 'tg__0',
+ 'peer_ifname': 'xe0',
+ 'peer_name': 'vnf__0',
+ 'vld_id': 'uplink_0',
+ 'vpci': '0000:81:00.0'},
+ 'peer_name': 'tg__0',
+ 'vld_id': 'uplink_0',
+ 'vpci': '0000:ff:06.0',
+ 'vpp_name': u'TenGigabitEthernetff/6/0',
+ 'vpp_sw_index': 1}
+ mock_vat_terminal_exec_cmd_from_template.return_value = self.VPP_INTERFACES_DUMP
+ mock_ipsec_approx_setup_helper.return_value = self.VPP_INTERFACES_DUMP
+ sys_cores = cpu.CpuSysCores(ssh_helper)
+ ipsec_approx_setup_helper._update_vnfd_helper(
+ sys_cores.get_cpu_layout())
+ ipsec_approx_setup_helper.update_vpp_interface_data()
+ ipsec_approx_setup_helper.iface_update_numa()
+ self.assertIsNone(ipsec_approx_setup_helper.create_ipsec_tunnels())
+ self.assertGreaterEqual(
+ mock_vat_terminal_exec_cmd_from_template.call_count, 9)
+
+ def test_find_raw_data_interface(self):
+ expected = {'dpdk_port_num': 0,
+ 'driver': 'igb_uio',
+ 'dst_ip': '192.168.100.1',
+ 'dst_mac': '90:e2:ba:7c:30:e8',
+ 'ifname': 'xe0',
+ 'local_ip': '192.168.100.2',
+ 'local_mac': '90:e2:ba:7c:41:a8',
+ 'netmask': '255.255.255.0',
+ 'network': {},
+ 'node_name': 'vnf__0',
+ 'numa_node': 0,
+ 'peer_ifname': 'xe0',
+ 'peer_intf': {'dpdk_port_num': 0,
+ 'driver': 'igb_uio',
+ 'dst_ip': '192.168.100.2',
+ 'dst_mac': '90:e2:ba:7c:41:a8',
+ 'ifname': 'xe0',
+ 'local_ip': '192.168.100.1',
+ 'local_mac': '90:e2:ba:7c:30:e8',
+ 'netmask': '255.255.255.0',
+ 'network': {},
+ 'node_name': 'tg__0',
+ 'peer_ifname': 'xe0',
+ 'peer_name': 'vnf__0',
+ 'vld_id': 'uplink_0',
+ 'vpci': '0000:81:00.0'},
+ 'peer_name': 'tg__0',
+ 'vld_id': 'uplink_0',
+ 'vpci': '0000:ff:06.0',
+ 'vpp_name': u'TenGigabitEthernetff/6/0',
+ 'vpp_sw_index': 1}
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+ self.assertEqual(expected,
+ ipsec_approx_setup_helper.find_raw_data_interface())
+
+ def test_find_raw_data_interface_error(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD_ERROR['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+ with self.assertRaises(KeyError):
+ ipsec_approx_setup_helper.find_raw_data_interface()
+
+ def test_find_encrypted_data_interface(self):
+ expected = {'dpdk_port_num': 1,
+ 'driver': 'igb_uio',
+ 'dst_ip': '1.1.1.2',
+ 'dst_mac': '0a:b1:ec:fd:a2:66',
+ 'ifname': 'xe1',
+ 'local_ip': '1.1.1.1',
+ 'local_mac': '4e:90:85:d3:c5:13',
+ 'netmask': '255.255.255.0',
+ 'network': {},
+ 'node_name': 'vnf__0',
+ 'numa_node': 0,
+ 'peer_ifname': 'xe1',
+ 'peer_intf': {'driver': 'igb_uio',
+ 'dst_ip': '1.1.1.1',
+ 'dst_mac': '4e:90:85:d3:c5:13',
+ 'ifname': 'xe1',
+ 'local_ip': '1.1.1.2',
+ 'local_mac': '0a:b1:ec:fd:a2:66',
+ 'netmask': '255.255.255.0',
+ 'network': {},
+ 'node_name': 'vnf__1',
+ 'peer_ifname': 'xe1',
+ 'peer_name': 'vnf__0',
+ 'vld_id': 'ciphertext',
+ 'vpci': '0000:00:07.0'},
+ 'peer_name': 'vnf__1',
+ 'vld_id': 'ciphertext',
+ 'vpci': '0000:ff:07.0',
+ 'vpp_name': u'VirtualFunctionEthernetff/7/0',
+ 'vpp_sw_index': 2}
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+ self.assertEqual(expected,
+ ipsec_approx_setup_helper.find_encrypted_data_interface())
+
+ def test_create_startup_configuration_of_vpp(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '0', ''
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS
+ scenario_helper.all_options = self.ALL_OPTIONS
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'execute_script_json_out') as \
+ mock_execute_script_json_out:
+ mock_get_cpu_layout.return_value = self.CPU_LAYOUT
+ mock_execute_script_json_out.return_value = str(
+ self.VPP_INTERFACES_DUMP).replace("\'", "\"")
+ sys_cores = cpu.CpuSysCores(ssh_helper)
+ ipsec_approx_setup_helper._update_vnfd_helper(
+ sys_cores.get_cpu_layout())
+ ipsec_approx_setup_helper.update_vpp_interface_data()
+ ipsec_approx_setup_helper.iface_update_numa()
+ self.assertIsInstance(
+ ipsec_approx_setup_helper.create_startup_configuration_of_vpp(),
+ vpp_helpers.VppConfigGenerator)
+
+ def test_add_worker_threads_and_rxqueues(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '0', ''
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS
+ scenario_helper.all_options = self.ALL_OPTIONS
+ vpp_config_generator = vpp_helpers.VppConfigGenerator()
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'execute_script_json_out') as \
+ mock_execute_script_json_out:
+ mock_get_cpu_layout.return_value = self.CPU_LAYOUT
+ mock_execute_script_json_out.return_value = str(
+ self.VPP_INTERFACES_DUMP).replace("\'", "\"")
+ ipsec_approx_setup_helper.sys_cores = cpu.CpuSysCores(ssh_helper)
+ ipsec_approx_setup_helper.sys_cores.cpuinfo = self.CPU_LAYOUT
+ ipsec_approx_setup_helper._update_vnfd_helper(
+ ipsec_approx_setup_helper.sys_cores.get_cpu_layout())
+ ipsec_approx_setup_helper.update_vpp_interface_data()
+ ipsec_approx_setup_helper.iface_update_numa()
+ self.assertIsNone(
+ ipsec_approx_setup_helper.add_worker_threads_and_rxqueues(
+ vpp_config_generator, 1, 1))
+ self.assertEqual(
+ 'cpu\n{\n corelist-workers 2\n main-core 1\n}\ndpdk\n{\n ' \
+ 'dev default\n {\n num-rx-queues 1\n }\n num-mbufs 32768\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_worker_threads_and_rxqueues_smt(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '0', ''
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS
+ scenario_helper.all_options = self.ALL_OPTIONS
+ vpp_config_generator = vpp_helpers.VppConfigGenerator()
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'execute_script_json_out') as \
+ mock_execute_script_json_out:
+ mock_get_cpu_layout.return_value = self.CPU_SMT
+ mock_execute_script_json_out.return_value = str(
+ self.VPP_INTERFACES_DUMP).replace("\'", "\"")
+ ipsec_approx_setup_helper.sys_cores = cpu.CpuSysCores(ssh_helper)
+ ipsec_approx_setup_helper.sys_cores.cpuinfo = self.CPU_SMT
+ ipsec_approx_setup_helper._update_vnfd_helper(
+ ipsec_approx_setup_helper.sys_cores.get_cpu_layout())
+ ipsec_approx_setup_helper.update_vpp_interface_data()
+ ipsec_approx_setup_helper.iface_update_numa()
+ self.assertIsNone(
+ ipsec_approx_setup_helper.add_worker_threads_and_rxqueues(
+ vpp_config_generator, 1))
+ self.assertEqual(
+ 'cpu\n{\n corelist-workers 2,6\n main-core 1\n}\ndpdk\n{\n ' \
+ 'dev default\n {\n num-rx-queues 1\n }\n num-mbufs 32768\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_worker_threads_and_rxqueues_with_numa(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '0', ''
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS
+ scenario_helper.all_options = self.ALL_OPTIONS
+ vpp_config_generator = vpp_helpers.VppConfigGenerator()
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'execute_script_json_out') as \
+ mock_execute_script_json_out:
+ mock_get_cpu_layout.return_value = self.CPU_LAYOUT
+ mock_execute_script_json_out.return_value = str(
+ self.VPP_INTERFACES_DUMP).replace("\'", "\"")
+ ipsec_approx_setup_helper.sys_cores = cpu.CpuSysCores(ssh_helper)
+ ipsec_approx_setup_helper.sys_cores.cpuinfo = self.CPU_LAYOUT
+ ipsec_approx_setup_helper._update_vnfd_helper(
+ ipsec_approx_setup_helper.sys_cores.get_cpu_layout())
+ ipsec_approx_setup_helper.update_vpp_interface_data()
+ ipsec_approx_setup_helper.iface_update_numa()
+ self.assertIsNone(
+ ipsec_approx_setup_helper.add_worker_threads_and_rxqueues(
+ vpp_config_generator, 1, 1))
+ self.assertEqual(
+ 'cpu\n{\n corelist-workers 2\n main-core 1\n}\ndpdk\n{\n ' \
+ 'dev default\n {\n num-rx-queues 1\n }\n num-mbufs 32768\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_pci_devices(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '0', ''
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS
+ scenario_helper.all_options = self.ALL_OPTIONS
+ vpp_config_generator = vpp_helpers.VppConfigGenerator()
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'execute_script_json_out') as \
+ mock_execute_script_json_out:
+ mock_get_cpu_layout.return_value = self.CPU_LAYOUT
+ mock_execute_script_json_out.return_value = str(
+ self.VPP_INTERFACES_DUMP).replace("\'", "\"")
+ sys_cores = cpu.CpuSysCores(ssh_helper)
+ ipsec_approx_setup_helper._update_vnfd_helper(
+ sys_cores.get_cpu_layout())
+ ipsec_approx_setup_helper.update_vpp_interface_data()
+ ipsec_approx_setup_helper.iface_update_numa()
+ self.assertIsNone(ipsec_approx_setup_helper.add_pci_devices(
+ vpp_config_generator))
+ self.assertEqual(
+ 'dpdk\n{\n dev 0000:ff:06.0 \n dev 0000:ff:07.0 \n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_dpdk_cryptodev(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '0', ''
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS
+ scenario_helper.all_options = self.ALL_OPTIONS
+ vpp_config_generator = vpp_helpers.VppConfigGenerator()
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'execute_script_json_out') as \
+ mock_execute_script_json_out:
+ mock_get_cpu_layout.return_value = self.CPU_LAYOUT
+ mock_execute_script_json_out.return_value = str(
+ self.VPP_INTERFACES_DUMP).replace("\'", "\"")
+ ipsec_approx_setup_helper.sys_cores = cpu.CpuSysCores(ssh_helper)
+ ipsec_approx_setup_helper.sys_cores.cpuinfo = self.CPU_LAYOUT
+ ipsec_approx_setup_helper._update_vnfd_helper(
+ ipsec_approx_setup_helper.sys_cores.get_cpu_layout())
+ ipsec_approx_setup_helper.update_vpp_interface_data()
+ ipsec_approx_setup_helper.iface_update_numa()
+ self.assertIsNone(ipsec_approx_setup_helper.add_dpdk_cryptodev(
+ vpp_config_generator, 'aesni_gcm', 1))
+ self.assertEqual(
+ 'dpdk\n{\n vdev cryptodev_aesni_gcm_pmd,socket_id=0 \n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_dpdk_cryptodev_hw(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '0', ''
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS_HW
+ scenario_helper.all_options = self.ALL_OPTIONS
+ vpp_config_generator = vpp_helpers.VppConfigGenerator()
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'execute_script_json_out') as \
+ mock_execute_script_json_out:
+ mock_get_cpu_layout.return_value = self.CPU_LAYOUT
+ mock_execute_script_json_out.return_value = str(
+ self.VPP_INTERFACES_DUMP).replace("\'", "\"")
+ ipsec_approx_setup_helper.sys_cores = cpu.CpuSysCores(ssh_helper)
+ ipsec_approx_setup_helper.sys_cores.cpuinfo = self.CPU_LAYOUT
+ ipsec_approx_setup_helper._update_vnfd_helper(
+ ipsec_approx_setup_helper.sys_cores.get_cpu_layout())
+ ipsec_approx_setup_helper.update_vpp_interface_data()
+ ipsec_approx_setup_helper.iface_update_numa()
+ self.assertIsNone(ipsec_approx_setup_helper.add_dpdk_cryptodev(
+ vpp_config_generator, 'aesni_gcm', 1))
+ self.assertEqual(
+ 'dpdk\n{\n dev 0000:ff:01.0 \n uio-driver igb_uio\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_dpdk_cryptodev_smt_used(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '0', ''
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS
+ scenario_helper.all_options = self.ALL_OPTIONS
+ vpp_config_generator = vpp_helpers.VppConfigGenerator()
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'execute_script_json_out') as \
+ mock_execute_script_json_out:
+ mock_get_cpu_layout.return_value = self.CPU_SMT
+ mock_execute_script_json_out.return_value = str(
+ self.VPP_INTERFACES_DUMP).replace("\'", "\"")
+ ipsec_approx_setup_helper.sys_cores = cpu.CpuSysCores(ssh_helper)
+ ipsec_approx_setup_helper.sys_cores.cpuinfo = self.CPU_LAYOUT
+ ipsec_approx_setup_helper._update_vnfd_helper(
+ ipsec_approx_setup_helper.sys_cores.get_cpu_layout())
+ ipsec_approx_setup_helper.update_vpp_interface_data()
+ ipsec_approx_setup_helper.iface_update_numa()
+ self.assertIsNone(ipsec_approx_setup_helper.add_dpdk_cryptodev(
+ vpp_config_generator, 'aesni_gcm', 1))
+ self.assertEqual(
+ 'dpdk\n{\n vdev cryptodev_aesni_gcm_pmd,socket_id=0 \n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_dpdk_cryptodev_smt_used_hw(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '0', ''
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS_HW
+ scenario_helper.all_options = self.ALL_OPTIONS
+ vpp_config_generator = vpp_helpers.VppConfigGenerator()
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout:
+ mock_get_cpu_layout.return_value = self.CPU_SMT
+ ipsec_approx_setup_helper.sys_cores = cpu.CpuSysCores(ssh_helper)
+ ipsec_approx_setup_helper.sys_cores.cpuinfo = self.CPU_SMT
+ ipsec_approx_setup_helper._update_vnfd_helper(
+ ipsec_approx_setup_helper.sys_cores.get_cpu_layout())
+ self.assertIsNone(ipsec_approx_setup_helper.add_dpdk_cryptodev(
+ vpp_config_generator, 'aesni_gcm', 1))
+ self.assertEqual(
+ 'dpdk\n{\n dev 0000:ff:01.0 \n dev 0000:ff:01.1 \n uio-driver igb_uio\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_initialize_ipsec(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '0', ''
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS
+ scenario_helper.all_options = self.ALL_OPTIONS
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'execute_script_json_out') as \
+ mock_execute_script_json_out, \
+ mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'vpp_get_interface_data') as \
+ mock_ipsec_approx_setup_helper:
+ mock_get_cpu_layout.return_value = self.CPU_LAYOUT
+ mock_execute_script_json_out.return_value = str(
+ self.VPP_INTERFACES_DUMP).replace("\'", "\"")
+ mock_vat_terminal_exec_cmd_from_template.return_value = ''
+ mock_ipsec_approx_setup_helper.return_value = self.VPP_INTERFACES_DUMP
+ sys_cores = cpu.CpuSysCores(ssh_helper)
+ ipsec_approx_setup_helper._update_vnfd_helper(
+ sys_cores.get_cpu_layout())
+ ipsec_approx_setup_helper.update_vpp_interface_data()
+ ipsec_approx_setup_helper.iface_update_numa()
+ self.assertIsNone(ipsec_approx_setup_helper.initialize_ipsec())
+ self.assertGreaterEqual(
+ mock_vat_terminal_exec_cmd_from_template.call_count, 9)
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_imsbench_sipp.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_imsbench_sipp.py
new file mode 100644
index 000000000..698b1b03f
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_imsbench_sipp.py
@@ -0,0 +1,481 @@
+# Copyright (c) 2019 Viosoft 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.
+
+import mock
+import unittest
+from collections import deque
+
+from yardstick.network_services.vnf_generic.vnf import tg_imsbench_sipp
+from yardstick import ssh
+
+
+class TestSippVnf(unittest.TestCase):
+
+ VNFD = {
+ "short-name": "SippVnf",
+ "vdu": [
+ {
+ "id": "sippvnf-baremetal",
+ "routing_table": "",
+ "external-interface": [
+ {
+ "virtual-interface": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "peer_intf": {
+ "vld_id": "data_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "node_name": "vnf__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:a8"
+ },
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ },
+ "vnfd-connection-point-ref": "xe0",
+ "name": "xe0"
+ },
+ {
+ "virtual-interface": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "peer_intf": {
+ "vld_id": "data_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "peer_intf": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ },
+ "node_name": "vnf__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:a8"
+ },
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe1",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ },
+ "vnfd-connection-point-ref": "xe1",
+ "name": "xe1"
+ }
+ ],
+ "name": "sippvnf-baremetal",
+ "description": "Sipp"
+ }
+ ],
+ "description": "ImsbenchSipp",
+ "mgmt-interface": {
+ "vdu-id": "sipp-baremetal",
+ "password": "r00t",
+ "user": "root",
+ "ip": "10.80.3.11"
+ },
+ "benchmark": {
+ "kpi": [
+ "packets_in",
+ "packets_fwd",
+ "packets_dropped"
+ ]
+ },
+ "id": "SippVnf",
+ "name": "SippVnf"
+ }
+
+ SCENARIO_CFG = {
+ "task_id": "ba636744-898e-4783-a4aa-0a79c60953cc",
+ "tc": "tc_vims_baremetal_sipp",
+ "runner": {
+ "interval": 1,
+ "output_config": {
+ "DEFAULT": {
+ "debug": "False",
+ "dispatcher": [
+ "influxdb"
+ ]
+ },
+ "nsb": {
+ "debug": "False",
+ "trex_client_lib": "/opt/nsb_bin/trex_client/stl",
+ "bin_path": "/opt/nsb_bin",
+ "trex_path": "/opt/nsb_bin/trex/scripts",
+ "dispatcher": "influxdb"
+ },
+ "dispatcher_influxdb": {
+ "username": "root",
+ "target": "http://10.80.3.11:8086",
+ "db_name": "yardstick",
+ "timeout": "5",
+ "debug": "False",
+ "password": "root",
+ "dispatcher": "influxdb"
+ },
+ "dispatcher_http": {
+ "debug": "False",
+ "dispatcher": "influxdb",
+ "timeout": "5",
+ "target": "http://127.0.0.1:8000/results"
+ },
+ "dispatcher_file": {
+ "debug": "False",
+ "backup_count": "0",
+ "max_bytes": "0",
+ "dispatcher": "influxdb",
+ "file_path": "/tmp/yardstick.out"
+ }
+ },
+ "runner_id": 18148,
+ "duration": 60,
+ "type": "Vims"
+ },
+ "nodes": {
+ "vnf__0": "pcscf.yardstick-ba636744",
+ "vnf__1": "hss.yardstick-ba636744",
+ "tg__0": "sipp.yardstick-ba636744"
+ },
+ "topology": "vims-topology.yaml",
+ "type": "NSPerf",
+ "traffic_profile": "../../traffic_profiles/ipv4_throughput.yaml",
+ "task_path": "samples/vnf_samples/nsut/vims",
+ "options": {
+ "init_reg_max": 5000,
+ "end_user": 10000,
+ "reg_cps": 20,
+ "rereg_cps": 20,
+ "rereg_step": 10,
+ "wait_time": 5,
+ "start_user": 1,
+ "msgc_cps": 10,
+ "dereg_step": 10,
+ "call_cps": 10,
+ "reg_step": 10,
+ "init_reg_cps": 50,
+ "dereg_cps": 20,
+ "msgc_step": 5,
+ "call_step": 5,
+ "hold_time": 15,
+ "port": 5060,
+ "run_mode": "nortp"
+ }
+ }
+ CONTEXT_CFG = {
+ "nodes": {
+ "tg__0": {
+ "ip": "10.80.3.11",
+ "interfaces": {
+ "xe0": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "peer_intf": {
+ "vld_id": "data_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "node_name": "vnf__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:a8"
+ },
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ },
+ "xe1": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "peer_intf": {
+ "vld_id": "data_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "peer_intf": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ },
+ "node_name": "vnf__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:a8"
+ },
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe1",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ }
+ },
+ "user": "root",
+ "password": "r00t",
+ "VNF model": "../../vnf_descriptors/tg_sipp_vnfd.yaml",
+ "name": "sipp.yardstick-a75a3aff",
+ "vnfd-id-ref": "tg__0",
+ "member-vnf-index": "1",
+ "role": "TrafficGen",
+ "ctx_type": "Node"
+ },
+ "vnf__0": {
+ "ip": "10.80.3.7",
+ "interfaces": {
+ "xe0": {
+ "vld_id": "data_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "peer_intf": {
+ "tg__0": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe1",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ }
+ },
+ "node_name": "vnf__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:a8"
+ }
+ },
+ "user": "root",
+ "password": "r00t",
+ "VNF model": "../../vnf_descriptors/vims_pcscf_vnfd.yaml",
+ "name": "pcscf.yardstick-a75a3aff",
+ "vnfd-id-ref": "vnf__0",
+ "member-vnf-index": "2",
+ "role": "VirtualNetworkFunction",
+ "ctx_type": "Node"
+ },
+ "vnf__1": {
+ "ip": "10.80.3.7",
+ "interfaces": {
+ "xe0": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "peer_intf": {
+ "tg__0": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "peer_intf": {
+ "vld_id": "data_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "peer_intf": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ },
+ "node_name": "vnf__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:a8"
+ },
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe1",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ }
+ },
+ "node_name": "vnf__1",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:e8"
+ }
+ },
+ "user": "root",
+ "password": "r00t",
+ "VNF model": "../../vnf_descriptors/vims_hss_vnfd.yaml",
+ "name": "hss.yardstick-a75a3aff",
+ "vnfd-id-ref": "vnf__1",
+ "member-vnf-index": "3",
+ "role": "VirtualNetworkFunction",
+ "ctx_type": "Node"
+ }
+ },
+ "networks": {}
+ }
+
+ FILE = "timestamp:1000 reg:100 reg_saps:0"
+
+ QUEUE = {'reg_saps': 0.0, 'timestamp': 1000.0, 'reg': 100.0}
+
+ TRAFFIC_PROFILE = {
+ "schema": "nsb:traffic_profile:0.1",
+ "name": "sip",
+ "description": "Traffic profile to run sip",
+ "traffic_profile": {
+ "traffic_type": "SipProfile",
+ "frame_rate": 100, # pps
+ "enable_latency": False
+ },
+ }
+
+ def setUp(self):
+ self._mock_ssh = mock.patch.object(ssh, 'SSH')
+ self.mock_ssh = self._mock_ssh.start()
+
+ self.addCleanup(self._stop_mocks)
+ self.sipp_vnf = tg_imsbench_sipp.SippVnf('tg__0', self.VNFD)
+
+ def _stop_mocks(self):
+ self._mock_ssh.stop()
+
+ def test___init__(self):
+ self.assertIsInstance(self.sipp_vnf.resource_helper,
+ tg_imsbench_sipp.SippResourceHelper)
+
+ def test_wait_for_instantiate(self):
+ self.assertIsNone(self.sipp_vnf.wait_for_instantiate())
+
+ @mock.patch('six.moves.builtins.open', new_callable=mock.mock_open, read_data=FILE)
+ def test_handle_result_files(self, mock_file):
+ result_deque = deque([self.QUEUE])
+ file = "/tmp/test.txt"
+ test = self.sipp_vnf.handle_result_files(file)
+ self.assertEqual(result_deque, test)
+ mock_file.assert_called_with(file, 'r')
+
+ @mock.patch.object(ssh.SSH, 'get')
+ def test_get_result_files(self, mock_get):
+ self.sipp_vnf.get_result_files()
+ mock_get.assert_called()
+
+ def test_collect_kpi(self):
+ self.sipp_vnf.queue = deque([self.QUEUE])
+ self.assertEqual(self.QUEUE, self.sipp_vnf.collect_kpi())
+
+ def test_collect_kpi_empty(self):
+ self.sipp_vnf.queue = deque([])
+ self.assertEqual({}, self.sipp_vnf.collect_kpi())
+
+ @mock.patch('six.moves.builtins.open', new_callable=mock.mock_open, read_data=FILE)
+ def test_count_line_num(self, mock_file):
+ file = "/tmp/test.txt"
+ mock_file.return_value.__iter__.return_value = self.FILE.splitlines()
+ self.assertEqual(1, self.sipp_vnf.count_line_num(file))
+ mock_file.assert_called_with(file, 'r')
+
+ @mock.patch('six.moves.builtins.open', new_callable=mock.mock_open, read_data='')
+ def test_count_line_num_file_empty(self, mock_file):
+ file = "/tmp/test.txt"
+ self.assertEqual(0, self.sipp_vnf.count_line_num(file))
+ mock_file.assert_called_with(file, 'r')
+
+ @mock.patch('six.moves.builtins.open', new_callable=mock.mock_open, read_data=FILE)
+ def test_count_line_num_file_error(self, mock_file):
+ file = "/tmp/test.txt"
+ mock_file.side_effect = IOError()
+ self.assertEqual(0, self.sipp_vnf.count_line_num(file))
+
+ def test_is_ended_false(self):
+ self.sipp_vnf.count_line_num = mock.Mock(return_value=1)
+ not_end = self.sipp_vnf.is_ended()
+ self.assertFalse(not_end)
+
+ def test_is_ended_true(self):
+ self.sipp_vnf.count_line_num = mock.Mock(return_value=0)
+ end = self.sipp_vnf.is_ended()
+ self.assertTrue(end)
+
+ def test_terminate(self):
+ self.sipp_vnf.ssh_helper = mock.MagicMock()
+ self.sipp_vnf.resource_helper.ssh_helper = mock.MagicMock()
+ self.assertIsNone(self.sipp_vnf.terminate())
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_trex_vpp.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_trex_vpp.py
new file mode 100644
index 000000000..ef1ae1182
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_trex_vpp.py
@@ -0,0 +1,1130 @@
+# Copyright (c) 2019 Viosoft 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.
+
+import unittest
+from multiprocessing import Process
+
+import mock
+from trex_stl_lib.trex_stl_exceptions import STLError
+
+from yardstick.benchmark.contexts import base as ctx_base
+from yardstick.network_services.traffic_profile import base as tp_base
+from yardstick.network_services.traffic_profile import rfc2544
+from yardstick.network_services.vnf_generic.vnf import base, sample_vnf, \
+ tg_trex_vpp
+from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import \
+ mock_ssh
+
+
+class TestTrexVppResourceHelper(unittest.TestCase):
+ TRAFFIC_PROFILE = {
+ "schema": "isb:traffic_profile:0.1",
+ "name": "fixed",
+ "description": "Fixed traffic profile to run UDP traffic",
+ "traffic_profile": {
+ "traffic_type": "FixedTraffic",
+ "frame_rate": 100, # pps
+ "flow_number": 10,
+ "frame_size": 64
+ },
+ }
+
+ def test_fmt_latency(self):
+ mock_setup_helper = mock.Mock()
+ vpp_rfc = tg_trex_vpp.TrexVppResourceHelper(mock_setup_helper)
+ self.assertEqual('10/90/489', vpp_rfc.fmt_latency(10, 90, 489))
+
+ def test_fmt_latency_error(self):
+ mock_setup_helper = mock.Mock()
+ vpp_rfc = tg_trex_vpp.TrexVppResourceHelper(mock_setup_helper)
+ self.assertEqual('-1/-1/-1', vpp_rfc.fmt_latency('err', 'err', 'err'))
+
+ def test_generate_samples(self):
+ stats = {
+ 0: {
+ "ibytes": 55549120,
+ "ierrors": 0,
+ "ipackets": 867955,
+ "obytes": 55549696,
+ "oerrors": 0,
+ "opackets": 867964,
+ "rx_bps": 104339032.0,
+ "rx_bps_L1": 136944984.0,
+ "rx_pps": 203787.2,
+ "rx_util": 1.36944984,
+ "tx_bps": 134126008.0,
+ "tx_bps_L1": 176040392.0,
+ "tx_pps": 261964.9,
+ "tx_util": 1.7604039200000001
+ },
+ 1: {
+ "ibytes": 55549696,
+ "ierrors": 0,
+ "ipackets": 867964,
+ "obytes": 55549120,
+ "oerrors": 0,
+ "opackets": 867955,
+ "rx_bps": 134119648.0,
+ "rx_bps_L1": 176032032.0,
+ "rx_pps": 261952.4,
+ "rx_util": 1.76032032,
+ "tx_bps": 104338192.0,
+ "tx_bps_L1": 136943872.0,
+ "tx_pps": 203785.5,
+ "tx_util": 1.36943872
+ },
+ "flow_stats": {
+ 1: {
+ "rx_bps": {
+ "0": 0,
+ "1": 0,
+ "total": 0
+ },
+ "rx_bps_l1": {
+ "0": 0.0,
+ "1": 0.0,
+ "total": 0.0
+ },
+ "rx_bytes": {
+ "0": 6400,
+ "1": 0,
+ "total": 6400
+ },
+ "rx_pkts": {
+ "0": 100,
+ "1": 0,
+ "total": 100
+ },
+ "rx_pps": {
+ "0": 0,
+ "1": 0,
+ "total": 0
+ },
+ "tx_bps": {
+ "0": 0,
+ "1": 0,
+ "total": 0
+ },
+ "tx_bps_l1": {
+ "0": 0.0,
+ "1": 0.0,
+ "total": 0.0
+ },
+ "tx_bytes": {
+ "0": 0,
+ "1": 6400,
+ "total": 6400
+ },
+ "tx_pkts": {
+ "0": 0,
+ "1": 100,
+ "total": 100
+ },
+ "tx_pps": {
+ "0": 0,
+ "1": 0,
+ "total": 0
+ }
+ },
+ 2: {
+ "rx_bps": {
+ "0": 0,
+ "1": 0,
+ "total": 0
+ },
+ "rx_bps_l1": {
+ "0": 0.0,
+ "1": 0.0,
+ "total": 0.0
+ },
+ "rx_bytes": {
+ "0": 0,
+ "1": 6464,
+ "total": 6464
+ },
+ "rx_pkts": {
+ "0": 0,
+ "1": 101,
+ "total": 101
+ },
+ "rx_pps": {
+ "0": 0,
+ "1": 0,
+ "total": 0
+ },
+ "tx_bps": {
+ "0": 0,
+ "1": 0,
+ "total": 0
+ },
+ "tx_bps_l1": {
+ "0": 0.0,
+ "1": 0.0,
+ "total": 0.0
+ },
+ "tx_bytes": {
+ "0": 6464,
+ "1": 0,
+ "total": 6464
+ },
+ "tx_pkts": {
+ "0": 101,
+ "1": 0,
+ "total": 101
+ },
+ "tx_pps": {
+ "0": 0,
+ "1": 0,
+ "total": 0
+ }
+ },
+ "global": {
+ "rx_err": {
+ "0": 0,
+ "1": 0
+ },
+ "tx_err": {
+ "0": 0,
+ "1": 0
+ }
+ }
+ },
+ "global": {
+ "bw_per_core": 45.6,
+ "cpu_util": 0.1494,
+ "queue_full": 0,
+ "rx_bps": 238458672.0,
+ "rx_cpu_util": 4.751e-05,
+ "rx_drop_bps": 0.0,
+ "rx_pps": 465739.6,
+ "tx_bps": 238464208.0,
+ "tx_pps": 465750.4
+ },
+ "latency": {
+ 1: {
+ "err_cntrs": {
+ "dropped": 0,
+ "dup": 0,
+ "out_of_order": 0,
+ "seq_too_high": 0,
+ "seq_too_low": 0
+ },
+ "latency": {
+ "average": 63.375,
+ "histogram": {
+ "20": 1,
+ "30": 18,
+ "40": 12,
+ "50": 10,
+ "60": 12,
+ "70": 11,
+ "80": 6,
+ "90": 10,
+ "100": 20
+ },
+ "jitter": 23,
+ "last_max": 122,
+ "total_max": 123,
+ "total_min": 20
+ }
+ },
+ 2: {
+ "err_cntrs": {
+ "dropped": 0,
+ "dup": 0,
+ "out_of_order": 0,
+ "seq_too_high": 0,
+ "seq_too_low": 0
+ },
+ "latency": {
+ "average": 74,
+ "histogram": {
+ "60": 20,
+ "70": 10,
+ "80": 3,
+ "90": 4,
+ "100": 64
+ },
+ "jitter": 6,
+ "last_max": 83,
+ "total_max": 135,
+ "total_min": 60
+ }
+ },
+ "global": {
+ "bad_hdr": 0,
+ "old_flow": 0
+ }
+ },
+ "total": {
+ "ibytes": 111098816,
+ "ierrors": 0,
+ "ipackets": 1735919,
+ "obytes": 111098816,
+ "oerrors": 0,
+ "opackets": 1735919,
+ "rx_bps": 238458680.0,
+ "rx_bps_L1": 312977016.0,
+ "rx_pps": 465739.6,
+ "rx_util": 3.1297701599999996,
+ "tx_bps": 238464200.0,
+ "tx_bps_L1": 312984264.0,
+ "tx_pps": 465750.4,
+ "tx_util": 3.12984264
+ }
+ }
+ expected = {
+ "xe0": {
+ "in_packets": 867955,
+ "latency": {
+ 2: {
+ "avg_latency": 74.0,
+ "max_latency": 135.0,
+ "min_latency": 60.0
+ }
+ },
+ "out_packets": 867964,
+ "rx_throughput_bps": 104339032.0,
+ "rx_throughput_fps": 203787.2,
+ "tx_throughput_bps": 134126008.0,
+ "tx_throughput_fps": 261964.9
+ },
+ "xe1": {
+ "in_packets": 867964,
+ "latency": {
+ 1: {
+ "avg_latency": 63.375,
+ "max_latency": 123.0,
+ "min_latency": 20.0
+ }
+ },
+ "out_packets": 867955,
+ "rx_throughput_bps": 134119648.0,
+ "rx_throughput_fps": 261952.4,
+ "tx_throughput_bps": 104338192.0,
+ "tx_throughput_fps": 203785.5
+ }
+ }
+ mock_setup_helper = mock.Mock()
+ vpp_rfc = tg_trex_vpp.TrexVppResourceHelper(mock_setup_helper)
+ vpp_rfc.vnfd_helper = base.VnfdHelper(TestTrexTrafficGenVpp.VNFD_0)
+ port_pg_id = rfc2544.PortPgIDMap()
+ port_pg_id.add_port(1)
+ port_pg_id.increase_pg_id()
+ port_pg_id.add_port(0)
+ port_pg_id.increase_pg_id()
+ self.assertEqual(expected,
+ vpp_rfc.generate_samples(stats, [0, 1], port_pg_id,
+ True))
+
+ def test_generate_samples_error(self):
+ stats = {
+ 0: {
+ "ibytes": 55549120,
+ "ierrors": 0,
+ "ipackets": 867955,
+ "obytes": 55549696,
+ "oerrors": 0,
+ "opackets": 867964,
+ "rx_bps": 104339032.0,
+ "rx_bps_L1": 136944984.0,
+ "rx_pps": 203787.2,
+ "rx_util": 1.36944984,
+ "tx_bps": 134126008.0,
+ "tx_bps_L1": 176040392.0,
+ "tx_pps": 261964.9,
+ "tx_util": 1.7604039200000001
+ },
+ 1: {
+ "ibytes": 55549696,
+ "ierrors": 0,
+ "ipackets": 867964,
+ "obytes": 55549120,
+ "oerrors": 0,
+ "opackets": 867955,
+ "rx_bps": 134119648.0,
+ "rx_bps_L1": 176032032.0,
+ "rx_pps": 261952.4,
+ "rx_util": 1.76032032,
+ "tx_bps": 104338192.0,
+ "tx_bps_L1": 136943872.0,
+ "tx_pps": 203785.5,
+ "tx_util": 1.36943872
+ },
+ "flow_stats": {
+ 1: {
+ "rx_bps": {
+ "0": 0,
+ "1": 0,
+ "total": 0
+ },
+ "rx_bps_l1": {
+ "0": 0.0,
+ "1": 0.0,
+ "total": 0.0
+ },
+ "rx_bytes": {
+ "0": 6400,
+ "1": 0,
+ "total": 6400
+ },
+ "rx_pkts": {
+ "0": 100,
+ "1": 0,
+ "total": 100
+ },
+ "rx_pps": {
+ "0": 0,
+ "1": 0,
+ "total": 0
+ },
+ "tx_bps": {
+ "0": 0,
+ "1": 0,
+ "total": 0
+ },
+ "tx_bps_l1": {
+ "0": 0.0,
+ "1": 0.0,
+ "total": 0.0
+ },
+ "tx_bytes": {
+ "0": 0,
+ "1": 6400,
+ "total": 6400
+ },
+ "tx_pkts": {
+ "0": 0,
+ "1": 100,
+ "total": 100
+ },
+ "tx_pps": {
+ "0": 0,
+ "1": 0,
+ "total": 0
+ }
+ },
+ 2: {
+ "rx_bps": {
+ "0": 0,
+ "1": 0,
+ "total": 0
+ },
+ "rx_bps_l1": {
+ "0": 0.0,
+ "1": 0.0,
+ "total": 0.0
+ },
+ "rx_bytes": {
+ "0": 0,
+ "1": 6464,
+ "total": 6464
+ },
+ "rx_pkts": {
+ "0": 0,
+ "1": 101,
+ "total": 101
+ },
+ "rx_pps": {
+ "0": 0,
+ "1": 0,
+ "total": 0
+ },
+ "tx_bps": {
+ "0": 0,
+ "1": 0,
+ "total": 0
+ },
+ "tx_bps_l1": {
+ "0": 0.0,
+ "1": 0.0,
+ "total": 0.0
+ },
+ "tx_bytes": {
+ "0": 6464,
+ "1": 0,
+ "total": 6464
+ },
+ "tx_pkts": {
+ "0": 101,
+ "1": 0,
+ "total": 101
+ },
+ "tx_pps": {
+ "0": 0,
+ "1": 0,
+ "total": 0
+ }
+ },
+ "global": {
+ "rx_err": {
+ "0": 0,
+ "1": 0
+ },
+ "tx_err": {
+ "0": 0,
+ "1": 0
+ }
+ }
+ },
+ "global": {
+ "bw_per_core": 45.6,
+ "cpu_util": 0.1494,
+ "queue_full": 0,
+ "rx_bps": 238458672.0,
+ "rx_cpu_util": 4.751e-05,
+ "rx_drop_bps": 0.0,
+ "rx_pps": 465739.6,
+ "tx_bps": 238464208.0,
+ "tx_pps": 465750.4
+ },
+ "latency": {
+ 1: {
+ "err_cntrs": {
+ "dropped": 0,
+ "dup": 0,
+ "out_of_order": 0,
+ "seq_too_high": 0,
+ "seq_too_low": 0
+ },
+ "latency": {
+ "average": "err",
+ "histogram": {
+ "20": 1,
+ "30": 18,
+ "40": 12,
+ "50": 10,
+ "60": 12,
+ "70": 11,
+ "80": 6,
+ "90": 10,
+ "100": 20
+ },
+ "jitter": 23,
+ "last_max": 122,
+ "total_max": "err",
+ "total_min": "err"
+ }
+ },
+ 2: {
+ "err_cntrs": {
+ "dropped": 0,
+ "dup": 0,
+ "out_of_order": 0,
+ "seq_too_high": 0,
+ "seq_too_low": 0
+ },
+ "latency": {
+ "average": 74,
+ "histogram": {
+ "60": 20,
+ "70": 10,
+ "80": 3,
+ "90": 4,
+ "100": 64
+ },
+ "jitter": 6,
+ "last_max": 83,
+ "total_max": 135,
+ "total_min": 60
+ }
+ },
+ "global": {
+ "bad_hdr": 0,
+ "old_flow": 0
+ }
+ },
+ "total": {
+ "ibytes": 111098816,
+ "ierrors": 0,
+ "ipackets": 1735919,
+ "obytes": 111098816,
+ "oerrors": 0,
+ "opackets": 1735919,
+ "rx_bps": 238458680.0,
+ "rx_bps_L1": 312977016.0,
+ "rx_pps": 465739.6,
+ "rx_util": 3.1297701599999996,
+ "tx_bps": 238464200.0,
+ "tx_bps_L1": 312984264.0,
+ "tx_pps": 465750.4,
+ "tx_util": 3.12984264
+ }
+ }
+ expected = {'xe0': {'in_packets': 867955,
+ 'latency': {2: {'avg_latency': 74.0,
+ 'max_latency': 135.0,
+ 'min_latency': 60.0}},
+ 'out_packets': 867964,
+ 'rx_throughput_bps': 104339032.0,
+ 'rx_throughput_fps': 203787.2,
+ 'tx_throughput_bps': 134126008.0,
+ 'tx_throughput_fps': 261964.9},
+ 'xe1': {'in_packets': 867964,
+ 'latency': {1: {'avg_latency': -1.0,
+ 'max_latency': -1.0,
+ 'min_latency': -1.0}},
+ 'out_packets': 867955,
+ 'rx_throughput_bps': 134119648.0,
+ 'rx_throughput_fps': 261952.4,
+ 'tx_throughput_bps': 104338192.0,
+ 'tx_throughput_fps': 203785.5}}
+ mock_setup_helper = mock.Mock()
+ vpp_rfc = tg_trex_vpp.TrexVppResourceHelper(mock_setup_helper)
+ vpp_rfc.vnfd_helper = base.VnfdHelper(TestTrexTrafficGenVpp.VNFD_0)
+ vpp_rfc.get_stats = mock.Mock()
+ vpp_rfc.get_stats.return_value = stats
+ port_pg_id = rfc2544.PortPgIDMap()
+ port_pg_id.add_port(1)
+ port_pg_id.increase_pg_id()
+ port_pg_id.add_port(0)
+ port_pg_id.increase_pg_id()
+ self.assertEqual(expected,
+ vpp_rfc.generate_samples(stats=None, ports=[0, 1],
+ port_pg_id=port_pg_id,
+ latency=True))
+
+ def test__run_traffic_once(self):
+ mock_setup_helper = mock.Mock()
+ mock_traffic_profile = mock.Mock()
+ vpp_rfc = tg_trex_vpp.TrexVppResourceHelper(mock_setup_helper)
+ vpp_rfc.TRANSIENT_PERIOD = 0
+ vpp_rfc.rfc2544_helper = mock.Mock()
+
+ self.assertTrue(vpp_rfc._run_traffic_once(mock_traffic_profile))
+ mock_traffic_profile.execute_traffic.assert_called_once_with(vpp_rfc)
+
+ def test_run_traffic(self):
+ mock_traffic_profile = mock.Mock(autospec=tp_base.TrafficProfile)
+ mock_traffic_profile.get_traffic_definition.return_value = "64"
+ mock_traffic_profile.params = self.TRAFFIC_PROFILE
+ mock_setup_helper = mock.Mock()
+ vpp_rfc = tg_trex_vpp.TrexVppResourceHelper(mock_setup_helper)
+ vpp_rfc.ssh_helper = mock.Mock()
+ vpp_rfc.ssh_helper.run = mock.Mock()
+ vpp_rfc._traffic_runner = mock.Mock(return_value=0)
+ vpp_rfc._build_ports = mock.Mock()
+ vpp_rfc._connect = mock.Mock()
+ vpp_rfc.run_traffic(mock_traffic_profile)
+
+ def test_send_traffic_on_tg(self):
+ stats = {
+ 0: {
+ "ibytes": 55549120,
+ "ierrors": 0,
+ "ipackets": 867955,
+ "obytes": 55549696,
+ "oerrors": 0,
+ "opackets": 867964,
+ "rx_bps": 104339032.0,
+ "rx_bps_L1": 136944984.0,
+ "rx_pps": 203787.2,
+ "rx_util": 1.36944984,
+ "tx_bps": 134126008.0,
+ "tx_bps_L1": 176040392.0,
+ "tx_pps": 261964.9,
+ "tx_util": 1.7604039200000001
+ },
+ 1: {
+ "ibytes": 55549696,
+ "ierrors": 0,
+ "ipackets": 867964,
+ "obytes": 55549120,
+ "oerrors": 0,
+ "opackets": 867955,
+ "rx_bps": 134119648.0,
+ "rx_bps_L1": 176032032.0,
+ "rx_pps": 261952.4,
+ "rx_util": 1.76032032,
+ "tx_bps": 104338192.0,
+ "tx_bps_L1": 136943872.0,
+ "tx_pps": 203785.5,
+ "tx_util": 1.36943872
+ },
+ "flow_stats": {
+ 1: {
+ "rx_bps": {
+ "0": 0,
+ "1": 0,
+ "total": 0
+ },
+ "rx_bps_l1": {
+ "0": 0.0,
+ "1": 0.0,
+ "total": 0.0
+ },
+ "rx_bytes": {
+ "0": 6400,
+ "1": 0,
+ "total": 6400
+ },
+ "rx_pkts": {
+ "0": 100,
+ "1": 0,
+ "total": 100
+ },
+ "rx_pps": {
+ "0": 0,
+ "1": 0,
+ "total": 0
+ },
+ "tx_bps": {
+ "0": 0,
+ "1": 0,
+ "total": 0
+ },
+ "tx_bps_l1": {
+ "0": 0.0,
+ "1": 0.0,
+ "total": 0.0
+ },
+ "tx_bytes": {
+ "0": 0,
+ "1": 6400,
+ "total": 6400
+ },
+ "tx_pkts": {
+ "0": 0,
+ "1": 100,
+ "total": 100
+ },
+ "tx_pps": {
+ "0": 0,
+ "1": 0,
+ "total": 0
+ }
+ },
+ 2: {
+ "rx_bps": {
+ "0": 0,
+ "1": 0,
+ "total": 0
+ },
+ "rx_bps_l1": {
+ "0": 0.0,
+ "1": 0.0,
+ "total": 0.0
+ },
+ "rx_bytes": {
+ "0": 0,
+ "1": 6464,
+ "total": 6464
+ },
+ "rx_pkts": {
+ "0": 0,
+ "1": 101,
+ "total": 101
+ },
+ "rx_pps": {
+ "0": 0,
+ "1": 0,
+ "total": 0
+ },
+ "tx_bps": {
+ "0": 0,
+ "1": 0,
+ "total": 0
+ },
+ "tx_bps_l1": {
+ "0": 0.0,
+ "1": 0.0,
+ "total": 0.0
+ },
+ "tx_bytes": {
+ "0": 6464,
+ "1": 0,
+ "total": 6464
+ },
+ "tx_pkts": {
+ "0": 101,
+ "1": 0,
+ "total": 101
+ },
+ "tx_pps": {
+ "0": 0,
+ "1": 0,
+ "total": 0
+ }
+ },
+ "global": {
+ "rx_err": {
+ "0": 0,
+ "1": 0
+ },
+ "tx_err": {
+ "0": 0,
+ "1": 0
+ }
+ }
+ },
+ "global": {
+ "bw_per_core": 45.6,
+ "cpu_util": 0.1494,
+ "queue_full": 0,
+ "rx_bps": 238458672.0,
+ "rx_cpu_util": 4.751e-05,
+ "rx_drop_bps": 0.0,
+ "rx_pps": 465739.6,
+ "tx_bps": 238464208.0,
+ "tx_pps": 465750.4
+ },
+ "latency": {
+ 1: {
+ "err_cntrs": {
+ "dropped": 0,
+ "dup": 0,
+ "out_of_order": 0,
+ "seq_too_high": 0,
+ "seq_too_low": 0
+ },
+ "latency": {
+ "average": 63.375,
+ "histogram": {
+ "20": 1,
+ "30": 18,
+ "40": 12,
+ "50": 10,
+ "60": 12,
+ "70": 11,
+ "80": 6,
+ "90": 10,
+ "100": 20
+ },
+ "jitter": 23,
+ "last_max": 122,
+ "total_max": 123,
+ "total_min": 20
+ }
+ },
+ 2: {
+ "err_cntrs": {
+ "dropped": 0,
+ "dup": 0,
+ "out_of_order": 0,
+ "seq_too_high": 0,
+ "seq_too_low": 0
+ },
+ "latency": {
+ "average": 74,
+ "histogram": {
+ "60": 20,
+ "70": 10,
+ "80": 3,
+ "90": 4,
+ "100": 64
+ },
+ "jitter": 6,
+ "last_max": 83,
+ "total_max": 135,
+ "total_min": 60
+ }
+ },
+ "global": {
+ "bad_hdr": 0,
+ "old_flow": 0
+ }
+ },
+ "total": {
+ "ibytes": 111098816,
+ "ierrors": 0,
+ "ipackets": 1735919,
+ "obytes": 111098816,
+ "oerrors": 0,
+ "opackets": 1735919,
+ "rx_bps": 238458680.0,
+ "rx_bps_L1": 312977016.0,
+ "rx_pps": 465739.6,
+ "rx_util": 3.1297701599999996,
+ "tx_bps": 238464200.0,
+ "tx_bps_L1": 312984264.0,
+ "tx_pps": 465750.4,
+ "tx_util": 3.12984264
+ }
+ }
+ mock_setup_helper = mock.Mock()
+ vpp_rfc = tg_trex_vpp.TrexVppResourceHelper(mock_setup_helper)
+ vpp_rfc.vnfd_helper = base.VnfdHelper(TestTrexTrafficGenVpp.VNFD_0)
+ vpp_rfc.client = mock.Mock()
+ vpp_rfc.client.get_warnings.return_value = 'get_warnings'
+ vpp_rfc.client.get_stats.return_value = stats
+ port_pg_id = rfc2544.PortPgIDMap()
+ port_pg_id.add_port(1)
+ port_pg_id.increase_pg_id()
+ port_pg_id.add_port(0)
+ port_pg_id.increase_pg_id()
+ self.assertEqual(stats,
+ vpp_rfc.send_traffic_on_tg([0, 1], port_pg_id, 30,
+ 10000, True))
+
+ def test_send_traffic_on_tg_error(self):
+ mock_setup_helper = mock.Mock()
+ vpp_rfc = tg_trex_vpp.TrexVppResourceHelper(mock_setup_helper)
+ vpp_rfc.vnfd_helper = base.VnfdHelper(TestTrexTrafficGenVpp.VNFD_0)
+ vpp_rfc.client = mock.Mock()
+ vpp_rfc.client.get_warnings.return_value = 'get_warnings'
+ vpp_rfc.client.get_stats.side_effect = STLError('get_stats')
+ vpp_rfc.client.wait_on_traffic.side_effect = STLError(
+ 'wait_on_traffic')
+ port_pg_id = rfc2544.PortPgIDMap()
+ port_pg_id.add_port(1)
+ port_pg_id.increase_pg_id()
+ port_pg_id.add_port(0)
+ port_pg_id.increase_pg_id()
+ # with self.assertRaises(RuntimeError) as raised:
+ vpp_rfc.send_traffic_on_tg([0, 1], port_pg_id, 30, 10000, True)
+ # self.assertIn('TRex stateless runtime error', str(raised.exception))
+
+
+class TestTrexTrafficGenVpp(unittest.TestCase):
+ VNFD_0 = {
+ "benchmark": {
+ "kpi": [
+ "rx_throughput_fps",
+ "tx_throughput_fps",
+ "tx_throughput_mbps",
+ "rx_throughput_mbps",
+ "in_packets",
+ "out_packets",
+ "min_latency",
+ "max_latency",
+ "avg_latency"
+ ]
+ },
+ "description": "TRex stateless traffic verifier",
+ "id": "TrexTrafficGenVpp",
+ "mgmt-interface": {
+ "ip": "10.10.10.10",
+ "password": "r00t",
+ "user": "root",
+ "vdu-id": "trexgen-baremetal"
+ },
+ "name": "trexverifier",
+ "short-name": "trexverifier",
+ "vdu": [
+ {
+ "description": "TRex stateless traffic verifier",
+ "external-interface": [
+ {
+ "name": "xe0",
+ "virtual-interface": {
+ "dpdk_port_num": 0,
+ "driver": "igb_uio",
+ "dst_ip": "192.168.100.2",
+ "dst_mac": "90:e2:ba:7c:41:a8",
+ "ifname": "xe0",
+ "local_ip": "192.168.100.1",
+ "local_mac": "90:e2:ba:7c:30:e8",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "tg__0",
+ "peer_ifname": "xe0",
+ "peer_intf": {
+ "driver": "igb_uio",
+ "dst_ip": "192.168.100.1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "ifname": "xe0",
+ "local_ip": "192.168.100.2",
+ "local_mac": "90:e2:ba:7c:41:a8",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "vnf__0",
+ "peer_ifname": "xe0",
+ "peer_name": "tg__0",
+ "vld_id": "uplink_0",
+ "vpci": "0000:ff:06.0"
+ },
+ "peer_name": "vnf__0",
+ "vld_id": "uplink_0",
+ "vpci": "0000:81:00.0"
+ },
+ "vnfd-connection-point-ref": "xe0"
+ },
+ {
+ "name": "xe1",
+ "virtual-interface": {
+ "dpdk_port_num": 1,
+ "driver": "igb_uio",
+ "dst_ip": "192.168.101.2",
+ "dst_mac": "90:e2:ba:7c:41:a9",
+ "ifname": "xe1",
+ "local_ip": "192.168.101.1",
+ "local_mac": "90:e2:ba:7c:30:e9",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "tg__0",
+ "peer_ifname": "xe0",
+ "peer_intf": {
+ "driver": "igb_uio",
+ "dst_ip": "192.168.101.1",
+ "dst_mac": "90:e2:ba:7c:30:e9",
+ "ifname": "xe0",
+ "local_ip": "192.168.101.2",
+ "local_mac": "90:e2:ba:7c:41:a9",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "vnf__1",
+ "peer_ifname": "xe1",
+ "peer_name": "tg__0",
+ "vld_id": "downlink_0",
+ "vpci": "0000:ff:06.0"
+ },
+ "peer_name": "vnf__1",
+ "vld_id": "downlink_0",
+ "vpci": "0000:81:00.1"
+ },
+ "vnfd-connection-point-ref": "xe1"
+ }
+ ],
+ "id": "trexgen-baremetal",
+ "name": "trexgen-baremetal"
+ }
+ ]
+ }
+
+ VNFD = {
+ 'vnfd:vnfd-catalog': {
+ 'vnfd': [
+ VNFD_0,
+ ],
+ },
+ }
+
+ def setUp(self):
+ self._mock_ssh_helper = mock.patch.object(sample_vnf, 'VnfSshHelper')
+ self.mock_ssh_helper = self._mock_ssh_helper.start()
+ self.addCleanup(self._stop_mocks)
+
+ def _stop_mocks(self):
+ self._mock_ssh_helper.stop()
+
+ def test___init__(self):
+ trex_traffic_gen = tg_trex_vpp.TrexTrafficGenVpp(
+ 'tg0', self.VNFD_0)
+ self.assertIsNotNone(
+ trex_traffic_gen.resource_helper._terminated.value)
+
+ def test__check_status(self):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ trex_traffic_gen = tg_trex_vpp.TrexTrafficGenVpp('tg0', vnfd)
+ trex_traffic_gen.ssh_helper = mock.MagicMock()
+ trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock()
+ trex_traffic_gen.resource_helper.ssh_helper.execute.return_value = 0, '', ''
+ trex_traffic_gen.scenario_helper.scenario_cfg = {}
+ self.assertEqual(0, trex_traffic_gen._check_status())
+
+ def test__start_server(self):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ trex_traffic_gen = tg_trex_vpp.TrexTrafficGenVpp('tg0', vnfd)
+ trex_traffic_gen.ssh_helper = mock.MagicMock()
+ trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock()
+ trex_traffic_gen.scenario_helper.scenario_cfg = {}
+ self.assertIsNone(trex_traffic_gen._start_server())
+
+ @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server',
+ return_value='mock_node')
+ def test_collect_kpi(self, *args):
+ trex_traffic_gen = tg_trex_vpp.TrexTrafficGenVpp(
+ 'tg0', self.VNFD_0)
+ trex_traffic_gen.scenario_helper.scenario_cfg = {
+ 'nodes': {trex_traffic_gen.name: "mock"}
+ }
+ expected = {
+ 'physical_node': 'mock_node',
+ 'collect_stats': {},
+ }
+ self.assertEqual(trex_traffic_gen.collect_kpi(), expected)
+
+ @mock.patch.object(ctx_base.Context, 'get_context_from_server',
+ return_value='fake_context')
+ def test_instantiate(self, *args):
+ trex_traffic_gen = tg_trex_vpp.TrexTrafficGenVpp(
+ 'tg0', self.VNFD_0)
+ trex_traffic_gen._start_server = mock.Mock(return_value=0)
+ trex_traffic_gen.resource_helper = mock.MagicMock()
+ trex_traffic_gen.setup_helper.setup_vnf_environment = mock.MagicMock()
+
+ scenario_cfg = {
+ "tc": "tc_baremetal_rfc2544_ipv4_1flow_64B",
+ "topology": 'nsb_test_case.yaml',
+ 'options': {
+ 'packetsize': 64,
+ 'traffic_type': 4,
+ 'rfc2544': {
+ 'allowed_drop_rate': '0.8 - 1',
+ },
+ 'vnf__0': {
+ 'rules': 'acl_1rule.yaml',
+ 'vnf_config': {
+ 'lb_config': 'SW',
+ 'lb_count': 1,
+ 'worker_config': '1C/1T',
+ 'worker_threads': 1
+ },
+ },
+ },
+ }
+ tg_trex_vpp.WAIT_TIME = 3
+ scenario_cfg.update({"nodes": {"tg0": {}, "vnf0": {}}})
+ self.assertIsNone(trex_traffic_gen.instantiate(scenario_cfg, {}))
+
+ @mock.patch.object(ctx_base.Context, 'get_context_from_server',
+ return_value='fake_context')
+ def test_instantiate_error(self, *args):
+ trex_traffic_gen = tg_trex_vpp.TrexTrafficGenVpp(
+ 'tg0', self.VNFD_0)
+ trex_traffic_gen.resource_helper = mock.MagicMock()
+ trex_traffic_gen.setup_helper.setup_vnf_environment = mock.MagicMock()
+ scenario_cfg = {
+ "tc": "tc_baremetal_rfc2544_ipv4_1flow_64B",
+ "nodes": {
+ "tg0": {},
+ "vnf0": {}
+ },
+ "topology": 'nsb_test_case.yaml',
+ 'options': {
+ 'packetsize': 64,
+ 'traffic_type': 4,
+ 'rfc2544': {
+ 'allowed_drop_rate': '0.8 - 1',
+ },
+ 'vnf__0': {
+ 'rules': 'acl_1rule.yaml',
+ 'vnf_config': {
+ 'lb_config': 'SW',
+ 'lb_count': 1,
+ 'worker_config': '1C/1T',
+ 'worker_threads': 1,
+ },
+ },
+ },
+ }
+ trex_traffic_gen.instantiate(scenario_cfg, {})
+
+ @mock.patch(
+ 'yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper')
+ def test_wait_for_instantiate(self, ssh, *args):
+ mock_ssh(ssh)
+
+ mock_process = mock.Mock(autospec=Process)
+ mock_process.is_alive.return_value = True
+ mock_process.exitcode = 432
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ trex_traffic_gen = tg_trex_vpp.TrexTrafficGenVpp('tg0', vnfd)
+ trex_traffic_gen.ssh_helper = mock.MagicMock()
+ trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock()
+ trex_traffic_gen.resource_helper.ssh_helper.execute.return_value = 0, '', ''
+ trex_traffic_gen.scenario_helper.scenario_cfg = {}
+ trex_traffic_gen._tg_process = mock_process
+ self.assertEqual(432, trex_traffic_gen.wait_for_instantiate())
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_vcmts_pktgen.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_vcmts_pktgen.py
new file mode 100755
index 000000000..3b226d3f1
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_vcmts_pktgen.py
@@ -0,0 +1,652 @@
+# Copyright (c) 2019 Viosoft 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.
+
+import unittest
+import mock
+import socket
+import threading
+import time
+import os
+import copy
+
+from yardstick.benchmark.contexts import base as ctx_base
+from yardstick.network_services.vnf_generic.vnf.base import VnfdHelper
+from yardstick.network_services.vnf_generic.vnf import tg_vcmts_pktgen
+from yardstick.common import exceptions
+
+
+NAME = "tg__0"
+
+
+class TestPktgenHelper(unittest.TestCase):
+
+ def test___init__(self):
+ pktgen_helper = tg_vcmts_pktgen.PktgenHelper("localhost", 23000)
+ self.assertEqual(pktgen_helper.host, "localhost")
+ self.assertEqual(pktgen_helper.port, 23000)
+ self.assertFalse(pktgen_helper.connected)
+
+ def _run_fake_server(self):
+ server_sock = socket.socket()
+ server_sock.bind(('localhost', 23000))
+ server_sock.listen(0)
+ client_socket, _ = server_sock.accept()
+ client_socket.close()
+ server_sock.close()
+
+ def test__connect(self):
+ pktgen_helper = tg_vcmts_pktgen.PktgenHelper("localhost", 23000)
+ self.assertFalse(pktgen_helper._connect())
+ server_thread = threading.Thread(target=self._run_fake_server)
+ server_thread.start()
+ time.sleep(0.5)
+ self.assertTrue(pktgen_helper._connect())
+ pktgen_helper._sock.close()
+ server_thread.join()
+
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.tg_vcmts_pktgen.time')
+ def test_connect(self, *args):
+ pktgen_helper = tg_vcmts_pktgen.PktgenHelper("localhost", 23000)
+ pktgen_helper.connected = True
+ self.assertTrue(pktgen_helper.connect())
+ pktgen_helper.connected = False
+
+ pktgen_helper._connect = mock.MagicMock(return_value=True)
+ self.assertTrue(pktgen_helper.connect())
+ self.assertTrue(pktgen_helper.connected)
+
+ pktgen_helper = tg_vcmts_pktgen.PktgenHelper("localhost", 23000)
+ pktgen_helper._connect = mock.MagicMock(return_value=False)
+ self.assertFalse(pktgen_helper.connect())
+ self.assertFalse(pktgen_helper.connected)
+
+ def test_send_command(self):
+ pktgen_helper = tg_vcmts_pktgen.PktgenHelper("localhost", 23000)
+ self.assertFalse(pktgen_helper.send_command(""))
+
+ pktgen_helper.connected = True
+ pktgen_helper._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.assertFalse(pktgen_helper.send_command(""))
+
+ pktgen_helper._sock = mock.MagicMock()
+ self.assertTrue(pktgen_helper.send_command(""))
+
+
+class TestVcmtsPktgenSetupEnvHelper(unittest.TestCase):
+
+ PKTGEN_PARAMETERS = "export LUA_PATH=/vcmts/Pktgen.lua;"\
+ "export CMK_PROC_FS=/host/proc;"\
+ " /pktgen-config/setup.sh 0 4 18:02.0 "\
+ "18:02.1 18:02.2 18:02.3 00:00.0 00:00.0 "\
+ "00:00.0 00:00.0 imix1_100cms_1ofdm.pcap "\
+ "imix1_100cms_1ofdm.pcap imix1_100cms_1ofdm.pcap "\
+ "imix1_100cms_1ofdm.pcap imix1_100cms_1ofdm.pcap "\
+ "imix1_100cms_1ofdm.pcap imix1_100cms_1ofdm.pcap "\
+ "imix1_100cms_1ofdm.pcap"
+
+ OPTIONS = {
+ "pktgen_values": "/tmp/pktgen_values.yaml",
+ "tg__0": {
+ "pktgen_id": 0
+ },
+ "vcmts_influxdb_ip": "10.80.5.150",
+ "vcmts_influxdb_port": 8086,
+ "vcmtsd_values": "/tmp/vcmtsd_values.yaml",
+ "vnf__0": {
+ "sg_id": 0,
+ "stream_dir": "us"
+ },
+ "vnf__1": {
+ "sg_id": 0,
+ "stream_dir": "ds"
+ }
+ }
+
+ def setUp(self):
+ vnfd_helper = VnfdHelper(
+ TestVcmtsPktgen.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS
+
+ self.setup_helper = tg_vcmts_pktgen.VcmtsPktgenSetupEnvHelper(
+ vnfd_helper, ssh_helper, scenario_helper)
+
+ def test_generate_pcap_filename(self):
+ pcap_file_name = self.setup_helper.generate_pcap_filename(\
+ TestVcmtsPktgen.PKTGEN_POD_VALUES[0]['ports'][0])
+ self.assertEquals(pcap_file_name, "imix1_100cms_1ofdm.pcap")
+
+ def test_find_port_cfg(self):
+ port_cfg = self.setup_helper.find_port_cfg(\
+ TestVcmtsPktgen.PKTGEN_POD_VALUES[0]['ports'], "port_0")
+ self.assertIsNotNone(port_cfg)
+
+ port_cfg = self.setup_helper.find_port_cfg(\
+ TestVcmtsPktgen.PKTGEN_POD_VALUES[0]['ports'], "port_8")
+ self.assertIsNone(port_cfg)
+
+ def test_build_pktgen_parameters(self):
+ parameters = self.setup_helper.build_pktgen_parameters(
+ TestVcmtsPktgen.PKTGEN_POD_VALUES[0])
+ self.assertEquals(parameters, self.PKTGEN_PARAMETERS)
+
+ def test_start_pktgen(self):
+ self.setup_helper.ssh_helper = mock.MagicMock()
+ self.setup_helper.start_pktgen(TestVcmtsPktgen.PKTGEN_POD_VALUES[0])
+ self.setup_helper.ssh_helper.send_command.assert_called_with(
+ self.PKTGEN_PARAMETERS)
+
+ def test_setup_vnf_environment(self):
+ self.assertIsNone(self.setup_helper.setup_vnf_environment())
+
+class TestVcmtsPktgen(unittest.TestCase):
+
+ VNFD = {'vnfd:vnfd-catalog':
+ {'vnfd':
+ [{
+ "benchmark": {
+ "kpi": [
+ "upstream/bits_per_second"
+ ]
+ },
+ "connection-point": [
+ {
+ "name": "xe0",
+ "type": "VPORT"
+ },
+ {
+ "name": "xe1",
+ "type": "VPORT"
+ }
+ ],
+ "description": "vCMTS Pktgen Kubernetes",
+ "id": "VcmtsPktgen",
+ "mgmt-interface": {
+ "ip": "192.168.24.150",
+ "key_filename": "/tmp/yardstick_key-a3b663c2",
+ "user": "root",
+ "vdu-id": "vcmtspktgen-kubernetes"
+ },
+ "name": "vcmtspktgen",
+ "short-name": "vcmtspktgen",
+ "vdu": [
+ {
+ "description": "vCMTS Pktgen Kubernetes",
+ "external-interface": [],
+ "id": "vcmtspktgen-kubernetes",
+ "name": "vcmtspktgen-kubernetes"
+ }
+ ],
+ "vm-flavor": {
+ "memory-mb": "4096",
+ "vcpu-count": "4"
+ }
+ }]
+ }}
+
+ PKTGEN_POD_VALUES = [
+ {
+ "num_ports": "4",
+ "pktgen_id": "0",
+ "ports": [
+ {
+ "net_pktgen": "18:02.0",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "port_0": "",
+ "traffic_type": "imix1"
+ },
+ {
+ "net_pktgen": "18:02.1",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "port_1": "",
+ "traffic_type": "imix1"
+ },
+ {
+ "net_pktgen": "18:02.2",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "port_2": "",
+ "traffic_type": "imix1"
+ },
+ {
+ "net_pktgen": "18:02.3",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "port_3": "",
+ "traffic_type": "imix1"
+ },
+ {
+ "net_pktgen": "00:00.0",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "port_4": "",
+ "traffic_type": "imix1"
+ },
+ {
+ "net_pktgen": "00:00.0",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "port_5": "",
+ "traffic_type": "imix1"
+ },
+ {
+ "net_pktgen": "00:00.0",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "port_6": "",
+ "traffic_type": "imix1"
+ },
+ {
+ "net_pktgen": "00:00.0",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "port_7": "",
+ "traffic_type": "imix1"
+ }
+ ]
+ },
+ {
+ "num_ports": 4,
+ "pktgen_id": 1,
+ "ports": [
+ {
+ "net_pktgen": "18:0a.0",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "port_0": "",
+ "traffic_type": "imix1"
+ },
+ {
+ "net_pktgen": "18:0a.1",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "port_1": "",
+ "traffic_type": "imix1"
+ },
+ {
+ "net_pktgen": "18:0a.2",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "port_2": "",
+ "traffic_type": "imix1"
+ },
+ {
+ "net_pktgen": "18:0a.3",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "port_3": "",
+ "traffic_type": "imix1"
+ },
+ {
+ "net_pktgen": "00:00.0",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "port_4": "",
+ "traffic_type": "imix1"
+ },
+ {
+ "net_pktgen": "00:00.0",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "port_5": "",
+ "traffic_type": "imix1"
+ },
+ {
+ "net_pktgen": "00:00.0",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "port_6": "",
+ "traffic_type": "imix1"
+ },
+ {
+ "net_pktgen": "00:00.0",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "port_7": "",
+ "traffic_type": "imix1"
+ }
+ ]
+ }
+ ]
+
+ SCENARIO_CFG = {
+ "nodes": {
+ "tg__0": "pktgen0-k8syardstick-a3b663c2",
+ "vnf__0": "vnf0us-k8syardstick-a3b663c2",
+ "vnf__1": "vnf0ds-k8syardstick-a3b663c2"
+ },
+ "options": {
+ "pktgen_values": "/tmp/pktgen_values.yaml",
+ "tg__0": {
+ "pktgen_id": 0
+ },
+ "vcmts_influxdb_ip": "10.80.5.150",
+ "vcmts_influxdb_port": 8086,
+ "vcmtsd_values": "/tmp/vcmtsd_values.yaml",
+ "vnf__0": {
+ "sg_id": 0,
+ "stream_dir": "us"
+ },
+ "vnf__1": {
+ "sg_id": 0,
+ "stream_dir": "ds"
+ }
+ },
+ "task_id": "a3b663c2-e616-4777-b6d0-ec2ea7a06f42",
+ "task_path": "samples/vnf_samples/nsut/cmts",
+ "tc": "tc_vcmts_k8s_pktgen",
+ "topology": "k8s_vcmts_topology.yaml",
+ "traffic_profile": "../../traffic_profiles/fixed.yaml",
+ "type": "NSPerf"
+ }
+
+ CONTEXT_CFG = {
+ "networks": {
+ "flannel": {
+ "name": "flannel"
+ },
+ "xe0": {
+ "name": "xe0"
+ },
+ "xe1": {
+ "name": "xe1"
+ }
+ },
+ "nodes": {
+ "tg__0": {
+ "VNF model": "../../vnf_descriptors/tg_vcmts_tpl.yaml",
+ "interfaces": {
+ "flannel": {
+ "local_ip": "192.168.24.150",
+ "local_mac": None,
+ "network_name": "flannel"
+ },
+ "xe0": {
+ "local_ip": "192.168.24.150",
+ "local_mac": None,
+ "network_name": "xe0"
+ },
+ "xe1": {
+ "local_ip": "192.168.24.150",
+ "local_mac": None,
+ "network_name": "xe1"
+ }
+ },
+ "ip": "192.168.24.150",
+ "key_filename": "/tmp/yardstick_key-a3b663c2",
+ "member-vnf-index": "1",
+ "name": "pktgen0-k8syardstick-a3b663c2",
+ "private_ip": "192.168.24.150",
+ "service_ports": [
+ {
+ "name": "ssh",
+ "node_port": 60270,
+ "port": 22,
+ "protocol": "TCP",
+ "target_port": 22
+ },
+ {
+ "name": "lua",
+ "node_port": 43619,
+ "port": 22022,
+ "protocol": "TCP",
+ "target_port": 22022
+ }
+ ],
+ "ssh_port": 60270,
+ "user": "root",
+ "vnfd-id-ref": "tg__0"
+ },
+ "vnf__0": {
+ "VNF model": "../../vnf_descriptors/vnf_vcmts_tpl.yaml",
+ "interfaces": {
+ "flannel": {
+ "local_ip": "192.168.100.132",
+ "local_mac": None,
+ "network_name": "flannel"
+ },
+ "xe0": {
+ "local_ip": "192.168.100.132",
+ "local_mac": None,
+ "network_name": "xe0"
+ },
+ "xe1": {
+ "local_ip": "192.168.100.132",
+ "local_mac": None,
+ "network_name": "xe1"
+ }
+ },
+ "ip": "192.168.100.132",
+ "key_filename": "/tmp/yardstick_key-a3b663c2",
+ "member-vnf-index": "3",
+ "name": "vnf0us-k8syardstick-a3b663c2",
+ "private_ip": "192.168.100.132",
+ "service_ports": [
+ {
+ "name": "ssh",
+ "node_port": 57057,
+ "port": 22,
+ "protocol": "TCP",
+ "target_port": 22
+ },
+ {
+ "name": "lua",
+ "node_port": 29700,
+ "port": 22022,
+ "protocol": "TCP",
+ "target_port": 22022
+ }
+ ],
+ "ssh_port": 57057,
+ "user": "root",
+ "vnfd-id-ref": "vnf__0"
+ },
+ "vnf__1": {
+ "VNF model": "../../vnf_descriptors/vnf_vcmts_tpl.yaml",
+ "interfaces": {
+ "flannel": {
+ "local_ip": "192.168.100.134",
+ "local_mac": None,
+ "network_name": "flannel"
+ },
+ "xe0": {
+ "local_ip": "192.168.100.134",
+ "local_mac": None,
+ "network_name": "xe0"
+ },
+ "xe1": {
+ "local_ip": "192.168.100.134",
+ "local_mac": None,
+ "network_name": "xe1"
+ }
+ },
+ "ip": "192.168.100.134",
+ "key_filename": "/tmp/yardstick_key-a3b663c2",
+ "member-vnf-index": "4",
+ "name": "vnf0ds-k8syardstick-a3b663c2",
+ "private_ip": "192.168.100.134",
+ "service_ports": [
+ {
+ "name": "ssh",
+ "node_port": 18581,
+ "port": 22,
+ "protocol": "TCP",
+ "target_port": 22
+ },
+ {
+ "name": "lua",
+ "node_port": 18469,
+ "port": 22022,
+ "protocol": "TCP",
+ "target_port": 22022
+ }
+ ],
+ "ssh_port": 18581,
+ "user": "root",
+ "vnfd-id-ref": "vnf__1"
+ }
+ }
+ }
+
+ PKTGEN_VALUES_PATH = "/tmp/pktgen_values.yaml"
+
+ PKTGEN_VALUES = \
+ "serviceAccount: cmk-serviceaccount\n" \
+ "images:\n" \
+ " vcmts_pktgen: vcmts-pktgen:v18.10\n" \
+ "topology:\n" \
+ " pktgen_replicas: 8\n" \
+ " pktgen_pods:\n" \
+ " - pktgen_id: 0\n" \
+ " num_ports: 4\n" \
+ " ports:\n" \
+ " - port_0:\n" \
+ " traffic_type: 'imix2'\n" \
+ " num_ofdm: 4\n" \
+ " num_subs: 300\n" \
+ " net_pktgen: 8a:02.0\n" \
+ " - port_1:\n" \
+ " traffic_type: 'imix2'\n" \
+ " num_ofdm: 4\n" \
+ " num_subs: 300\n" \
+ " net_pktgen: 8a:02.1\n" \
+ " - port_2:\n" \
+ " traffic_type: 'imix2'\n" \
+ " num_ofdm: 4\n" \
+ " num_subs: 300\n" \
+ " net_pktgen: 8a:02.2\n" \
+ " - port_3:\n" \
+ " traffic_type: 'imix2'\n" \
+ " num_ofdm: 4\n" \
+ " num_subs: 300\n" \
+ " net_pktgen: 8a:02.3\n" \
+ " - port_4:\n" \
+ " traffic_type: 'imix2'\n" \
+ " num_ofdm: 4\n" \
+ " num_subs: 300\n" \
+ " net_pktgen: 8a:02.4\n" \
+ " - port_5:\n" \
+ " traffic_type: 'imix2'\n" \
+ " num_ofdm: 4\n" \
+ " num_subs: 300\n" \
+ " net_pktgen: 8a:02.5\n" \
+ " - port_6:\n" \
+ " traffic_type: 'imix2'\n" \
+ " num_ofdm: 4\n" \
+ " num_subs: 300\n" \
+ " net_pktgen: 8a:02.6\n" \
+ " - port_7:\n" \
+ " traffic_type: 'imix2'\n" \
+ " num_ofdm: 4\n" \
+ " num_subs: 300\n" \
+ " net_pktgen: 8a:02.7\n"
+
+ def setUp(self):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ self.vcmts_pktgen = tg_vcmts_pktgen.VcmtsPktgen(NAME, vnfd)
+ self.vcmts_pktgen._start_server = mock.Mock(return_value=0)
+ self.vcmts_pktgen.resource_helper = mock.MagicMock()
+ self.vcmts_pktgen.setup_helper = mock.MagicMock()
+
+ def test___init__(self):
+ self.assertFalse(self.vcmts_pktgen.traffic_finished)
+ self.assertIsNotNone(self.vcmts_pktgen.setup_helper)
+ self.assertIsNotNone(self.vcmts_pktgen.resource_helper)
+
+ def test_extract_pod_cfg(self):
+ pod_cfg = self.vcmts_pktgen.extract_pod_cfg(self.PKTGEN_POD_VALUES, "0")
+ self.assertIsNotNone(pod_cfg)
+ self.assertEqual(pod_cfg["pktgen_id"], "0")
+ pod_cfg = self.vcmts_pktgen.extract_pod_cfg(self.PKTGEN_POD_VALUES, "4")
+ self.assertIsNone(pod_cfg)
+
+ @mock.patch.object(ctx_base.Context, 'get_context_from_server',
+ return_value='fake_context')
+ def test_instantiate_missing_pktgen_values_key(self, *args):
+ err_scenario_cfg = copy.deepcopy(self.SCENARIO_CFG)
+ err_scenario_cfg['options'].pop('pktgen_values', None)
+ with self.assertRaises(KeyError):
+ self.vcmts_pktgen.instantiate(err_scenario_cfg, self.CONTEXT_CFG)
+
+ @mock.patch.object(ctx_base.Context, 'get_context_from_server',
+ return_value='fake_context')
+ def test_instantiate_missing_pktgen_values_file(self, *args):
+ if os.path.isfile(self.PKTGEN_VALUES_PATH):
+ os.remove(self.PKTGEN_VALUES_PATH)
+ err_scenario_cfg = copy.deepcopy(self.SCENARIO_CFG)
+ err_scenario_cfg['options']['pktgen_values'] = self.PKTGEN_VALUES_PATH
+ with self.assertRaises(RuntimeError):
+ self.vcmts_pktgen.instantiate(err_scenario_cfg, self.CONTEXT_CFG)
+
+ @mock.patch.object(ctx_base.Context, 'get_context_from_server',
+ return_value='fake_context')
+ def test_instantiate_empty_pktgen_values_file(self, *args):
+ yaml_sample = open(self.PKTGEN_VALUES_PATH, 'w')
+ yaml_sample.write("")
+ yaml_sample.close()
+
+ err_scenario_cfg = copy.deepcopy(self.SCENARIO_CFG)
+ err_scenario_cfg['options']['pktgen_values'] = self.PKTGEN_VALUES_PATH
+ with self.assertRaises(RuntimeError):
+ self.vcmts_pktgen.instantiate(err_scenario_cfg, self.CONTEXT_CFG)
+
+ if os.path.isfile(self.PKTGEN_VALUES_PATH):
+ os.remove(self.PKTGEN_VALUES_PATH)
+
+ @mock.patch.object(ctx_base.Context, 'get_context_from_server',
+ return_value='fake_context')
+ def test_instantiate_invalid_pktgen_id(self, *args):
+ yaml_sample = open(self.PKTGEN_VALUES_PATH, 'w')
+ yaml_sample.write(self.PKTGEN_VALUES)
+ yaml_sample.close()
+
+ err_scenario_cfg = copy.deepcopy(self.SCENARIO_CFG)
+ err_scenario_cfg['options'][NAME]['pktgen_id'] = 12
+ with self.assertRaises(KeyError):
+ self.vcmts_pktgen.instantiate(err_scenario_cfg, self.CONTEXT_CFG)
+
+ if os.path.isfile(self.PKTGEN_VALUES_PATH):
+ os.remove(self.PKTGEN_VALUES_PATH)
+
+ @mock.patch.object(ctx_base.Context, 'get_context_from_server',
+ return_value='fake_context')
+ def test_instantiate_all_valid(self, *args):
+ yaml_sample = open(self.PKTGEN_VALUES_PATH, 'w')
+ yaml_sample.write(self.PKTGEN_VALUES)
+ yaml_sample.close()
+
+ self.vcmts_pktgen.instantiate(self.SCENARIO_CFG, self.CONTEXT_CFG)
+ self.assertIsNotNone(self.vcmts_pktgen.pod_cfg)
+ self.assertEqual(self.vcmts_pktgen.pod_cfg["pktgen_id"], "0")
+
+ if os.path.isfile(self.PKTGEN_VALUES_PATH):
+ os.remove(self.PKTGEN_VALUES_PATH)
+
+ def test_run_traffic_failed_connect(self):
+ self.vcmts_pktgen.pktgen_helper = mock.MagicMock()
+ self.vcmts_pktgen.pktgen_helper.connect.return_value = False
+ with self.assertRaises(exceptions.PktgenActionError):
+ self.vcmts_pktgen.run_traffic({})
+
+ def test_run_traffic_successful_connect(self):
+ self.vcmts_pktgen.pktgen_helper = mock.MagicMock()
+ self.vcmts_pktgen.pktgen_helper.connect.return_value = True
+ self.vcmts_pktgen.pktgen_rate = 8.0
+ self.assertTrue(self.vcmts_pktgen.run_traffic({}))
+ self.vcmts_pktgen.pktgen_helper.connect.assert_called_once()
+ self.vcmts_pktgen.pktgen_helper.send_command.assert_called_with(
+ 'pktgen.start("all");')
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_udp_replay.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_udp_replay.py
index cbb4ee913..aabd402a6 100644
--- a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_udp_replay.py
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_udp_replay.py
@@ -329,9 +329,9 @@ class TestUdpReplayApproxVnf(unittest.TestCase):
vnfd = self.VNFD_0
get_stats_ret_val = \
"stats\r\r\n\r\nUDP_Replay stats:\r\n--------------\r\n" \
- "Port\t\tRx Packet\t\tTx Packet\t\tRx Pkt Drop\t\tTx Pkt Drop \r\n"\
- "0\t\t7374156\t\t7374136\t\t\t0\t\t\t0\r\n" \
- "1\t\t7374316\t\t7374315\t\t\t0\t\t\t0\r\n\r\nReplay>\r\r\nReplay>"
+ "Port\t\tRx Packet\t\tTx Packet\t\tRx Pkt Drop\t\tTx Pkt Drop\t\tarp_pkts \r\n"\
+ "0\t\t7374156\t\t7374136\t\t\t0\t\t\t0\t\t\t0\r\n" \
+ "1\t\t7374316\t\t7374315\t\t\t0\t\t\t0\t\t\t0\r\n\r\nReplay>\r\r\nReplay>"
udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, vnfd)
udp_replay_approx_vnf.scenario_helper.scenario_cfg = {
'nodes': {udp_replay_approx_vnf.name: "mock"}
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vcmts_vnf.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vcmts_vnf.py
new file mode 100755
index 000000000..11e3d6e17
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vcmts_vnf.py
@@ -0,0 +1,651 @@
+# Copyright (c) 2019 Viosoft 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.
+
+import unittest
+import mock
+import copy
+import os
+
+from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh
+from yardstick.network_services.vnf_generic.vnf.base import VnfdHelper
+from yardstick.network_services.vnf_generic.vnf import vcmts_vnf
+from yardstick.common import exceptions
+
+from influxdb.resultset import ResultSet
+
+NAME = "vnf__0"
+
+
+class TestInfluxDBHelper(unittest.TestCase):
+
+ def test___init__(self):
+ influxdb_helper = vcmts_vnf.InfluxDBHelper("localhost", 8086)
+ self.assertEqual(influxdb_helper._vcmts_influxdb_ip, "localhost")
+ self.assertEqual(influxdb_helper._vcmts_influxdb_port, 8086)
+ self.assertIsNotNone(influxdb_helper._last_upstream_rx)
+ self.assertIsNotNone(influxdb_helper._last_values_time)
+
+ def test_start(self):
+ influxdb_helper = vcmts_vnf.InfluxDBHelper("localhost", 8086)
+ influxdb_helper.start()
+ self.assertIsNotNone(influxdb_helper._read_client)
+ self.assertIsNotNone(influxdb_helper._write_client)
+
+ def test__get_last_value_time(self):
+ influxdb_helper = vcmts_vnf.InfluxDBHelper("localhost", 8086)
+ self.assertEqual(influxdb_helper._get_last_value_time('cpu_value'),
+ vcmts_vnf.InfluxDBHelper.INITIAL_VALUE)
+
+ influxdb_helper._last_values_time['cpu_value'] = "RANDOM"
+ self.assertEqual(influxdb_helper._get_last_value_time('cpu_value'),
+ "RANDOM")
+
+ def test__set_last_value_time(self):
+ influxdb_helper = vcmts_vnf.InfluxDBHelper("localhost", 8086)
+ influxdb_helper._set_last_value_time('cpu_value', '00:00')
+ self.assertEqual(influxdb_helper._last_values_time['cpu_value'],
+ "'00:00'")
+
+ def test__query_measurement(self):
+ influxdb_helper = vcmts_vnf.InfluxDBHelper("localhost", 8086)
+ influxdb_helper._read_client = mock.MagicMock()
+
+ resulted_generator = mock.MagicMock()
+ resulted_generator.keys.return_value = []
+ influxdb_helper._read_client.query.return_value = resulted_generator
+ query_result = influxdb_helper._query_measurement('cpu_value')
+ self.assertIsNone(query_result)
+
+ resulted_generator = mock.MagicMock()
+ resulted_generator.keys.return_value = ["", ""]
+ resulted_generator.get_points.return_value = ResultSet({"":""})
+ influxdb_helper._read_client.query.return_value = resulted_generator
+ query_result = influxdb_helper._query_measurement('cpu_value')
+ self.assertIsNotNone(query_result)
+
+ def test__rw_measurment(self):
+ influxdb_helper = vcmts_vnf.InfluxDBHelper("localhost", 8086)
+ influxdb_helper._query_measurement = mock.MagicMock()
+ influxdb_helper._query_measurement.return_value = None
+ influxdb_helper._rw_measurment('cpu_value', [])
+ self.assertEqual(len(influxdb_helper._last_values_time), 0)
+
+ entry = {
+ "type":"type",
+ "host":"host",
+ "time":"time",
+ "id": "1",
+ "value": "1.0"
+ }
+ influxdb_helper._query_measurement.return_value = [entry]
+ influxdb_helper._write_client = mock.MagicMock()
+ influxdb_helper._rw_measurment('cpu_value', ["id", "value"])
+ self.assertEqual(len(influxdb_helper._last_values_time), 1)
+ influxdb_helper._write_client.write_points.assert_called_once()
+
+ def test_copy_kpi(self):
+ influxdb_helper = vcmts_vnf.InfluxDBHelper("localhost", 8086)
+ influxdb_helper._rw_measurment = mock.MagicMock()
+ influxdb_helper.copy_kpi()
+ influxdb_helper._rw_measurment.assert_called()
+
+
+class TestVcmtsdSetupEnvHelper(unittest.TestCase):
+ POD_CFG = {
+ "cm_crypto": "aes",
+ "cpu_socket_id": "0",
+ "ds_core_pool_index": "2",
+ "ds_core_type": "exclusive",
+ "net_ds": "1a:02.1",
+ "net_us": "1a:02.0",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "power_mgmt": "pm_on",
+ "qat": "qat_off",
+ "service_group_config": "",
+ "sg_id": "0",
+ "vcmtsd_image": "vcmts-d:perf"
+ }
+
+ OPTIONS = {
+ "pktgen_values": "/tmp/pktgen_values.yaml",
+ "tg__0": {
+ "pktgen_id": 0
+ },
+ "vcmts_influxdb_ip": "10.80.5.150",
+ "vcmts_influxdb_port": 8086,
+ "vcmtsd_values": "/tmp/vcmtsd_values.yaml",
+ "vnf__0": {
+ "sg_id": 0,
+ "stream_dir": "us"
+ },
+ "vnf__1": {
+ "sg_id": 0,
+ "stream_dir": "ds"
+ }
+ }
+
+ def setUp(self):
+ vnfd_helper = VnfdHelper(
+ TestVcmtsVNF.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS
+
+ self.setup_helper = vcmts_vnf.VcmtsdSetupEnvHelper(
+ vnfd_helper, ssh_helper, scenario_helper)
+
+ def _build_us_parameters(self):
+ return vcmts_vnf.VcmtsdSetupEnvHelper.BASE_PARAMETERS + " " \
+ + " /opt/bin/cmk isolate --conf-dir=/etc/cmk" \
+ + " --socket-id=" + str(self.POD_CFG['cpu_socket_id']) \
+ + " --pool=shared" \
+ + " /vcmts-config/run_upstream.sh " + self.POD_CFG['sg_id'] \
+ + " " + self.POD_CFG['ds_core_type'] \
+ + " " + str(self.POD_CFG['num_ofdm']) + "ofdm" \
+ + " " + str(self.POD_CFG['num_subs']) + "cm" \
+ + " " + self.POD_CFG['cm_crypto'] \
+ + " " + self.POD_CFG['qat'] \
+ + " " + self.POD_CFG['net_us'] \
+ + " " + self.POD_CFG['power_mgmt']
+
+ def test_build_us_parameters(self):
+ constructed = self._build_us_parameters()
+ result = self.setup_helper.build_us_parameters(self.POD_CFG)
+ self.assertEqual(constructed, result)
+
+ def _build_ds_parameters(self):
+ return vcmts_vnf.VcmtsdSetupEnvHelper.BASE_PARAMETERS + " " \
+ + " /opt/bin/cmk isolate --conf-dir=/etc/cmk" \
+ + " --socket-id=" + str(self.POD_CFG['cpu_socket_id']) \
+ + " --pool=" + self.POD_CFG['ds_core_type'] \
+ + " /vcmts-config/run_downstream.sh " + self.POD_CFG['sg_id'] \
+ + " " + self.POD_CFG['ds_core_type'] \
+ + " " + str(self.POD_CFG['ds_core_pool_index']) \
+ + " " + str(self.POD_CFG['num_ofdm']) + "ofdm" \
+ + " " + str(self.POD_CFG['num_subs']) + "cm" \
+ + " " + self.POD_CFG['cm_crypto'] \
+ + " " + self.POD_CFG['qat'] \
+ + " " + self.POD_CFG['net_ds'] \
+ + " " + self.POD_CFG['power_mgmt']
+
+ def test_build_ds_parameters(self):
+ constructed = self._build_ds_parameters()
+ result = self.setup_helper.build_ds_parameters(self.POD_CFG)
+ self.assertEqual(constructed, result)
+
+ def test_build_cmd(self):
+ us_constructed = self._build_us_parameters()
+ us_result = self.setup_helper.build_cmd('us', self.POD_CFG)
+ self.assertEqual(us_constructed, us_result)
+ ds_constructed = self._build_ds_parameters()
+ ds_result = self.setup_helper.build_cmd('ds', self.POD_CFG)
+ self.assertEqual(ds_constructed, ds_result)
+
+ def test_run_vcmtsd(self):
+ us_constructed = self._build_us_parameters()
+
+ vnfd_helper = VnfdHelper(
+ TestVcmtsVNF.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.MagicMock()
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS
+
+ setup_helper = vcmts_vnf.VcmtsdSetupEnvHelper(
+ vnfd_helper, ssh_helper, scenario_helper)
+
+ setup_helper.run_vcmtsd('us', self.POD_CFG)
+ ssh_helper.send_command.assert_called_with(us_constructed)
+
+ def test_setup_vnf_environment(self):
+ self.assertIsNone(self.setup_helper.setup_vnf_environment())
+
+class TestVcmtsVNF(unittest.TestCase):
+
+ VNFD = {'vnfd:vnfd-catalog':
+ {'vnfd':
+ [{
+ "benchmark": {
+ "kpi": [
+ "upstream/bits_per_second"
+ ]
+ },
+ "connection-point": [
+ {
+ "name": "xe0",
+ "type": "VPORT"
+ },
+ {
+ "name": "xe1",
+ "type": "VPORT"
+ }
+ ],
+ "description": "vCMTS Upstream-Downstream Kubernetes",
+ "id": "VcmtsVNF",
+ "mgmt-interface": {
+ "ip": "192.168.100.35",
+ "key_filename": "/tmp/yardstick_key-81dcca91",
+ "user": "root",
+ "vdu-id": "vcmtsvnf-kubernetes"
+ },
+ "name": "vcmtsvnf",
+ "short-name": "vcmtsvnf",
+ "vdu": [
+ {
+ "description": "vCMTS Upstream-Downstream Kubernetes",
+ "external-interface": [],
+ "id": "vcmtsvnf-kubernetes",
+ "name": "vcmtsvnf-kubernetes"
+ }
+ ],
+ "vm-flavor": {
+ "memory-mb": "4096",
+ "vcpu-count": "4"
+ }
+ }]
+ }
+ }
+
+ POD_CFG = [
+ {
+ "cm_crypto": "aes",
+ "cpu_socket_id": "0",
+ "ds_core_pool_index": "2",
+ "ds_core_type": "exclusive",
+ "net_ds": "1a:02.1",
+ "net_us": "1a:02.0",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "power_mgmt": "pm_on",
+ "qat": "qat_off",
+ "service_group_config": "",
+ "sg_id": "0",
+ "vcmtsd_image": "vcmts-d:perf"
+ },
+ ]
+
+ SCENARIO_CFG = {
+ "nodes": {
+ "tg__0": "pktgen0-k8syardstick-afae18b2",
+ "vnf__0": "vnf0us-k8syardstick-afae18b2",
+ "vnf__1": "vnf0ds-k8syardstick-afae18b2"
+ },
+ "options": {
+ "pktgen_values": "/tmp/pktgen_values.yaml",
+ "tg__0": {
+ "pktgen_id": 0
+ },
+ "vcmts_influxdb_ip": "10.80.5.150",
+ "vcmts_influxdb_port": 8086,
+ "vcmtsd_values": "/tmp/vcmtsd_values.yaml",
+ "vnf__0": {
+ "sg_id": 0,
+ "stream_dir": "us"
+ },
+ "vnf__1": {
+ "sg_id": 0,
+ "stream_dir": "ds"
+ }
+ },
+ "task_id": "afae18b2-9902-477f-8128-49afde7c3040",
+ "task_path": "samples/vnf_samples/nsut/cmts",
+ "tc": "tc_vcmts_k8s_pktgen",
+ "topology": "k8s_vcmts_topology.yaml",
+ "traffic_profile": "../../traffic_profiles/fixed.yaml",
+ "type": "NSPerf"
+ }
+
+ CONTEXT_CFG = {
+ "networks": {
+ "flannel": {
+ "name": "flannel"
+ },
+ "xe0": {
+ "name": "xe0"
+ },
+ "xe1": {
+ "name": "xe1"
+ }
+ },
+ "nodes": {
+ "tg__0": {
+ "VNF model": "../../vnf_descriptors/tg_vcmts_tpl.yaml",
+ "interfaces": {
+ "flannel": {
+ "local_ip": "192.168.24.110",
+ "local_mac": None,
+ "network_name": "flannel"
+ },
+ "xe0": {
+ "local_ip": "192.168.24.110",
+ "local_mac": None,
+ "network_name": "xe0"
+ },
+ "xe1": {
+ "local_ip": "192.168.24.110",
+ "local_mac": None,
+ "network_name": "xe1"
+ }
+ },
+ "ip": "192.168.24.110",
+ "key_filename": "/tmp/yardstick_key-afae18b2",
+ "member-vnf-index": "1",
+ "name": "pktgen0-k8syardstick-afae18b2",
+ "private_ip": "192.168.24.110",
+ "service_ports": [
+ {
+ "name": "ssh",
+ "node_port": 17153,
+ "port": 22,
+ "protocol": "TCP",
+ "target_port": 22
+ },
+ {
+ "name": "lua",
+ "node_port": 51250,
+ "port": 22022,
+ "protocol": "TCP",
+ "target_port": 22022
+ }
+ ],
+ "ssh_port": 17153,
+ "user": "root",
+ "vnfd-id-ref": "tg__0"
+ },
+ "vnf__0": {
+ "VNF model": "../../vnf_descriptors/vnf_vcmts_tpl.yaml",
+ "interfaces": {
+ "flannel": {
+ "local_ip": "192.168.100.53",
+ "local_mac": None,
+ "network_name": "flannel"
+ },
+ "xe0": {
+ "local_ip": "192.168.100.53",
+ "local_mac": None,
+ "network_name": "xe0"
+ },
+ "xe1": {
+ "local_ip": "192.168.100.53",
+ "local_mac": None,
+ "network_name": "xe1"
+ }
+ },
+ "ip": "192.168.100.53",
+ "key_filename": "/tmp/yardstick_key-afae18b2",
+ "member-vnf-index": "3",
+ "name": "vnf0us-k8syardstick-afae18b2",
+ "private_ip": "192.168.100.53",
+ "service_ports": [
+ {
+ "name": "ssh",
+ "node_port": 34027,
+ "port": 22,
+ "protocol": "TCP",
+ "target_port": 22
+ },
+ {
+ "name": "lua",
+ "node_port": 32580,
+ "port": 22022,
+ "protocol": "TCP",
+ "target_port": 22022
+ }
+ ],
+ "ssh_port": 34027,
+ "user": "root",
+ "vnfd-id-ref": "vnf__0"
+ },
+ "vnf__1": {
+ "VNF model": "../../vnf_descriptors/vnf_vcmts_tpl.yaml",
+ "interfaces": {
+ "flannel": {
+ "local_ip": "192.168.100.52",
+ "local_mac": None,
+ "network_name": "flannel"
+ },
+ "xe0": {
+ "local_ip": "192.168.100.52",
+ "local_mac": None,
+ "network_name": "xe0"
+ },
+ "xe1": {
+ "local_ip": "192.168.100.52",
+ "local_mac": None,
+ "network_name": "xe1"
+ }
+ },
+ "ip": "192.168.100.52",
+ "key_filename": "/tmp/yardstick_key-afae18b2",
+ "member-vnf-index": "4",
+ "name": "vnf0ds-k8syardstick-afae18b2",
+ "private_ip": "192.168.100.52",
+ "service_ports": [
+ {
+ "name": "ssh",
+ "node_port": 58661,
+ "port": 22,
+ "protocol": "TCP",
+ "target_port": 22
+ },
+ {
+ "name": "lua",
+ "node_port": 58233,
+ "port": 22022,
+ "protocol": "TCP",
+ "target_port": 22022
+ }
+ ],
+ "ssh_port": 58661,
+ "user": "root",
+ "vnfd-id-ref": "vnf__1"
+ },
+ }
+ }
+
+ VCMTSD_VALUES_PATH = "/tmp/vcmtsd_values.yaml"
+
+ VCMTSD_VALUES = \
+ "serviceAccount: cmk-serviceaccount\n" \
+ "topology:\n" \
+ " vcmts_replicas: 16\n" \
+ " vcmts_pods:\n" \
+ " - service_group_config:\n" \
+ " sg_id: 0\n" \
+ " net_us: 18:02.0\n" \
+ " net_ds: 18:02.1\n" \
+ " num_ofdm: 4\n" \
+ " num_subs: 300\n" \
+ " cm_crypto: aes\n" \
+ " qat: qat_off\n" \
+ " power_mgmt: pm_on\n" \
+ " cpu_socket_id: 0\n" \
+ " ds_core_type: exclusive\n" \
+ " ds_core_pool_index: 0\n" \
+ " vcmtsd_image: vcmts-d:feat"
+
+ VCMTSD_VALUES_INCOMPLETE = \
+ "serviceAccount: cmk-serviceaccount\n" \
+ "topology:\n" \
+ " vcmts_replicas: 16"
+
+ def setUp(self):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ self.vnf = vcmts_vnf.VcmtsVNF(NAME, vnfd)
+
+ def test___init__(self, *args):
+ self.assertIsNotNone(self.vnf.setup_helper)
+
+ def test_extract_pod_cfg(self):
+ pod_cfg = self.vnf.extract_pod_cfg(self.POD_CFG, "0")
+ self.assertIsNotNone(pod_cfg)
+ self.assertEqual(pod_cfg['sg_id'], '0')
+ pod_cfg = self.vnf.extract_pod_cfg(self.POD_CFG, "1")
+ self.assertIsNone(pod_cfg)
+
+ def test_instantiate_missing_influxdb_info(self):
+ err_scenario_cfg = copy.deepcopy(self.SCENARIO_CFG)
+ err_scenario_cfg['options'].pop('vcmts_influxdb_ip', None)
+ with self.assertRaises(KeyError):
+ self.vnf.instantiate(err_scenario_cfg, self.CONTEXT_CFG)
+
+ def test_instantiate_missing_vcmtsd_values_file(self):
+ if os.path.isfile(self.VCMTSD_VALUES_PATH):
+ os.remove(self.VCMTSD_VALUES_PATH)
+ err_scenario_cfg = copy.deepcopy(self.SCENARIO_CFG)
+ err_scenario_cfg['options']['vcmtsd_values'] = self.VCMTSD_VALUES_PATH
+ with self.assertRaises(RuntimeError):
+ self.vnf.instantiate(err_scenario_cfg, self.CONTEXT_CFG)
+
+ def test_instantiate_empty_vcmtsd_values_file(self):
+ yaml_sample = open(self.VCMTSD_VALUES_PATH, 'w')
+ yaml_sample.write("")
+ yaml_sample.close()
+
+ err_scenario_cfg = copy.deepcopy(self.SCENARIO_CFG)
+ err_scenario_cfg['options']['vcmtsd_values'] = self.VCMTSD_VALUES_PATH
+ with self.assertRaises(RuntimeError):
+ self.vnf.instantiate(err_scenario_cfg, self.CONTEXT_CFG)
+
+ if os.path.isfile(self.VCMTSD_VALUES_PATH):
+ os.remove(self.VCMTSD_VALUES_PATH)
+
+ def test_instantiate_missing_vcmtsd_values_key(self):
+ err_scenario_cfg = copy.deepcopy(self.SCENARIO_CFG)
+ err_scenario_cfg['options'].pop('vcmtsd_values', None)
+ with self.assertRaises(KeyError):
+ self.vnf.instantiate(err_scenario_cfg, self.CONTEXT_CFG)
+
+ def test_instantiate_invalid_vcmtsd_values(self):
+ yaml_sample = open(self.VCMTSD_VALUES_PATH, 'w')
+ yaml_sample.write(self.VCMTSD_VALUES_INCOMPLETE)
+ yaml_sample.close()
+
+ err_scenario_cfg = copy.deepcopy(self.SCENARIO_CFG)
+ with self.assertRaises(KeyError):
+ self.vnf.instantiate(err_scenario_cfg, self.CONTEXT_CFG)
+
+ if os.path.isfile(self.VCMTSD_VALUES_PATH):
+ os.remove(self.VCMTSD_VALUES_PATH)
+
+ def test_instantiate_invalid_sg_id(self):
+ yaml_sample = open(self.VCMTSD_VALUES_PATH, 'w')
+ yaml_sample.write(self.VCMTSD_VALUES)
+ yaml_sample.close()
+
+ err_scenario_cfg = copy.deepcopy(self.SCENARIO_CFG)
+ err_scenario_cfg['options'][NAME]['sg_id'] = 8
+ with self.assertRaises(exceptions.IncorrectConfig):
+ self.vnf.instantiate(err_scenario_cfg, self.CONTEXT_CFG)
+
+ if os.path.isfile(self.VCMTSD_VALUES_PATH):
+ os.remove(self.VCMTSD_VALUES_PATH)
+
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.vcmts_vnf.VnfSshHelper')
+ def test_instantiate_all_valid(self, ssh, *args):
+ mock_ssh(ssh)
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ vnf = vcmts_vnf.VcmtsVNF(NAME, vnfd)
+
+ yaml_sample = open(self.VCMTSD_VALUES_PATH, 'w')
+ yaml_sample.write(self.VCMTSD_VALUES)
+ yaml_sample.close()
+
+ vnf.instantiate(self.SCENARIO_CFG, self.CONTEXT_CFG)
+ self.assertEqual(vnf.vcmts_influxdb_ip, "10.80.5.150")
+ self.assertEqual(vnf.vcmts_influxdb_port, 8086)
+
+ if os.path.isfile(self.VCMTSD_VALUES_PATH):
+ os.remove(self.VCMTSD_VALUES_PATH)
+
+ def test__update_collectd_options(self):
+ scenario_cfg = {'options':
+ {'collectd':
+ {'interval': 3,
+ 'plugins':
+ {'plugin3': {'param': 3}}},
+ 'vnf__0':
+ {'collectd':
+ {'interval': 2,
+ 'plugins':
+ {'plugin3': {'param': 2},
+ 'plugin2': {'param': 2}}}}}}
+ context_cfg = {'nodes':
+ {'vnf__0':
+ {'collectd':
+ {'interval': 1,
+ 'plugins':
+ {'plugin3': {'param': 1},
+ 'plugin2': {'param': 1},
+ 'plugin1': {'param': 1}}}}}}
+ expected = {'interval': 1,
+ 'plugins':
+ {'plugin3': {'param': 1},
+ 'plugin2': {'param': 1},
+ 'plugin1': {'param': 1}}}
+
+ self.vnf._update_collectd_options(scenario_cfg, context_cfg)
+ self.assertEqual(self.vnf.setup_helper.collectd_options, expected)
+
+ def test__update_options(self):
+ options1 = {'interval': 1,
+ 'param1': 'value1',
+ 'plugins':
+ {'plugin3': {'param': 3},
+ 'plugin2': {'param': 1},
+ 'plugin1': {'param': 1}}}
+ options2 = {'interval': 2,
+ 'param2': 'value2',
+ 'plugins':
+ {'plugin4': {'param': 4},
+ 'plugin2': {'param': 2},
+ 'plugin1': {'param': 2}}}
+ expected = {'interval': 1,
+ 'param1': 'value1',
+ 'param2': 'value2',
+ 'plugins':
+ {'plugin4': {'param': 4},
+ 'plugin3': {'param': 3},
+ 'plugin2': {'param': 1},
+ 'plugin1': {'param': 1}}}
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ vnf = vcmts_vnf.VcmtsVNF('vnf1', vnfd)
+ vnf._update_options(options2, options1)
+ self.assertEqual(options2, expected)
+
+ def test_wait_for_instantiate(self):
+ self.assertIsNone(self.vnf.wait_for_instantiate())
+
+ def test_terminate(self):
+ self.assertIsNone(self.vnf.terminate())
+
+ def test_scale(self):
+ self.assertIsNone(self.vnf.scale())
+
+ def test_collect_kpi(self):
+ self.vnf.influxdb_helper = mock.MagicMock()
+ self.vnf.collect_kpi()
+ self.vnf.influxdb_helper.copy_kpi.assert_called_once()
+
+ def test_start_collect(self):
+ self.vnf.vcmts_influxdb_ip = "localhost"
+ self.vnf.vcmts_influxdb_port = 8800
+
+ self.assertIsNone(self.vnf.start_collect())
+ self.assertIsNotNone(self.vnf.influxdb_helper)
+
+ def test_stop_collect(self):
+ self.assertIsNone(self.vnf.stop_collect())
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vims_vnf.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vims_vnf.py
new file mode 100644
index 000000000..d86dab8ad
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vims_vnf.py
@@ -0,0 +1,713 @@
+# Copyright (c) 2019 Viosoft 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.
+
+import unittest
+import mock
+
+from yardstick.network_services.vnf_generic.vnf import vims_vnf
+from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh
+
+
+class TestVimsPcscfVnf(unittest.TestCase):
+
+ VNFD_0 = {
+ "short-name": "SippVnf",
+ "vdu": [
+ {
+ "id": "sippvnf-baremetal",
+ "routing_table": "",
+ "external-interface": [
+ {
+ "virtual-interface": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "peer_intf": {
+ "vnf__0": {
+ "vld_id": "data_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "node_name": "vnf__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:a8"
+ },
+ "vnf__1": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "node_name": "vnf__1",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:e8"
+ }
+ },
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ },
+ "vnfd-connection-point-ref": "xe0",
+ "name": "xe0"
+ },
+ {
+ "virtual-interface": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "peer_intf": {
+ "vnf__0": {
+ "vld_id": "data_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "peer_intf": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ },
+ "node_name": "vnf__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:a8"
+ },
+ "vnf__1": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "peer_intf": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "peer_intf": {
+ "vld_id": "data_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "node_name": "vnf__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:a8"
+ },
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ },
+ "node_name": "vnf__1",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:e8"
+ }
+ },
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe1",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ },
+ "vnfd-connection-point-ref": "xe1",
+ "name": "xe1"
+ }
+ ],
+ "name": "sippvnf-baremetal",
+ "description": "Sipp"
+ }
+ ],
+ "description": "ImsbenchSipp",
+ "mgmt-interface": {
+ "vdu-id": "sipp-baremetal",
+ "password": "r00t",
+ "user": "root",
+ "ip": "10.80.3.11"
+ },
+ "benchmark": {
+ "kpi": [
+ "packets_in",
+ "packets_fwd",
+ "packets_dropped"
+ ]
+ },
+ "id": "SippVnf",
+ "name": "SippVnf"
+ }
+
+ def setUp(self):
+ self.pcscf_vnf = vims_vnf.VimsPcscfVnf('vnf__0', self.VNFD_0)
+
+ def test___init__(self):
+ self.assertEqual(self.pcscf_vnf.name, 'vnf__0')
+ self.assertIsInstance(self.pcscf_vnf.resource_helper,
+ vims_vnf.VimsResourceHelper)
+ self.assertIsNone(self.pcscf_vnf._vnf_process)
+
+ def test_wait_for_instantiate(self):
+ self.assertIsNone(self.pcscf_vnf.wait_for_instantiate())
+
+ def test__run(self):
+ self.assertIsNone(self.pcscf_vnf._run())
+
+ def test_start_collect(self):
+ self.assertIsNone(self.pcscf_vnf.start_collect())
+
+ def test_collect_kpi(self):
+ self.assertIsNone(self.pcscf_vnf.collect_kpi())
+
+
+class TestVimsHssVnf(unittest.TestCase):
+
+ VNFD_1 = {
+ "short-name": "SippVnf",
+ "vdu": [
+ {
+ "id": "sippvnf-baremetal",
+ "routing_table": "",
+ "external-interface": [
+ {
+ "virtual-interface": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "peer_intf": {
+ "vnf__0": {
+ "vld_id": "data_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "node_name": "vnf__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:a8"
+ },
+ "vnf__1": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "node_name": "vnf__1",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:e8"
+ }
+ },
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ },
+ "vnfd-connection-point-ref": "xe0",
+ "name": "xe0"
+ },
+ {
+ "virtual-interface": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "peer_intf": {
+ "vnf__0": {
+ "vld_id": "data_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "peer_intf": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ },
+ "node_name": "vnf__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:a8"
+ },
+ "vnf__1": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "peer_intf": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "peer_intf": {
+ "vld_id": "data_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "node_name": "vnf__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:a8"
+ },
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ },
+ "node_name": "vnf__1",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:e8"
+ }
+ },
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe1",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ },
+ "vnfd-connection-point-ref": "xe1",
+ "name": "xe1"
+ }
+ ],
+ "name": "sippvnf-baremetal",
+ "description": "Sipp"
+ }
+ ],
+ "description": "ImsbenchSipp",
+ "mgmt-interface": {
+ "vdu-id": "sipp-baremetal",
+ "password": "r00t",
+ "user": "root",
+ "ip": "10.80.3.11"
+ },
+ "benchmark": {
+ "kpi": [
+ "packets_in",
+ "packets_fwd",
+ "packets_dropped"
+ ]
+ },
+ "id": "SippVnf",
+ "name": "SippVnf"
+ }
+
+ SCENARIO_CFG = {
+ "task_id": "86414e11-5ef5-4426-b175-71baaa00fbd7",
+ "tc": "tc_vims_baremetal_sipp",
+ "runner": {
+ "interval": 1,
+ "output_config": {
+ "DEFAULT": {
+ "debug": "False",
+ "dispatcher": [
+ "influxdb"
+ ]
+ },
+ "nsb": {
+ "debug": "False",
+ "trex_client_lib": "/opt/nsb_bin/trex_client/stl",
+ "bin_path": "/opt/nsb_bin",
+ "trex_path": "/opt/nsb_bin/trex/scripts",
+ "dispatcher": "influxdb"
+ },
+ "dispatcher_influxdb": {
+ "username": "root",
+ "target": "http://10.80.3.11:8086",
+ "db_name": "yardstick",
+ "timeout": "5",
+ "debug": "False",
+ "password": "root",
+ "dispatcher": "influxdb"
+ },
+ "dispatcher_http": {
+ "debug": "False",
+ "dispatcher": "influxdb",
+ "timeout": "5",
+ "target": "http://127.0.0.1:8000/results"
+ },
+ "dispatcher_file": {
+ "debug": "False",
+ "backup_count": "0",
+ "max_bytes": "0",
+ "dispatcher": "influxdb",
+ "file_path": "/tmp/yardstick.out"
+ }
+ },
+ "runner_id": 22610,
+ "duration": 60,
+ "type": "Vims"
+ },
+ "nodes": {
+ "vnf__0": "pcscf.yardstick-86414e11",
+ "vnf__1": "hss.yardstick-86414e11",
+ "tg__0": "sipp.yardstick-86414e11"
+ },
+ "topology": "vims-topology.yaml",
+ "type": "NSPerf",
+ "traffic_profile": "../../traffic_profiles/ipv4_throughput.yaml",
+ "task_path": "samples/vnf_samples/nsut/vims",
+ "options": {
+ "init_reg_max": 5000,
+ "end_user": 10000,
+ "reg_cps": 20,
+ "rereg_cps": 20,
+ "rereg_step": 10,
+ "wait_time": 5,
+ "start_user": 1,
+ "msgc_cps": 10,
+ "dereg_step": 10,
+ "call_cps": 10,
+ "reg_step": 10,
+ "init_reg_cps": 50,
+ "dereg_cps": 20,
+ "msgc_step": 5,
+ "call_step": 5,
+ "hold_time": 15,
+ "port": 5060,
+ "run_mode": "nortp"
+ }
+ }
+
+ CONTEXT_CFG = {
+ "nodes": {
+ "tg__0": {
+ "ip": "10.80.3.11",
+ "interfaces": {
+ "xe0": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "peer_intf": {
+ "vnf__0": {
+ "vld_id": "data_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "node_name": "vnf__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:a8"
+ },
+ "vnf__1": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "node_name": "vnf__1",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:e8"
+ }
+ },
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ },
+ "xe1": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "peer_intf": {
+ "vnf__0": {
+ "vld_id": "data_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "peer_intf": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ },
+ "node_name": "vnf__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:a8"
+ },
+ "vnf__1": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "peer_intf": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "peer_intf": {
+ "vld_id": "data_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "node_name": "vnf__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:a8"
+ },
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ },
+ "node_name": "vnf__1",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:e8"
+ }
+ },
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe1",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ }
+ },
+ "user": "root",
+ "password": "r00t",
+ "VNF model": "../../vnf_descriptors/tg_sipp_vnfd.yaml",
+ "name": "sipp.yardstick-86414e11",
+ "vnfd-id-ref": "tg__0",
+ "member-vnf-index": "1",
+ "role": "TrafficGen",
+ "ctx_type": "Node"
+ },
+ "vnf__0": {
+ "ip": "10.80.3.7",
+ "interfaces": {
+ "xe0": {
+ "vld_id": "data_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "peer_intf": {
+ "tg__0": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe1",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ }
+ },
+ "node_name": "vnf__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:a8"
+ }
+ },
+ "user": "root",
+ "password": "r00t",
+ "VNF model": "../../vnf_descriptors/vims_pcscf_vnfd.yaml",
+ "name": "pcscf.yardstick-86414e11",
+ "vnfd-id-ref": "vnf__0",
+ "member-vnf-index": "2",
+ "role": "VirtualNetworkFunction",
+ "ctx_type": "Node"
+ },
+ "vnf__1": {
+ "ip": "10.80.3.7",
+ "interfaces": {
+ "xe0": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "peer_intf": {
+ "tg__0": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "peer_intf": {
+ "vld_id": "data_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "peer_intf": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ },
+ "node_name": "vnf__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:a8"
+ },
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe1",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ }
+ },
+ "node_name": "vnf__1",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:e8"
+ }
+ },
+ "user": "root",
+ "password": "r00t",
+ "VNF model": "../../vnf_descriptors/vims_hss_vnfd.yaml",
+ "name": "hss.yardstick-86414e11",
+ "vnfd-id-ref": "vnf__1",
+ "member-vnf-index": "3",
+ "role": "VirtualNetworkFunction",
+ "ctx_type": "Node"
+ }
+ },
+ "networks": {}
+ }
+
+ def setUp(self):
+ self.hss_vnf = vims_vnf.VimsHssVnf('vnf__1', self.VNFD_1)
+
+ def test___init__(self):
+ self.assertIsInstance(self.hss_vnf.resource_helper,
+ vims_vnf.VimsResourceHelper)
+ self.assertIsNone(self.hss_vnf._vnf_process)
+
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper")
+ def test_instantiate(self, ssh):
+ mock_ssh(ssh)
+ hss_vnf = vims_vnf.VimsHssVnf('vnf__1', self.VNFD_1)
+ self.assertIsNone(hss_vnf.instantiate(self.SCENARIO_CFG,
+ self.CONTEXT_CFG))
+
+ def test_wait_for_instantiate(self):
+ self.assertIsNone(self.hss_vnf.wait_for_instantiate())
+
+ def test_start_collect(self):
+ self.assertIsNone(self.hss_vnf.start_collect())
+
+ def test_collect_kpi(self):
+ self.assertIsNone(self.hss_vnf.collect_kpi())
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vpp_helpers.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vpp_helpers.py
new file mode 100644
index 000000000..cca604f43
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vpp_helpers.py
@@ -0,0 +1,1723 @@
+# Copyright (c) 2019 Viosoft 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.
+import ipaddress
+import unittest
+
+import mock
+
+from yardstick.common import exceptions
+from yardstick.network_services.helpers import cpu
+from yardstick.network_services.vnf_generic.vnf import vpp_helpers
+from yardstick.network_services.vnf_generic.vnf.base import VnfdHelper
+from yardstick.network_services.vnf_generic.vnf.vpp_helpers import \
+ VppSetupEnvHelper, VppConfigGenerator, VatTerminal
+
+
+class TestVppConfigGenerator(unittest.TestCase):
+
+ def test_add_config_item(self):
+ test_item = {}
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_config_item(test_item, '/tmp/vpe.log',
+ ['unix', 'log'])
+ self.assertEqual({'unix': {'log': '/tmp/vpe.log'}}, test_item)
+
+ def test_add_config_item_str(self):
+ test_item = {'unix': ''}
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_config_item(test_item, '/tmp/vpe.log',
+ ['unix', 'log'])
+ self.assertEqual({'unix': {'log': '/tmp/vpe.log'}}, test_item)
+
+ def test_add_unix_log(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_unix_log()
+ self.assertEqual('unix\n{\n log /tmp/vpe.log\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_unix_cli_listen(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_unix_cli_listen()
+ self.assertEqual('unix\n{\n cli-listen /run/vpp/cli.sock\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_unix_nodaemon(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_unix_nodaemon()
+ self.assertEqual('unix\n{\n nodaemon \n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_unix_coredump(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_unix_coredump()
+ self.assertEqual('unix\n{\n full-coredump \n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_dpdk_dev(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_dpdk_dev('0000:00:00.0')
+ self.assertEqual('dpdk\n{\n dev 0000:00:00.0 \n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_dpdk_cryptodev(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_dpdk_cryptodev(2, '0000:00:00.0')
+ self.assertEqual(
+ 'dpdk\n{\n dev 0000:00:01.0 \n dev 0000:00:01.1 \n uio-driver igb_uio\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_dpdk_sw_cryptodev(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_dpdk_sw_cryptodev('aesni_gcm', 0, 2)
+ self.assertEqual(
+ 'dpdk\n{\n vdev cryptodev_aesni_gcm_pmd,socket_id=0 \n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_dpdk_dev_default_rxq(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_dpdk_dev_default_rxq(1)
+ self.assertEqual(
+ 'dpdk\n{\n dev default\n {\n num-rx-queues 1\n }\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_dpdk_dev_default_rxd(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_dpdk_dev_default_rxd(2048)
+ self.assertEqual(
+ 'dpdk\n{\n dev default\n {\n num-rx-desc 2048\n }\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_dpdk_dev_default_txd(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_dpdk_dev_default_txd(2048)
+ self.assertEqual(
+ 'dpdk\n{\n dev default\n {\n num-tx-desc 2048\n }\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_dpdk_log_level(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_dpdk_log_level('debug')
+ self.assertEqual('dpdk\n{\n log-level debug\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_dpdk_socketmem(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_dpdk_socketmem('1024,1024')
+ self.assertEqual('dpdk\n{\n socket-mem 1024,1024\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_dpdk_num_mbufs(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_dpdk_num_mbufs(32768)
+ self.assertEqual('dpdk\n{\n num-mbufs 32768\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_dpdk_uio_driver(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_dpdk_uio_driver('igb_uio')
+ self.assertEqual('dpdk\n{\n uio-driver igb_uio\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_cpu_main_core(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_cpu_main_core('1,2')
+ self.assertEqual('cpu\n{\n main-core 1,2\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_cpu_corelist_workers(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_cpu_corelist_workers('1,2')
+ self.assertEqual('cpu\n{\n corelist-workers 1,2\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_heapsize(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_heapsize('4G')
+ self.assertEqual('heapsize 4G\n', vpp_config_generator.dump_config())
+
+ def test_add_ip6_hash_buckets(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_ip6_hash_buckets(2000000)
+ self.assertEqual('ip6\n{\n hash-buckets 2000000\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_ip6_heap_size(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_ip6_heap_size('4G')
+ self.assertEqual('ip6\n{\n heap-size 4G\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_ip_heap_size(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_ip_heap_size('4G')
+ self.assertEqual('ip\n{\n heap-size 4G\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_statseg_size(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_statseg_size('4G')
+ self.assertEqual('statseg\n{\n size 4G\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_plugin(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_plugin('enable', ['dpdk_plugin.so'])
+ self.assertEqual(
+ 'plugins\n{\n plugin [\'dpdk_plugin.so\']\n {\n enable \n }\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_dpdk_no_multi_seg(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_dpdk_no_multi_seg()
+ self.assertEqual('dpdk\n{\n no-multi-seg \n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_dpdk_no_tx_checksum_offload(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_dpdk_no_tx_checksum_offload()
+ self.assertEqual('dpdk\n{\n no-tx-checksum-offload \n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_dump_config(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_unix_log()
+ self.assertEqual('unix\n{\n log /tmp/vpe.log\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_pci_dev_check(self):
+ self.assertTrue(VppConfigGenerator.pci_dev_check('0000:00:00.0'))
+
+ def test_pci_dev_check_error(self):
+ with self.assertRaises(ValueError) as raised:
+ VppConfigGenerator.pci_dev_check('0000:00:0.0')
+ self.assertIn(
+ 'PCI address 0000:00:0.0 is not in valid format xxxx:xx:xx.x',
+ str(raised.exception))
+
+
+class TestVppSetupEnvHelper(unittest.TestCase):
+ VNFD_0 = {
+ "benchmark": {
+ "kpi": [
+ "packets_in",
+ "packets_fwd",
+ "packets_dropped"
+ ]
+ },
+ "connection-point": [
+ {
+ "name": "xe0",
+ "type": "VPORT"
+ },
+ {
+ "name": "xe1",
+ "type": "VPORT"
+ }
+ ],
+ "description": "VPP IPsec",
+ "id": "VipsecApproxVnf",
+ "mgmt-interface": {
+ "ip": "10.10.10.101",
+ "password": "r00t",
+ "user": "root",
+ "vdu-id": "ipsecvnf-baremetal"
+ },
+ "name": "IpsecVnf",
+ "short-name": "IpsecVnf",
+ "vdu": [
+ {
+ "description": "VPP Ipsec",
+ "external-interface": [
+ {
+ "name": "xe0",
+ "virtual-interface": {
+ "driver": "igb_uio",
+ "dst_ip": "192.168.100.1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "ifname": "xe0",
+ "local_ip": "192.168.100.2",
+ "local_mac": "90:e2:ba:7c:41:a8",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "vnf__0",
+ "peer_ifname": "xe0",
+ "peer_intf": {
+ "dpdk_port_num": 0,
+ "driver": "igb_uio",
+ "dst_ip": "192.168.100.2",
+ "dst_mac": "90:e2:ba:7c:41:a8",
+ "ifname": "xe0",
+ "local_ip": "192.168.100.1",
+ "local_mac": "90:e2:ba:7c:30:e8",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "tg__0",
+ "peer_ifname": "xe0",
+ "peer_name": "vnf__0",
+ "vld_id": "uplink_0",
+ "vpci": "0000:81:00.0"
+ },
+ "peer_name": "tg__0",
+ "vld_id": "uplink_0",
+ "vpci": "0000:ff:06.0"
+ },
+ "vnfd-connection-point-ref": "xe0"
+ },
+ {
+ "name": "xe1",
+ "virtual-interface": {
+ "driver": "igb_uio",
+ "dst_ip": "1.1.1.2",
+ "dst_mac": "0a:b1:ec:fd:a2:66",
+ "ifname": "xe1",
+ "local_ip": "1.1.1.1",
+ "local_mac": "4e:90:85:d3:c5:13",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "vnf__0",
+ "peer_ifname": "xe1",
+ "peer_intf": {
+ "driver": "igb_uio",
+ "dst_ip": "1.1.1.1",
+ "dst_mac": "4e:90:85:d3:c5:13",
+ "ifname": "xe1",
+ "local_ip": "1.1.1.2",
+ "local_mac": "0a:b1:ec:fd:a2:66",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "vnf__1",
+ "peer_ifname": "xe1",
+ "peer_name": "vnf__0",
+ "vld_id": "ciphertext",
+ "vpci": "0000:00:07.0"
+ },
+ "peer_name": "vnf__1",
+ "vld_id": "ciphertext",
+ "vpci": "0000:ff:07.0"
+ },
+ "vnfd-connection-point-ref": "xe1"
+ }
+ ],
+ "id": "ipsecvnf-baremetal",
+ "name": "ipsecvnf-baremetal",
+ "routing_table": []
+ }
+ ]
+ }
+
+ VNFD_1 = {
+ "benchmark": {
+ "kpi": [
+ "packets_in",
+ "packets_fwd",
+ "packets_dropped"
+ ]
+ },
+ "connection-point": [
+ {
+ "name": "xe0",
+ "type": "VPORT"
+ },
+ {
+ "name": "xe1",
+ "type": "VPORT"
+ }
+ ],
+ "description": "VPP IPsec",
+ "id": "VipsecApproxVnf",
+ "mgmt-interface": {
+ "ip": "10.10.10.101",
+ "password": "r00t",
+ "user": "root",
+ "vdu-id": "ipsecvnf-baremetal"
+ },
+ "name": "IpsecVnf",
+ "short-name": "IpsecVnf",
+ "vdu": [
+ {
+ "description": "VPP Ipsec",
+ "external-interface": [
+ {
+ "name": "xe0",
+ "virtual-interface": {
+ "driver": "igb_uio",
+ "dst_ip": "192.168.100.1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "ifname": "xe0",
+ "local_ip": "192.168.100.2",
+ "local_mac": "90:e2:ba:7c:41:a8",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "vnf__0",
+ "peer_ifname": "xe0",
+ "peer_intf": {
+ "dpdk_port_num": 0,
+ "driver": "igb_uio",
+ "dst_ip": "192.168.100.2",
+ "dst_mac": "90:e2:ba:7c:41:a8",
+ "ifname": "xe0",
+ "local_ip": "192.168.100.1",
+ "local_mac": "90:e2:ba:7c:30:e8",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "tg__0",
+ "peer_ifname": "xe0",
+ "peer_name": "vnf__0",
+ "vld_id": "uplink_0",
+ "vpci": "0000:81:00.0"
+ },
+ "peer_name": "tg__0",
+ "vld_id": "uplink_0",
+ "vpci": "0000:ff:06.0"
+ },
+ "vnfd-connection-point-ref": "xe0"
+ },
+ {
+ "name": "xe1",
+ "virtual-interface": {
+ "driver": "igb_uio",
+ "dst_ip": "1.1.1.2",
+ "dst_mac": "0a:b1:ec:fd:a2:66",
+ "ifname": "xe1",
+ "local_ip": "1.1.1.1",
+ "local_mac": "4e:90:85:d3:c5:13",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "vnf__0",
+ "peer_ifname": "xe1",
+ "peer_intf": {
+ "driver": "igb_uio",
+ "dst_ip": "1.1.1.1",
+ "dst_mac": "4e:90:85:d3:c5:13",
+ "ifname": "xe1",
+ "local_ip": "1.1.1.2",
+ "local_mac": "0a:b1:ec:fd:a2:66",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "vnf__1",
+ "peer_ifname": "xe1",
+ "peer_name": "vnf__0",
+ "vld_id": "ciphertext",
+ "vpci": "0000:00:07.0"
+ },
+ "peer_name": "vnf__1",
+ "vld_id": "ciphertext",
+ "vpci": "0000:ff:07.0"
+ },
+ "vnfd-connection-point-ref": "xe1"
+ }
+ ],
+ "id": "ipsecvnf-baremetal",
+ "name": "ipsecvnf-baremetal",
+ "routing_table": []
+ }
+ ]
+ }
+
+ VNFD_2 = {
+ "benchmark": {
+ "kpi": [
+ "packets_in",
+ "packets_fwd",
+ "packets_dropped"
+ ]
+ },
+ "connection-point": [
+ {
+ "name": "xe0",
+ "type": "VPORT"
+ },
+ {
+ "name": "xe1",
+ "type": "VPORT"
+ }
+ ],
+ "description": "VPP IPsec",
+ "id": "VipsecApproxVnf",
+ "mgmt-interface": {
+ "ip": "10.10.10.101",
+ "password": "r00t",
+ "user": "root",
+ "vdu-id": "ipsecvnf-baremetal"
+ },
+ "name": "IpsecVnf",
+ "short-name": "IpsecVnf",
+ "vdu": [
+ {
+ "description": "VPP Ipsec",
+ "external-interface": [
+ {
+ "name": "xe0",
+ "virtual-interface": {
+ "driver": "igb_uio",
+ "dst_ip": "192.168.100.1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "ifname": "xe0",
+ "local_ip": "192.168.100.2",
+ "local_mac": "90:e2:ba:7c:41:a8",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "vnf__0",
+ "peer_ifname": "xe0",
+ "peer_intf": {
+ "dpdk_port_num": 0,
+ "driver": "igb_uio",
+ "dst_ip": "192.168.100.2",
+ "dst_mac": "90:e2:ba:7c:41:a8",
+ "ifname": "xe0",
+ "local_ip": "192.168.100.1",
+ "local_mac": "90:e2:ba:7c:30:e8",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "tg__0",
+ "peer_ifname": "xe0",
+ "peer_name": "vnf__0",
+ "vld_id": "uplink_0",
+ "vpci": "0000:81:00.0"
+ },
+ "peer_name": "tg__0",
+ "vld_id": "uplink_0",
+ "vpci": "0000:ff:06.0"
+ },
+ "vnfd-connection-point-ref": "xe0"
+ },
+ {
+ "name": "xe1",
+ "virtual-interface": {
+ "driver": "igb_uio",
+ "dst_ip": "1.1.1.2",
+ "dst_mac": "0a:b1:ec:fd:a2:66",
+ "ifname": "xe1",
+ "local_ip": "1.1.1.1",
+ "local_mac": "4e:90:85:d3:c5:13",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "vnf__0",
+ "peer_ifname": "xe1",
+ "peer_intf": {
+ "driver": "igb_uio",
+ "dst_ip": "1.1.1.1",
+ "dst_mac": "4e:90:85:d3:c5:13",
+ "ifname": "xe1",
+ "local_ip": "1.1.1.2",
+ "local_mac": "0a:b1:ec:fd:a2:66",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "vnf__1",
+ "peer_ifname": "xe1",
+ "peer_name": "vnf__0",
+ "vld_id": "ciphertext",
+ "vpci": "0000:00:07.0"
+ },
+ "peer_name": "vnf__1",
+ "vld_id": "ciphertext",
+ "vpci": "0000:ff:07.0"
+ },
+ "vnfd-connection-point-ref": "xe1"
+ }
+ ],
+ "id": "ipsecvnf-baremetal",
+ "name": "ipsecvnf-baremetal",
+ "routing_table": []
+ }
+ ]
+ }
+
+ VNFD = {
+ 'vnfd:vnfd-catalog': {
+ 'vnfd': [
+ VNFD_0,
+ ],
+ },
+ }
+
+ VPP_INTERFACES_DUMP = [
+ {
+ "sw_if_index": 0,
+ "sup_sw_if_index": 0,
+ "l2_address_length": 0,
+ "l2_address": [0, 0, 0, 0, 0, 0, 0, 0],
+ "interface_name": "local0",
+ "admin_up_down": 0,
+ "link_up_down": 0,
+ "link_duplex": 0,
+ "link_speed": 0,
+ "mtu": 0,
+ "sub_id": 0,
+ "sub_dot1ad": 0,
+ "sub_number_of_tags": 0,
+ "sub_outer_vlan_id": 0,
+ "sub_inner_vlan_id": 0,
+ "sub_exact_match": 0,
+ "sub_default": 0,
+ "sub_outer_vlan_id_any": 0,
+ "sub_inner_vlan_id_any": 0,
+ "vtr_op": 0,
+ "vtr_push_dot1q": 0,
+ "vtr_tag1": 0,
+ "vtr_tag2": 0
+ },
+ {
+ "sw_if_index": 1,
+ "sup_sw_if_index": 1,
+ "l2_address_length": 6,
+ "l2_address": [144, 226, 186, 124, 65, 168, 0, 0],
+ "interface_name": "TenGigabitEthernetff/6/0",
+ "admin_up_down": 0,
+ "link_up_down": 0,
+ "link_duplex": 2,
+ "link_speed": 32,
+ "mtu": 9202,
+ "sub_id": 0,
+ "sub_dot1ad": 0,
+ "sub_number_of_tags": 0,
+ "sub_outer_vlan_id": 0,
+ "sub_inner_vlan_id": 0,
+ "sub_exact_match": 0,
+ "sub_default": 0,
+ "sub_outer_vlan_id_any": 0,
+ "sub_inner_vlan_id_any": 0,
+ "vtr_op": 0,
+ "vtr_push_dot1q": 0,
+ "vtr_tag1": 0,
+ "vtr_tag2": 0
+ },
+ {
+ "sw_if_index": 2,
+ "sup_sw_if_index": 2,
+ "l2_address_length": 6,
+ "l2_address": [78, 144, 133, 211, 197, 19, 0, 0],
+ "interface_name": "VirtualFunctionEthernetff/7/0",
+ "admin_up_down": 0,
+ "link_up_down": 0,
+ "link_duplex": 2,
+ "link_speed": 32,
+ "mtu": 9206,
+ "sub_id": 0,
+ "sub_dot1ad": 0,
+ "sub_number_of_tags": 0,
+ "sub_outer_vlan_id": 0,
+ "sub_inner_vlan_id": 0,
+ "sub_exact_match": 0,
+ "sub_default": 0,
+ "sub_outer_vlan_id_any": 0,
+ "sub_inner_vlan_id_any": 0,
+ "vtr_op": 0,
+ "vtr_push_dot1q": 0,
+ "vtr_tag1": 0,
+ "vtr_tag2": 0
+ }
+ ]
+
+ VPP_INTERFACES_DUMP_MAC_ERR = [
+ {
+ "sw_if_index": 0,
+ "sup_sw_if_index": 0,
+ "l2_address_length": 0,
+ "l2_address": [0, 0, 0, 0, 0, 0, 0, 0],
+ "interface_name": "local0",
+ "admin_up_down": 0,
+ "link_up_down": 0,
+ "link_duplex": 0,
+ "link_speed": 0,
+ "mtu": 0,
+ "sub_id": 0,
+ "sub_dot1ad": 0,
+ "sub_number_of_tags": 0,
+ "sub_outer_vlan_id": 0,
+ "sub_inner_vlan_id": 0,
+ "sub_exact_match": 0,
+ "sub_default": 0,
+ "sub_outer_vlan_id_any": 0,
+ "sub_inner_vlan_id_any": 0,
+ "vtr_op": 0,
+ "vtr_push_dot1q": 0,
+ "vtr_tag1": 0,
+ "vtr_tag2": 0
+ },
+ {
+ "sw_if_index": 1,
+ "sup_sw_if_index": 1,
+ "l2_address_length": 6,
+ "l2_address": [144, 226, 186, 124, 65, 169, 0, 0],
+ "interface_name": "TenGigabitEthernetff/6/0",
+ "admin_up_down": 0,
+ "link_up_down": 0,
+ "link_duplex": 2,
+ "link_speed": 32,
+ "mtu": 9202,
+ "sub_id": 0,
+ "sub_dot1ad": 0,
+ "sub_number_of_tags": 0,
+ "sub_outer_vlan_id": 0,
+ "sub_inner_vlan_id": 0,
+ "sub_exact_match": 0,
+ "sub_default": 0,
+ "sub_outer_vlan_id_any": 0,
+ "sub_inner_vlan_id_any": 0,
+ "vtr_op": 0,
+ "vtr_push_dot1q": 0,
+ "vtr_tag1": 0,
+ "vtr_tag2": 0
+ },
+ {
+ "sw_if_index": 2,
+ "sup_sw_if_index": 2,
+ "l2_address_length": 6,
+ "l2_address": [78, 144, 133, 211, 197, 20, 0, 0],
+ "interface_name": "VirtualFunctionEthernetff/7/0",
+ "admin_up_down": 0,
+ "link_up_down": 0,
+ "link_duplex": 2,
+ "link_speed": 32,
+ "mtu": 9206,
+ "sub_id": 0,
+ "sub_dot1ad": 0,
+ "sub_number_of_tags": 0,
+ "sub_outer_vlan_id": 0,
+ "sub_inner_vlan_id": 0,
+ "sub_exact_match": 0,
+ "sub_default": 0,
+ "sub_outer_vlan_id_any": 0,
+ "sub_inner_vlan_id_any": 0,
+ "vtr_op": 0,
+ "vtr_push_dot1q": 0,
+ "vtr_tag1": 0,
+ "vtr_tag2": 0
+ }
+ ]
+
+ CPU_LAYOUT = {'cpuinfo': [[0, 0, 0, 0, 0, 0, 0, 0],
+ [1, 0, 0, 0, 0, 1, 1, 0]]}
+ CPU_SMT = {'cpuinfo': [[0, 0, 0, 0, 0, 0, 0, 0],
+ [1, 0, 0, 0, 0, 1, 1, 0],
+ [2, 1, 0, 0, 0, 2, 2, 1],
+ [3, 1, 0, 0, 0, 3, 3, 1],
+ [4, 2, 0, 0, 0, 4, 4, 2],
+ [5, 2, 0, 0, 0, 5, 5, 2],
+ [6, 3, 0, 0, 0, 6, 6, 3],
+ [7, 3, 0, 0, 0, 7, 7, 3],
+ [8, 4, 0, 0, 0, 8, 8, 4],
+ [9, 5, 0, 1, 0, 0, 0, 0],
+ [10, 6, 0, 1, 0, 1, 1, 0],
+ [11, 6, 0, 1, 0, 2, 2, 1],
+ [12, 7, 0, 1, 0, 3, 3, 1],
+ [13, 7, 0, 1, 0, 4, 4, 2],
+ [14, 8, 0, 1, 0, 5, 5, 2],
+ [15, 8, 0, 1, 0, 6, 6, 3],
+ [16, 9, 0, 1, 0, 7, 7, 3],
+ [17, 9, 0, 1, 0, 8, 8, 4]]}
+
+ def test_kill_vnf(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, 0, 0
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ vpp_setup_env_helper.kill_vnf()
+
+ def test_kill_vnf_error(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 1, 0, 0
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ with self.assertRaises(RuntimeError) as raised:
+ vpp_setup_env_helper.kill_vnf()
+
+ self.assertIn('Failed to stop service vpp', str(raised.exception))
+
+ def test_tear_down(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ vpp_setup_env_helper.tear_down()
+
+ def test_start_vpp_service(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, 0, 0
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ vpp_setup_env_helper.start_vpp_service()
+
+ def test_start_vpp_service_error(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 1, 0, 0
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ with self.assertRaises(RuntimeError) as raised:
+ vpp_setup_env_helper.start_vpp_service()
+
+ self.assertIn('Failed to start service vpp', str(raised.exception))
+
+ def test__update_vnfd_helper(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ vpp_setup_env_helper._update_vnfd_helper(
+ {'vpp-data': {'vpp-key': 'vpp-value'}})
+
+ self.assertEqual({'vpp-key': 'vpp-value'},
+ vpp_setup_env_helper.vnfd_helper.get('vpp-data', {}))
+
+ def test__update_vnfd_helper_with_key(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ vpp_setup_env_helper._update_vnfd_helper({'driver': 'qat'}, 'xe0')
+
+ self.assertEqual('qat',
+ vpp_setup_env_helper.get_value_by_interface_key(
+ 'xe0', 'driver'))
+
+ def test__update_vnfd_helper_dict_without_key(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ vpp_setup_env_helper._update_vnfd_helper(
+ {'mgmt-interface': {'name': 'net'}})
+
+ self.assertEqual({'ip': '10.10.10.101',
+ 'name': 'net',
+ 'password': 'r00t',
+ 'user': 'root',
+ 'vdu-id': 'ipsecvnf-baremetal'},
+ vpp_setup_env_helper.vnfd_helper.get('mgmt-interface',
+ {}))
+
+ def test_get_value_by_interface_key(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ vpp_setup_env_helper._update_vnfd_helper(
+ {'vpp-data': {'vpp-key': 'vpp-value'}}, 'xe0')
+
+ self.assertEqual({'vpp-key': 'vpp-value'},
+ vpp_setup_env_helper.get_value_by_interface_key(
+ 'xe0', 'vpp-data'))
+
+ def test_get_value_by_interface_key_error(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ vpp_setup_env_helper._update_vnfd_helper(
+ {'vpp-data': {'vpp-key': 'vpp-value'}}, 'xe0')
+
+ self.assertIsNone(vpp_setup_env_helper.get_value_by_interface_key(
+ 'xe2', 'vpp-err'))
+
+ def test_crypto_device_init(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ vpp_setup_env_helper.dpdk_bind_helper.load_dpdk_driver = mock.Mock()
+ vpp_setup_env_helper.dpdk_bind_helper.bind = mock.Mock()
+
+ vpp_setup_env_helper.kill_vnf = mock.Mock()
+ vpp_setup_env_helper.pci_driver_unbind = mock.Mock()
+
+ with mock.patch.object(vpp_setup_env_helper, 'get_pci_dev_driver') as \
+ mock_get_pci_dev_driver, \
+ mock.patch.object(vpp_setup_env_helper, 'set_sriov_numvfs') as \
+ mock_set_sriov_numvfs:
+ mock_get_pci_dev_driver.return_value = 'igb_uio'
+ self.assertIsNone(
+ vpp_setup_env_helper.crypto_device_init('0000:ff:06.0', 32))
+ mock_set_sriov_numvfs.assert_called()
+
+ def test_get_sriov_numvfs(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '32', ''
+
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ self.assertEqual(32,
+ vpp_setup_env_helper.get_sriov_numvfs('0000:ff:06.0'))
+
+ def test_get_sriov_numvfs_error(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, 'err', ''
+
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ self.assertEqual(0,
+ vpp_setup_env_helper.get_sriov_numvfs('0000:ff:06.0'))
+
+ def test_set_sriov_numvfs(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ vpp_setup_env_helper.set_sriov_numvfs('0000:ff:06.0')
+ self.assertEqual(ssh_helper.execute.call_count, 1)
+
+ def test_pci_driver_unbind(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ vpp_setup_env_helper.pci_driver_unbind('0000:ff:06.0')
+ self.assertEqual(ssh_helper.execute.call_count, 1)
+
+ def test_get_pci_dev_driver(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = \
+ 0, 'Slot: ff:07.0\n' \
+ 'Class: Ethernet controller\n' \
+ 'Vendor: Intel Corporation\n' \
+ 'Device: 82599 Ethernet Controller Virtual Function\n' \
+ 'SVendor: Intel Corporation\n' \
+ 'SDevice: 82599 Ethernet Controller Virtual Function\n' \
+ 'Rev: 01\n' \
+ 'Driver: igb_uio\n' \
+ 'Module: ixgbevf', ''
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ self.assertEqual('igb_uio', vpp_setup_env_helper.get_pci_dev_driver(
+ '0000:ff:06.0'))
+
+ def test_get_pci_dev_driver_error(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 1, 'err', ''
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ with self.assertRaises(RuntimeError) as raised:
+ vpp_setup_env_helper.get_pci_dev_driver(
+ '0000:ff:06.0')
+
+ self.assertIn("'lspci -vmmks 0000:ff:06.0' failed",
+ str(raised.exception))
+
+ def test_get_pci_dev_driver_output_error(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = \
+ 0, 'Slot: ff:07.0\n' \
+ '\n\t' \
+ 'Vendor: Intel Corporation\n' \
+ 'Device: 82599 Ethernet Controller Virtual Function\n' \
+ 'SVendor: Intel Corporation\n' \
+ 'SDevice: 82599 Ethernet Controller Virtual Function\n' \
+ 'Rev: 01\n' \
+ 'Driver_err: igb_uio\n' \
+ 'Module: ixgbevf', ''
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ self.assertIsNone(
+ vpp_setup_env_helper.get_pci_dev_driver('0000:ff:06.0'))
+
+ def test_vpp_create_ipsec_tunnels(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '', ''
+
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ self.assertIsNone(
+ vpp_setup_env_helper.vpp_create_ipsec_tunnels('10.10.10.2',
+ '10.10.10.1', 'xe0',
+ 1, 1, mock.Mock(),
+ 'crypto_key',
+ mock.Mock(),
+ 'integ_key',
+ '20.20.20.0'))
+ self.assertGreaterEqual(ssh_helper.execute.call_count, 2)
+
+ def test_vpp_create_ipsec_1000_tunnels(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '', ''
+
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ self.assertIsNone(
+ vpp_setup_env_helper.vpp_create_ipsec_tunnels('10.10.10.2',
+ '10.10.10.1', 'xe0',
+ 1000, 128000,
+ mock.Mock(),
+ 'crypto_key',
+ mock.Mock(),
+ 'integ_key',
+ '20.20.20.0'))
+ self.assertGreaterEqual(ssh_helper.execute.call_count, 2)
+
+ def test_apply_config(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '', ''
+
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ self.assertIsNone(vpp_setup_env_helper.apply_config(mock.Mock()))
+ self.assertGreaterEqual(ssh_helper.execute.call_count, 2)
+
+ def test_apply_config_error(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 1, '', ''
+
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ with self.assertRaises(RuntimeError) as raised:
+ vpp_setup_env_helper.apply_config(mock.Mock())
+
+ self.assertIn('Writing config file failed', str(raised.exception))
+
+ def test_vpp_route_add(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template:
+ mock_vat_terminal_exec_cmd_from_template.return_value = ''
+ self.assertIsNone(
+ vpp_setup_env_helper.vpp_route_add('xe0', '10.10.10.1', 24))
+
+ def test_vpp_route_add_without_index(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template:
+ mock_vat_terminal_exec_cmd_from_template.return_value = ''
+ self.assertIsNone(
+ vpp_setup_env_helper.vpp_route_add('xe0', '10.10.10.1', 24,
+ interface='xe0',
+ use_sw_index=False))
+
+ def test_add_arp_on_dut(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template:
+ mock_vat_terminal_exec_cmd_from_template.return_value = ''
+ self.assertEqual('', vpp_setup_env_helper.add_arp_on_dut('xe0',
+ '10.10.10.1',
+ '00:00:00:00:00:00'))
+
+ def test_set_ip(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template:
+ mock_vat_terminal_exec_cmd_from_template.return_value = ''
+ self.assertEqual('',
+ vpp_setup_env_helper.set_ip('xe0', '10.10.10.1',
+ 24))
+
+ def test_set_interface_state(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template:
+ mock_vat_terminal_exec_cmd_from_template.return_value = ''
+ self.assertEqual('',
+ vpp_setup_env_helper.set_interface_state('xe0',
+ 'up'))
+
+ def test_set_interface_state_error(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template:
+ mock_vat_terminal_exec_cmd_from_template.return_value = ''
+ with self.assertRaises(ValueError) as raised:
+ vpp_setup_env_helper.set_interface_state('xe0', 'error')
+ self.assertIn('Unexpected interface state: error',
+ str(raised.exception))
+
+ def test_set_interface_down_state(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template:
+ mock_vat_terminal_exec_cmd_from_template.return_value = ''
+ self.assertEqual('',
+ vpp_setup_env_helper.set_interface_state('xe0',
+ 'down'))
+
+ def test_vpp_set_interface_mtu(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template:
+ mock_vat_terminal_exec_cmd_from_template.return_value = ''
+ self.assertIsNone(
+ vpp_setup_env_helper.vpp_set_interface_mtu('xe0', 9200))
+
+ def test_vpp_interfaces_ready_wait(self):
+ json_output = [self.VPP_INTERFACES_DUMP]
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template:
+ mock_vat_terminal_exec_cmd_from_template.return_value = json_output
+ self.assertIsNone(vpp_setup_env_helper.vpp_interfaces_ready_wait())
+
+ def test_vpp_interfaces_ready_wait_timeout(self):
+ json_output = [[
+ {
+ "sw_if_index": 0,
+ "sup_sw_if_index": 0,
+ "l2_address_length": 0,
+ "l2_address": [0, 0, 0, 0, 0, 0, 0, 0],
+ "interface_name": "xe0",
+ "admin_up_down": 1,
+ "link_up_down": 0,
+ "link_duplex": 0,
+ "link_speed": 0,
+ "mtu": 0,
+ "sub_id": 0,
+ "sub_dot1ad": 0,
+ "sub_number_of_tags": 0,
+ "sub_outer_vlan_id": 0,
+ "sub_inner_vlan_id": 0,
+ "sub_exact_match": 0,
+ "sub_default": 0,
+ "sub_outer_vlan_id_any": 0,
+ "sub_inner_vlan_id_any": 0,
+ "vtr_op": 0,
+ "vtr_push_dot1q": 0,
+ "vtr_tag1": 0,
+ "vtr_tag2": 0
+ }]]
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template:
+ mock_vat_terminal_exec_cmd_from_template.return_value = json_output
+ with self.assertRaises(RuntimeError) as raised:
+ vpp_setup_env_helper.vpp_interfaces_ready_wait(5)
+ self.assertIn('timeout, not up [\'xe0\']', str(raised.exception))
+
+ def test_vpp_get_interface_data(self):
+ json_output = [self.VPP_INTERFACES_DUMP]
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template:
+ mock_vat_terminal_exec_cmd_from_template.return_value = json_output
+ self.assertEqual(json_output[0],
+ vpp_setup_env_helper.vpp_get_interface_data())
+
+ def test_vpp_get_interface_data_ifname(self):
+ json_output = [self.VPP_INTERFACES_DUMP]
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template:
+ mock_vat_terminal_exec_cmd_from_template.return_value = json_output
+ self.assertEqual(json_output[0][2],
+ vpp_setup_env_helper.vpp_get_interface_data(
+ 'VirtualFunctionEthernetff/7/0'))
+
+ def test_vpp_get_interface_data_ifname_error(self):
+ json_output = [self.VPP_INTERFACES_DUMP]
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template:
+ mock_vat_terminal_exec_cmd_from_template.return_value = json_output
+ self.assertEqual({}, vpp_setup_env_helper.vpp_get_interface_data(
+ 'error'))
+
+ def test_vpp_get_interface_data_ifindex(self):
+ json_output = [self.VPP_INTERFACES_DUMP]
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template:
+ mock_vat_terminal_exec_cmd_from_template.return_value = json_output
+ self.assertEqual(json_output[0][1],
+ vpp_setup_env_helper.vpp_get_interface_data(1))
+
+ def test_vpp_get_interface_data_error(self):
+ json_output = [self.VPP_INTERFACES_DUMP]
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template:
+ mock_vat_terminal_exec_cmd_from_template.return_value = json_output
+ with self.assertRaises(TypeError) as raised:
+ vpp_setup_env_helper.vpp_get_interface_data(1.0)
+ self.assertEqual('', str(raised.exception))
+
+ def test_update_vpp_interface_data(self):
+ output = '{}\n{}'.format(self.VPP_INTERFACES_DUMP,
+ 'dump_interface_table:6019: JSON output ' \
+ 'supported only for VPE API calls and dump_stats_table\n' \
+ '/opt/nsb_bin/vpp/templates/dump_interfaces.vat(2): \n' \
+ 'dump_interface_table error: Misc')
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, output.replace("\'", "\""), ''
+ ssh_helper.join_bin_path.return_value = '/opt/nsb_bin/vpp/templates'
+
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ self.assertIsNone(vpp_setup_env_helper.update_vpp_interface_data())
+ self.assertGreaterEqual(ssh_helper.execute.call_count, 1)
+ self.assertEqual('TenGigabitEthernetff/6/0',
+ vpp_setup_env_helper.get_value_by_interface_key(
+ 'xe0', 'vpp_name'))
+ self.assertEqual(1, vpp_setup_env_helper.get_value_by_interface_key(
+ 'xe0', 'vpp_sw_index'))
+ self.assertEqual('VirtualFunctionEthernetff/7/0',
+ vpp_setup_env_helper.get_value_by_interface_key(
+ 'xe1', 'vpp_name'))
+ self.assertEqual(2, vpp_setup_env_helper.get_value_by_interface_key(
+ 'xe1', 'vpp_sw_index'))
+
+ def test_update_vpp_interface_data_error(self):
+ output = '{}\n{}'.format(self.VPP_INTERFACES_DUMP_MAC_ERR,
+ 'dump_interface_table:6019: JSON output ' \
+ 'supported only for VPE API calls and dump_stats_table\n' \
+ '/opt/nsb_bin/vpp/templates/dump_interfaces.vat(2): \n' \
+ 'dump_interface_table error: Misc')
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, output.replace("\'", "\""), ''
+ ssh_helper.join_bin_path.return_value = '/opt/nsb_bin/vpp/templates'
+
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ self.assertIsNone(vpp_setup_env_helper.update_vpp_interface_data())
+ self.assertGreaterEqual(ssh_helper.execute.call_count, 1)
+
+ def test_iface_update_numa(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '0', ''
+
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ self.assertIsNone(vpp_setup_env_helper.iface_update_numa())
+ self.assertGreaterEqual(ssh_helper.execute.call_count, 2)
+ self.assertEqual(0, vpp_setup_env_helper.get_value_by_interface_key(
+ 'xe0', 'numa_node'))
+ self.assertEqual(0, vpp_setup_env_helper.get_value_by_interface_key(
+ 'xe1', 'numa_node'))
+
+ def test_iface_update_numa_error(self):
+ vnfd_helper = VnfdHelper(self.VNFD_1)
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '-1', ''
+
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout:
+ mock_get_cpu_layout.return_value = self.CPU_LAYOUT
+ sys_cores = cpu.CpuSysCores(ssh_helper)
+ vpp_setup_env_helper._update_vnfd_helper(
+ sys_cores.get_cpu_layout())
+ self.assertIsNone(vpp_setup_env_helper.iface_update_numa())
+ self.assertGreaterEqual(ssh_helper.execute.call_count, 2)
+ self.assertEqual(0, vpp_setup_env_helper.get_value_by_interface_key(
+ 'xe0', 'numa_node'))
+ self.assertEqual(0, vpp_setup_env_helper.get_value_by_interface_key(
+ 'xe1', 'numa_node'))
+
+ def test_iface_update_without_numa(self):
+ vnfd_helper = VnfdHelper(self.VNFD_2)
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '-1', ''
+
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout:
+ mock_get_cpu_layout.return_value = self.CPU_SMT
+ sys_cores = cpu.CpuSysCores(ssh_helper)
+ vpp_setup_env_helper._update_vnfd_helper(
+ sys_cores.get_cpu_layout())
+ self.assertIsNone(vpp_setup_env_helper.iface_update_numa())
+ self.assertGreaterEqual(ssh_helper.execute.call_count, 2)
+ self.assertIsNone(vpp_setup_env_helper.get_value_by_interface_key(
+ 'xe0', 'numa_node'))
+ self.assertIsNone(vpp_setup_env_helper.get_value_by_interface_key(
+ 'xe1', 'numa_node'))
+
+ def test_execute_script(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ vpp_setup_env_helper.execute_script('dump_interfaces.vat', True, True)
+ self.assertGreaterEqual(ssh_helper.put_file.call_count, 1)
+ self.assertGreaterEqual(ssh_helper.execute.call_count, 1)
+
+ def test_execute_script_error(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.side_effect = Exception
+
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ with self.assertRaises(Exception) as raised:
+ vpp_setup_env_helper.execute_script('dump_interfaces.vat', True,
+ True)
+ self.assertIn(
+ 'VAT script execution failed: vpp_api_test json in dump_interfaces.vat script',
+ str(raised.exception))
+ self.assertGreaterEqual(ssh_helper.put_file.call_count, 1)
+
+ def test_execute_script_json_out(self):
+ json_output = [
+ {
+ "sw_if_index": 0,
+ "sup_sw_if_index": 0
+ },
+ {
+ "l2_address_length": 6,
+ "l2_address": [144, 226, 186, 124, 65, 168, 0, 0]
+ },
+ {
+ "interface_name": "VirtualFunctionEthernetff/7/0",
+ "admin_up_down": 0
+ }
+ ]
+ output = '{}\n{}'.format(json_output,
+ 'dump_interface_table:6019: JSON output ' \
+ 'supported only for VPE API calls and dump_stats_table\n' \
+ '/opt/nsb_bin/vpp/templates/dump_interfaces.vat(2): \n' \
+ 'dump_interface_table error: Misc')
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, output, ''
+ ssh_helper.join_bin_path.return_value = '/opt/nsb_bin/vpp/templates'
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ self.assertEqual(str(json_output),
+ vpp_setup_env_helper.execute_script_json_out(
+ 'dump_interfaces.vat'))
+
+ def test_self_cleanup_vat_json_output(self):
+ json_output = [
+ {
+ "sw_if_index": 0,
+ "sup_sw_if_index": 0
+ },
+ {
+ "l2_address_length": 6,
+ "l2_address": [144, 226, 186, 124, 65, 168, 0, 0]
+ },
+ {
+ "interface_name": "VirtualFunctionEthernetff/7/0",
+ "admin_up_down": 0
+ }
+ ]
+
+ output = '{}\n{}'.format(json_output,
+ 'dump_interface_table:6019: JSON output ' \
+ 'supported only for VPE API calls and dump_stats_table\n' \
+ '/opt/nsb_bin/vpp/templates/dump_interfaces.vat(2): \n' \
+ 'dump_interface_table error: Misc')
+ self.assertEqual(str(json_output),
+ VppSetupEnvHelper.cleanup_vat_json_output(output,
+ '/opt/nsb_bin/vpp/templates/dump_interfaces.vat'))
+
+ def test__convert_mac_to_number_list(self):
+ self.assertEqual([144, 226, 186, 124, 65, 168],
+ VppSetupEnvHelper._convert_mac_to_number_list(
+ '90:e2:ba:7c:41:a8'))
+
+ def test_get_vpp_interface_by_mac(self):
+ mac_address = '90:e2:ba:7c:41:a8'
+ self.assertEqual({'admin_up_down': 0,
+ 'interface_name': 'TenGigabitEthernetff/6/0',
+ 'l2_address': [144, 226, 186, 124, 65, 168, 0, 0],
+ 'l2_address_length': 6,
+ 'link_duplex': 2,
+ 'link_speed': 32,
+ 'link_up_down': 0,
+ 'mtu': 9202,
+ 'sub_default': 0,
+ 'sub_dot1ad': 0,
+ 'sub_exact_match': 0,
+ 'sub_id': 0,
+ 'sub_inner_vlan_id': 0,
+ 'sub_inner_vlan_id_any': 0,
+ 'sub_number_of_tags': 0,
+ 'sub_outer_vlan_id': 0,
+ 'sub_outer_vlan_id_any': 0,
+ 'sup_sw_if_index': 1,
+ 'sw_if_index': 1,
+ 'vtr_op': 0,
+ 'vtr_push_dot1q': 0,
+ 'vtr_tag1': 0,
+ 'vtr_tag2': 0},
+ VppSetupEnvHelper.get_vpp_interface_by_mac(
+ self.VPP_INTERFACES_DUMP, mac_address))
+
+ def test_get_vpp_interface_by_mac_error(self):
+ mac_address = '90:e2:ba:7c:41:a9'
+ with self.assertRaises(ValueError) as raised:
+ VppSetupEnvHelper.get_vpp_interface_by_mac(
+ [{
+ "sw_if_index": 1,
+ "sup_sw_if_index": 1,
+ "l2_address_length": 7,
+ "l2_address": [144, 226, 186, 124, 65, 169, 0, 0],
+ "interface_name": "TenGigabitEthernetff/6/0",
+ "admin_up_down": 0,
+ "link_up_down": 0,
+ "link_duplex": 2,
+ "link_speed": 32,
+ "mtu": 9202,
+ "sub_id": 0,
+ "sub_dot1ad": 0,
+ "sub_number_of_tags": 0,
+ "sub_outer_vlan_id": 0,
+ "sub_inner_vlan_id": 0,
+ "sub_exact_match": 0,
+ "sub_default": 0,
+ "sub_outer_vlan_id_any": 0,
+ "sub_inner_vlan_id_any": 0,
+ "vtr_op": 0,
+ "vtr_push_dot1q": 0,
+ "vtr_tag1": 0,
+ "vtr_tag2": 0
+ }], mac_address)
+
+ self.assertIn('l2_address_length value is not 6.',
+ str(raised.exception))
+
+ def test_get_vpp_interface_by_mac_l2_error(self):
+ mac_address = '90:e2:ba:7c:41:a7'
+ with self.assertRaises(KeyError) as raised:
+ VppSetupEnvHelper.get_vpp_interface_by_mac(
+ [{
+ "sw_if_index": 1,
+ "sup_sw_if_index": 1,
+ "l2_address_length": 6,
+ "l2_address_err": [144, 226, 186, 124, 65, 167, 0, 0],
+ "interface_name": "TenGigabitEthernetff/6/0",
+ "admin_up_down": 0,
+ "link_up_down": 0,
+ "link_duplex": 2,
+ "link_speed": 32,
+ "mtu": 9202,
+ "sub_id": 0,
+ "sub_dot1ad": 0,
+ "sub_number_of_tags": 0,
+ "sub_outer_vlan_id": 0,
+ "sub_inner_vlan_id": 0,
+ "sub_exact_match": 0,
+ "sub_default": 0,
+ "sub_outer_vlan_id_any": 0,
+ "sub_inner_vlan_id_any": 0,
+ "vtr_op": 0,
+ "vtr_push_dot1q": 0,
+ "vtr_tag1": 0,
+ "vtr_tag2": 0
+ }], mac_address)
+
+ self.assertIn(
+ 'key l2_address not found in interface dict.Probably input list ' \
+ 'is not parsed from correct VAT json output.',
+ str(raised.exception))
+
+ def test_get_vpp_interface_by_mac_l2_length_error(self):
+ mac_address = '90:e2:ba:7c:41:a6'
+ with self.assertRaises(KeyError) as raised:
+ VppSetupEnvHelper.get_vpp_interface_by_mac(
+ [{
+ "sw_if_index": 1,
+ "sup_sw_if_index": 1,
+ "l2_address_length_err": 6,
+ "l2_address": [144, 226, 186, 124, 65, 166, 0, 0],
+ "interface_name": "TenGigabitEthernetff/6/0",
+ "admin_up_down": 0,
+ "link_up_down": 0,
+ "link_duplex": 2,
+ "link_speed": 32,
+ "mtu": 9202,
+ "sub_id": 0,
+ "sub_dot1ad": 0,
+ "sub_number_of_tags": 0,
+ "sub_outer_vlan_id": 0,
+ "sub_inner_vlan_id": 0,
+ "sub_exact_match": 0,
+ "sub_default": 0,
+ "sub_outer_vlan_id_any": 0,
+ "sub_inner_vlan_id_any": 0,
+ "vtr_op": 0,
+ "vtr_push_dot1q": 0,
+ "vtr_tag1": 0,
+ "vtr_tag2": 0
+ }], mac_address)
+
+ self.assertIn(
+ 'key l2_address_length not found in interface dict. Probably ' \
+ 'input list is not parsed from correct VAT json output.',
+ str(raised.exception))
+
+ def test_get_prefix_length(self):
+ start_ip = '10.10.10.0'
+ end_ip = '10.10.10.127'
+ ips = [ipaddress.ip_address(ip) for ip in
+ [str(ipaddress.ip_address(start_ip)), str(end_ip)]]
+ lowest_ip, highest_ip = min(ips), max(ips)
+
+ self.assertEqual(25,
+ VppSetupEnvHelper.get_prefix_length(int(lowest_ip),
+ int(highest_ip),
+ lowest_ip.max_prefixlen))
+
+ def test_get_prefix_length_zero_prefix(self):
+ start_ip = '10.0.0.0'
+ end_ip = '10.0.0.0'
+ ips = [ipaddress.ip_address(ip) for ip in
+ [str(ipaddress.ip_address(start_ip)), str(end_ip)]]
+ lowest_ip, highest_ip = min(ips), max(ips)
+
+ self.assertEqual(0,
+ VppSetupEnvHelper.get_prefix_length(int(lowest_ip),
+ int(highest_ip),
+ 0))
+
+
+class TestVatTerminal(unittest.TestCase):
+
+ def test___init___error(self):
+ ssh_helper = mock.Mock()
+ ssh_helper.interactive_terminal_open.side_effect = exceptions.SSHTimeout
+
+ with self.assertRaises(RuntimeError) as raised:
+ VatTerminal(ssh_helper, json_param=True)
+ self.assertIn('Cannot open interactive terminal',
+ str(raised.exception))
+
+ def test___init___exec_error(self):
+ ssh_helper = mock.Mock()
+ ssh_helper.interactive_terminal_exec_command.side_effect = exceptions.SSHTimeout
+ VatTerminal(ssh_helper, json_param=True)
+
+ def test_vat_terminal_exec_cmd(self):
+ ssh_helper = mock.Mock()
+ ssh_helper.interactive_terminal_exec_command.return_value = str(
+ {'empty': 'value'}).replace("\'", "\"")
+ vat_terminal = VatTerminal(ssh_helper, json_param=True)
+
+ self.assertEqual({'empty': 'value'},
+ vat_terminal.vat_terminal_exec_cmd(
+ "hw_interface_set_mtu sw_if_index 1 mtu 9200"))
+
+ def test_vat_terminal_exec_cmd_array(self):
+ ssh_helper = mock.Mock()
+ ssh_helper.interactive_terminal_exec_command.return_value = str(
+ [{'empty': 'value'}]).replace("\'", "\"")
+ vat_terminal = VatTerminal(ssh_helper, json_param=True)
+
+ self.assertEqual([{'empty': 'value'}],
+ vat_terminal.vat_terminal_exec_cmd(
+ "hw_interface_set_mtu sw_if_index 1 mtu 9200"))
+
+ def test_vat_terminal_exec_cmd_without_output(self):
+ ssh_helper = mock.Mock()
+ ssh_helper.interactive_terminal_exec_command.return_value = str(
+ {'empty': 'value'}).replace("\'", "\"")
+ vat_terminal = VatTerminal(ssh_helper, json_param=False)
+
+ self.assertIsNone(vat_terminal.vat_terminal_exec_cmd(
+ "hw_interface_set_mtu sw_if_index 1 mtu 9200"))
+
+ def test_vat_terminal_exec_cmd_error(self):
+ ssh_helper = mock.Mock()
+ ssh_helper.interactive_terminal_exec_command.return_value = str(
+ {'empty': 'value'}).replace("\'", "\"")
+ ssh_helper.interactive_terminal_exec_command.side_effect = exceptions.SSHTimeout
+
+ vat_terminal = VatTerminal(ssh_helper, json_param=True)
+
+ with self.assertRaises(RuntimeError) as raised:
+ vat_terminal.vat_terminal_exec_cmd(
+ "hw_interface_set_mtu sw_if_index 1 mtu 9200")
+ self.assertIn(
+ 'VPP is not running on node. VAT command hw_interface_set_mtu ' \
+ 'sw_if_index 1 mtu 9200 execution failed',
+ str(raised.exception))
+
+ def test_vat_terminal_exec_cmd_output_error(self):
+ ssh_helper = mock.Mock()
+ ssh_helper.interactive_terminal_exec_command.return_value = str(
+ 'empty: value').replace("\'", "\"")
+
+ vat_terminal = VatTerminal(ssh_helper, json_param=True)
+
+ with self.assertRaises(RuntimeError) as raised:
+ vat_terminal.vat_terminal_exec_cmd(
+ "hw_interface_set_mtu sw_if_index 1 mtu 9200")
+ self.assertIn(
+ 'VAT command hw_interface_set_mtu sw_if_index 1 mtu 9200: no JSON data.',
+ str(raised.exception))
+
+ def test_vat_terminal_close(self):
+ ssh_helper = mock.Mock()
+ vat_terminal = VatTerminal(ssh_helper, json_param=False)
+ self.assertIsNone(vat_terminal.vat_terminal_close())
+
+ def test_vat_terminal_close_error(self):
+ ssh_helper = mock.Mock()
+ ssh_helper.interactive_terminal_exec_command.side_effect = exceptions.SSHTimeout
+ vat_terminal = VatTerminal(ssh_helper, json_param=False)
+ with self.assertRaises(RuntimeError) as raised:
+ vat_terminal.vat_terminal_close()
+ self.assertIn('Failed to close VAT console', str(raised.exception))
+
+ def test_vat_terminal_close_vat_error(self):
+ ssh_helper = mock.Mock()
+ ssh_helper.interactive_terminal_close.side_effect = exceptions.SSHTimeout
+ vat_terminal = VatTerminal(ssh_helper, json_param=False)
+ with self.assertRaises(RuntimeError) as raised:
+ vat_terminal.vat_terminal_close()
+ self.assertIn('Cannot close interactive terminal',
+ str(raised.exception))
+
+ def test_vat_terminal_exec_cmd_from_template(self):
+ ssh_helper = mock.Mock()
+ vat_terminal = VatTerminal(ssh_helper, json_param=False)
+
+ with mock.patch.object(vat_terminal, 'vat_terminal_exec_cmd') as \
+ mock_vat_terminal_exec_cmd:
+ mock_vat_terminal_exec_cmd.return_value = 'empty'
+ self.assertEqual(['empty'],
+ vat_terminal.vat_terminal_exec_cmd_from_template(
+ "hw_interface_set_mtu.vat", sw_if_index=1,
+ mtu=9200))