aboutsummaryrefslogtreecommitdiffstats
path: root/yardstick
diff options
context:
space:
mode:
authorDeepak S <deepak.s@linux.intel.com>2017-06-20 14:18:57 -0700
committerRoss Brattain <ross.b.brattain@intel.com>2017-08-08 12:57:42 -0700
commit4545b967760ca795a3c67f043eaca60798a90570 (patch)
tree5ced218450c7fb96e1b6230080fc5cfc901b50fa /yardstick
parent5ce3b6f8c8b3217091e51a6041455738603d90b8 (diff)
IXIA traffic generator
Change-Id: I09bcb3f2c4b945283070d442589d3bf00468abbc Signed-off-by: Deepak S <deepak.s@linux.intel.com> Signed-off-by: Edward MacGillivray <edward.s.macgillivray@intel.com> Signed-off-by: Ross Brattain <ross.b.brattain@intel.com>
Diffstat (limited to 'yardstick')
-rw-r--r--yardstick/common/utils.py26
-rw-r--r--yardstick/network_services/libs/__init__.py0
-rw-r--r--yardstick/network_services/libs/ixia_libs/IxNet/IxNet.py335
-rw-r--r--yardstick/network_services/libs/ixia_libs/IxNet/__init__.py0
-rw-r--r--yardstick/network_services/libs/ixia_libs/__init__.py0
-rw-r--r--yardstick/network_services/traffic_profile/http_ixload.py294
-rw-r--r--yardstick/network_services/traffic_profile/ixia_rfc2544.py155
-rw-r--r--yardstick/network_services/vnf_generic/vnf/tg_ixload.py176
-rw-r--r--yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py165
9 files changed, 1151 insertions, 0 deletions
diff --git a/yardstick/common/utils.py b/yardstick/common/utils.py
index 1059e1ce4..969bb4b38 100644
--- a/yardstick/common/utils.py
+++ b/yardstick/common/utils.py
@@ -370,3 +370,29 @@ def parse_cpuinfo(cpuinfo):
def config_to_dict(config):
return {section: dict(config.items(section)) for section in
config.sections()}
+
+
+def validate_non_string_sequence(value, default=None, raise_exc=None):
+ if isinstance(value, collections.Sequence) and not isinstance(value, str):
+ return value
+ if raise_exc:
+ raise raise_exc
+ return default
+
+
+def join_non_strings(separator, *non_strings):
+ try:
+ non_strings = validate_non_string_sequence(non_strings[0], raise_exc=RuntimeError)
+ except (IndexError, RuntimeError):
+ pass
+ return str(separator).join(str(non_string) for non_string in non_strings)
+
+
+class ErrorClass(object):
+
+ def __init__(self, *args, **kwargs):
+ if 'test' not in kwargs:
+ raise RuntimeError
+
+ def __getattr__(self, item):
+ raise AttributeError
diff --git a/yardstick/network_services/libs/__init__.py b/yardstick/network_services/libs/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/yardstick/network_services/libs/__init__.py
diff --git a/yardstick/network_services/libs/ixia_libs/IxNet/IxNet.py b/yardstick/network_services/libs/ixia_libs/IxNet/IxNet.py
new file mode 100644
index 000000000..815a2a21c
--- /dev/null
+++ b/yardstick/network_services/libs/ixia_libs/IxNet/IxNet.py
@@ -0,0 +1,335 @@
+# Copyright (c) 2016-2017 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import absolute_import
+from __future__ import print_function
+import sys
+import logging
+
+import re
+from itertools import product
+
+from yardstick.common.utils import ErrorClass
+
+try:
+ import IxNetwork
+except ImportError:
+ IxNetwork = ErrorClass
+
+log = logging.getLogger(__name__)
+
+IP_VERSION_4 = 4
+IP_VERSION_6 = 6
+
+
+class TrafficStreamHelper(object):
+
+ TEMPLATE = '{0.traffic_item}/{0.stream}:{0.param_id}/{1}'
+
+ def __init__(self, traffic_item, stream, param_id):
+ super(TrafficStreamHelper, self).__init__()
+ self.traffic_item = traffic_item
+ self.stream = stream
+ self.param_id = param_id
+
+ def __getattr__(self, item):
+ return self.TEMPLATE.format(self, item)
+
+
+class FramesizeHelper(object):
+
+ def __init__(self):
+ super(FramesizeHelper, self).__init__()
+ self.weighted_pairs = []
+ self.weighted_range_pairs = []
+
+ @property
+ def weighted_pairs_arg(self):
+ return '-weightedPairs', self.weighted_pairs
+
+ @property
+ def weighted_range_pairs_arg(self):
+ return '-weightedRangePairs', self.weighted_range_pairs
+
+ def make_args(self, *args):
+ return self.weighted_pairs_arg + self.weighted_range_pairs_arg + args
+
+ def populate_data(self, framesize_data):
+ for key, value in framesize_data.items():
+ if value == '0':
+ continue
+
+ replaced = re.sub('[Bb]', '', key)
+ self.weighted_pairs.extend([
+ replaced,
+ value,
+ ])
+ pairs = [
+ replaced,
+ replaced,
+ value,
+ ]
+ self.weighted_range_pairs.append(pairs)
+
+
+class IxNextgen(object):
+
+ STATS_NAME_MAP = {
+ "traffic_item": 'Traffic Item',
+ "Tx_Frames": 'Tx Frames',
+ "Rx_Frames": 'Rx Frames',
+ "Tx_Frame_Rate": 'Tx Frame Rate',
+ "Rx_Frame_Rate": 'Tx Frame Rate',
+ "Store-Forward_Avg_latency_ns": 'Store-Forward Avg Latency (ns)',
+ "Store-Forward_Min_latency_ns": 'Store-Forward Min Latency (ns)',
+ "Store-Forward_Max_latency_ns": 'Store-Forward Max Latency (ns)',
+ }
+
+ PORT_STATS_NAME_MAP = {
+ "stat_name": 'Stat Name',
+ "Frames_Tx": 'Frames Tx.',
+ "Valid_Frames_Rx": 'Valid Frames Rx.',
+ "Frames_Tx_Rate": 'Frames Tx. Rate',
+ "Valid_Frames_Rx_Rate": 'Valid Frames Rx. Rate',
+ "Tx_Rate_Kbps": 'Tx. Rate (Kbps)',
+ "Rx_Rate_Kbps": 'Rx. Rate (Kbps)',
+ "Tx_Rate_Mbps": 'Tx. Rate (Mbps)',
+ "Rx_Rate_Mbps": 'Rx. Rate (Mbps)',
+ }
+
+ LATENCY_NAME_MAP = {
+ "Store-Forward_Avg_latency_ns": 'Store-Forward Avg Latency (ns)',
+ "Store-Forward_Min_latency_ns": 'Store-Forward Min Latency (ns)',
+ "Store-Forward_Max_latency_ns": 'Store-Forward Max Latency (ns)',
+ }
+
+ RANDOM_MASK_MAP = {
+ IP_VERSION_4: '0.0.0.255',
+ IP_VERSION_6: '0:0:0:0:0:0:0:ff',
+ }
+
+ MODE_SEEDS_MAP = {
+ 0: ('private', ['256', '2048']),
+ }
+
+ MODE_SEEDS_DEFAULT = 'public', ['2048', '256']
+
+ @staticmethod
+ def find_view_obj(view_name, views):
+ edited_view_name = '::ixNet::OBJ-/statistics/view:"{}"'.format(view_name)
+ return next((view for view in views if edited_view_name == view), '')
+
+ @staticmethod
+ def get_config(tg_cfg):
+ external_interface = tg_cfg["vdu"][0]["external-interface"]
+ card_port0 = external_interface[0]["virtual-interface"]["vpci"]
+ card_port1 = external_interface[1]["virtual-interface"]["vpci"]
+ card0, port0 = card_port0.split(':')[:2]
+ card1, port1 = card_port1.split(':')[:2]
+ cfg = {
+ 'py_lib_path': tg_cfg["mgmt-interface"]["tg-config"]["py_lib_path"],
+ 'machine': tg_cfg["mgmt-interface"]["ip"],
+ 'port': tg_cfg["mgmt-interface"]["tg-config"]["tcl_port"],
+ 'chassis': tg_cfg["mgmt-interface"]["tg-config"]["ixchassis"],
+ 'card1': card0,
+ 'port1': port0,
+ 'card2': card1,
+ 'port2': port1,
+ 'output_dir': tg_cfg["mgmt-interface"]["tg-config"]["dut_result_dir"],
+ 'version': tg_cfg["mgmt-interface"]["tg-config"]["version"],
+ 'bidir': True,
+ }
+ return cfg
+
+ def __init__(self, ixnet=None):
+ self.ixnet = ixnet
+ self._objRefs = dict()
+ self._cfg = None
+ self._logger = logging.getLogger(__name__)
+ self._params = None
+ self._bidir = None
+
+ def iter_over_get_lists(self, x1, x2, y2, offset=0):
+ for x in self.ixnet.getList(x1, x2):
+ y_list = self.ixnet.getList(x, y2)
+ for i, y in enumerate(y_list, offset):
+ yield x, y, i
+
+ def set_random_ip_multi_attribute(self, ipv4, seed, fixed_bits, random_mask, l3_count):
+ self.ixnet.setMultiAttribute(
+ ipv4,
+ '-seed', str(seed),
+ '-fixedBits', str(fixed_bits),
+ '-randomMask', str(random_mask),
+ '-valueType', 'random',
+ '-countValue', str(l3_count))
+
+ def set_random_ip_multi_attributes(self, ip, version, seeds, l3):
+ try:
+ random_mask = self.RANDOM_MASK_MAP[version]
+ except KeyError:
+ raise ValueError('Unknown version %s' % version)
+
+ l3_count = l3['count']
+ if "srcIp" in ip:
+ fixed_bits = l3['srcip4']
+ self.set_random_ip_multi_attribute(ip, seeds[0], fixed_bits, random_mask, l3_count)
+ if "dstIp" in ip:
+ fixed_bits = l3['dstip4']
+ self.set_random_ip_multi_attribute(ip, seeds[1], fixed_bits, random_mask, l3_count)
+
+ def add_ip_header(self, params, version):
+ for it, ep, i in self.iter_over_get_lists('/traffic', 'trafficItem', "configElement"):
+ mode, seeds = self.MODE_SEEDS_MAP.get(i, self.MODE_SEEDS_DEFAULT)
+ l3 = params[mode]['outer_l3']
+
+ for ip, ip_bits, _ in self.iter_over_get_lists(ep, 'stack', 'field'):
+ self.set_random_ip_multi_attributes(ip_bits, version, seeds, l3)
+
+ self.ixnet.commit()
+
+ def _connect(self, tg_cfg):
+ self._cfg = self.get_config(tg_cfg)
+
+ sys.path.append(self._cfg["py_lib_path"])
+ self.ixnet = IxNetwork.IxNet()
+
+ machine = self._cfg['machine']
+ port = str(self._cfg['port'])
+ version = str(self._cfg['version'])
+ result = self.ixnet.connect(machine, '-port', port, '-version', version)
+ return result
+
+ def clear_ixia_config(self):
+ self.ixnet.execute('newConfig')
+
+ def load_ixia_profile(self, profile):
+ self.ixnet.execute('loadConfig', self.ixnet.readFrom(profile))
+
+ def ix_load_config(self, profile):
+ self.clear_ixia_config()
+ self.load_ixia_profile(profile)
+
+ def ix_assign_ports(self):
+ vports = self.ixnet.getList(self.ixnet.getRoot(), 'vport')
+ ports = [
+ (self._cfg['chassis'], self._cfg['card1'], self._cfg['port1']),
+ (self._cfg['chassis'], self._cfg['card2'], self._cfg['port2']),
+ ]
+
+ vport_list = self.ixnet.getList("/", "vport")
+ self.ixnet.execute('assignPorts', ports, [], vport_list, True)
+ self.ixnet.commit()
+
+ for vport in vports:
+ if self.ixnet.getAttribute(vport, '-state') != 'up':
+ log.error("Both thr ports are down...")
+
+ def ix_update_frame(self, params):
+ streams = ["configElement"]
+
+ for param in params.values():
+ framesize_data = FramesizeHelper()
+ traffic_items = self.ixnet.getList('/traffic', 'trafficItem')
+ param_id = param['id']
+ for traffic_item, stream in product(traffic_items, streams):
+ helper = TrafficStreamHelper(traffic_item, stream, param_id)
+
+ self.ixnet.setMultiAttribute(helper.transmissionControl,
+ '-type', '{0}'.format(param['traffic_type']),
+ '-duration', '{0}'.format(param['duration']))
+
+ stream_frame_rate_path = helper.frameRate
+ self.ixnet.setMultiAttribute(stream_frame_rate_path, '-rate', param['iload'])
+ if param['outer_l2']['framesPerSecond']:
+ self.ixnet.setMultiAttribute(stream_frame_rate_path,
+ '-type', 'framesPerSecond')
+
+ framesize_data.populate_data(param['outer_l2']['framesize'])
+
+ make_attr_args = framesize_data.make_args('-incrementFrom', '66',
+ '-randomMin', '66',
+ '-quadGaussian', [],
+ '-type', 'weightedPairs',
+ '-presetDistribution', 'cisco',
+ '-incrementTo', '1518')
+
+ self.ixnet.setMultiAttribute(helper.frameSize, *make_attr_args)
+
+ self.ixnet.commit()
+
+ def update_ether_multi_attribute(self, ether, mac_addr):
+ self.ixnet.setMultiAttribute(ether,
+ '-singleValue', mac_addr,
+ '-fieldValue', mac_addr,
+ '-valueType', 'singleValue')
+
+ def update_ether_multi_attributes(self, ether, l2):
+ if "ethernet.header.destinationAddress" in ether:
+ self.update_ether_multi_attribute(ether, str(l2['dstmac']))
+
+ if "ethernet.header.sourceAddress" in ether:
+ self.update_ether_multi_attribute(ether, str(l2['srcmac']))
+
+ def ix_update_ether(self, params):
+ for ti, ep, index in self.iter_over_get_lists('/traffic', 'trafficItem',
+ "configElement", 1):
+ iter1 = (v['outer_l2'] for v in params.values() if str(v['id']) == str(index))
+ try:
+ l2 = next(iter1, {})
+ except KeyError:
+ continue
+
+ for ip, ether, _ in self.iter_over_get_lists(ep, 'stack', 'field'):
+ self.update_ether_multi_attributes(ether, l2)
+
+ self.ixnet.commit()
+
+ def ix_update_udp(self, params):
+ pass
+
+ def ix_update_tcp(self, params):
+ pass
+
+ def ix_start_traffic(self):
+ tis = self.ixnet.getList('/traffic', 'trafficItem')
+ for ti in tis:
+ self.ixnet.execute('generate', [ti])
+ self.ixnet.execute('apply', '/traffic')
+ self.ixnet.execute('start', '/traffic')
+
+ def ix_stop_traffic(self):
+ tis = self.ixnet.getList('/traffic', 'trafficItem')
+ for _ in tis:
+ self.ixnet.execute('stop', '/traffic')
+
+ def build_stats_map(self, view_obj, name_map):
+ return {kl: self.execute_get_column_values(view_obj, kr) for kl, kr in name_map.items()}
+
+ def execute_get_column_values(self, view_obj, name):
+ return self.ixnet.execute('getColumnValues', view_obj, name)
+
+ def ix_get_statistics(self):
+ views = self.ixnet.getList('/statistics', 'view')
+ view_obj = self.find_view_obj("Traffic Item Statistics", views)
+ stats = self.build_stats_map(view_obj, self.STATS_NAME_MAP)
+
+ self.find_view_obj("Port Statistics", views)
+ ports_stats = self.build_stats_map(view_obj, self.PORT_STATS_NAME_MAP)
+
+ views = self.ixnet.getList('/statistics', 'view')
+ view_obj = self.find_view_obj("Flow Statistics", views)
+ stats["latency"] = self.build_stats_map(view_obj, self.LATENCY_NAME_MAP)
+
+ return stats, ports_stats
diff --git a/yardstick/network_services/libs/ixia_libs/IxNet/__init__.py b/yardstick/network_services/libs/ixia_libs/IxNet/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/yardstick/network_services/libs/ixia_libs/IxNet/__init__.py
diff --git a/yardstick/network_services/libs/ixia_libs/__init__.py b/yardstick/network_services/libs/ixia_libs/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/yardstick/network_services/libs/ixia_libs/__init__.py
diff --git a/yardstick/network_services/traffic_profile/http_ixload.py b/yardstick/network_services/traffic_profile/http_ixload.py
new file mode 100644
index 000000000..8a4f97f04
--- /dev/null
+++ b/yardstick/network_services/traffic_profile/http_ixload.py
@@ -0,0 +1,294 @@
+# Copyright (c) 2016-2017 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import absolute_import
+from __future__ import print_function
+
+import sys
+import os
+import logging
+
+# ixload uses its own py2. So importing jsonutils fails. So adding below
+# workaround to support call from yardstick
+try:
+ from oslo_serialization import jsonutils
+except ImportError:
+ import json as jsonutils
+
+from yardstick.common.utils import join_non_strings
+from yardstick.common.utils import ErrorClass
+
+try:
+ from IxLoad import IxLoad, StatCollectorUtils
+except ImportError:
+ IxLoad = ErrorClass
+ StatCollectorUtils = ErrorClass
+
+LOG = logging.getLogger(__name__)
+CSV_FILEPATH_NAME = 'IxL_statResults.csv'
+
+STATS_TO_GET = (
+ 'HTTP_Client.csv',
+ 'HTTP_Server.csv',
+ 'L2-3 Stats for Client Ports.csv',
+ 'L2-3 Stats for Server Ports.csv',
+ 'IxLoad Detailed Report.html',
+ 'IxLoad Detailed Report.pdf'
+)
+
+HTTP_CLIENT_STATS = [
+ ["HTTP Client", "TCP Connections Established", "kSum"],
+ ["HTTP Client", "TCP Connection Requests Failed", "kSum"],
+ ["HTTP Client", "HTTP Simulated Users", "kSum"],
+ ["HTTP Client", "HTTP Concurrent Connections", "kSum"],
+ ["HTTP Client", "HTTP Connections", "kSum"],
+ ["HTTP Client", "HTTP Transactions", "kSum"],
+ ["HTTP Client", "HTTP Connection Attempts", "kSum"]
+]
+
+HTTP_SERVER_STATS = [
+ ["HTTP Server", "TCP Connections Established", "kSum"],
+ ["HTTP Server", "TCP Connection Requests Failed", "kSum"]
+]
+
+
+INCOMING_STAT_RECORD_TEMPLATE = """
+=====================================
+INCOMING STAT RECORD >>> %s
+Len = %s
+%s
+%s
+=====================================
+"""
+
+INCOMING_STAT_INTERVAL_TEMPLATE = """
+=====================================
+Incoming stats: Time interval: %s
+Incoming stats: Time interval: %s
+=====================================
+"""
+
+
+class IXLOADHttpTest(object):
+
+ def __init__(self, test_input):
+ self.test_input = jsonutils.loads(test_input)
+ self.parse_run_test()
+ self.ix_load = None
+ self.stat_utils = None
+ self.remote_server = None
+ self.config_file = None
+ self.results_on_windows = None
+ self.result_dir = None
+ self.chassis = None
+ self.card = None
+ self.ports_to_reassign = None
+
+ @staticmethod
+ def format_ports_for_reassignment(ports):
+ formatted = [join_non_strings(';', p) for p in ports if len(p) == 3]
+ LOG.debug('for client ports:%s', os.linesep.join(formatted))
+ return formatted
+
+ def reassign_ports(self, test, repository, ports_to_reassign):
+ LOG.debug('ReassignPorts: %s %s', test, repository)
+
+ chassis_chain = repository.cget('chassisChain')
+ LOG.debug('chassischain: %s', chassis_chain)
+ client_ports = ports_to_reassign[0::2]
+ server_ports = ports_to_reassign[1::2]
+
+ client_ports = self.format_ports_for_reassignment(client_ports)
+ LOG.debug('Reassigning client ports: %s', client_ports)
+ server_ports = self.format_ports_for_reassignment(server_ports)
+ LOG.debug('Reassigning server ports: %s', server_ports)
+ ports_to_set = client_ports + server_ports
+
+ try:
+ LOG.debug('Reassigning ports: %s', ports_to_set)
+ test.setPorts(ports_to_set)
+ except Exception:
+ LOG.error('Error: Could not remap port assignment for: %s',
+ ports_to_set)
+ self.ix_load.delete(repository)
+ self.ix_load.disconnect()
+ raise
+
+ @staticmethod
+ def stat_collector(*args):
+ LOG.debug(INCOMING_STAT_RECORD_TEMPLATE, args, len(args), args[0], args[1])
+
+ @staticmethod
+ def IxL_StatCollectorCommand(*args):
+ stats = args[1][3]
+ timestamp = args[1][1]
+ LOG.debug(INCOMING_STAT_INTERVAL_TEMPLATE, timestamp, stats)
+
+ @staticmethod
+ def set_results_dir(test_controller, results_on_windows):
+ """
+ If the folder doesn't exists on the Windows Client PC,
+ IxLoad will automatically create it.
+ """
+ try:
+ test_controller.setResultDir(results_on_windows)
+ except Exception:
+ LOG.error('Error creating results dir on Win: %s',
+ results_on_windows)
+ raise
+
+ def load_config_file(self, config_file):
+ try:
+ LOG.debug(config_file)
+ repository = self.ix_load.new("ixRepository", name=config_file)
+ return repository
+ except Exception:
+ LOG.error('Error: IxLoad config file not found: %s', config_file)
+ raise
+
+ def start_http_test(self):
+ self.ix_load = IxLoad()
+
+ LOG.debug('--- ixLoad obj: %s', self.ix_load)
+ try:
+ self.ix_load.connect(self.remote_server)
+ except Exception:
+ raise
+
+ log_tag = "IxLoad-api"
+ log_name = "reprun"
+ logger = self.ix_load.new("ixLogger", log_tag, 1)
+ log_engine = logger.getEngine()
+ log_engine.setLevels(self.ix_load.ixLogger.kLevelDebug,
+ self.ix_load.ixLogger.kLevelInfo)
+ log_engine.setFile(log_name, 2, 256, 1)
+
+ # Initialize stat collection utilities
+ self.stat_utils = StatCollectorUtils()
+
+ test_controller = self.ix_load.new("ixTestController", outputDir=1)
+
+ repository = self.load_config_file(self.config_file)
+
+ # Get the first test on the testList
+ test_name = repository.testList[0].cget("name")
+ test = repository.testList.getItem(test_name)
+
+ self.set_results_dir(test_controller, self.results_on_windows)
+
+ test.config(statsRequired=1, enableResetPorts=1, csvInterval=2,
+ enableForceOwnership=True)
+
+ # ---- Remap ports ----
+ try:
+ self.reassign_ports(test, repository, self.ports_to_reassign)
+ except Exception:
+ LOG.exception("Exception occurred during reassign_ports")
+
+ # -----------------------------------------------------------------------
+ # Set up stat Collection
+ # -----------------------------------------------------------------------
+ test_server_handle = test_controller.getTestServerHandle()
+ self.stat_utils.Initialize(test_server_handle)
+
+ # Clear any stats that may have been registered previously
+ self.stat_utils.ClearStats()
+
+ # Define the stats we would like to collect
+ self.stat_utils.AddStat(caption="Watch_Stat_1",
+ statSourceType="HTTP Client",
+ statName="TCP Connections Established",
+ aggregationType="kSum",
+ filterList={})
+
+ self.stat_utils.AddStat(caption="Watch_Stat_2",
+ statSourceType="HTTP Client",
+ statName="TCP Connection Requests Failed",
+ aggregationType="kSum",
+ filterList={})
+
+ self.stat_utils.AddStat(caption="Watch_Stat_3",
+ statSourceType="HTTP Server",
+ statName="TCP Connections Established",
+ aggregationType="kSum",
+ filterList={})
+
+ self.stat_utils.AddStat(caption="Watch_Stat_4",
+ statSourceType="HTTP Server",
+ statName="TCP Connection Requests Failed",
+ aggregationType="kSum",
+ filterList={})
+
+ self.stat_utils.StartCollector(self.IxL_StatCollectorCommand)
+
+ test_controller.run(test)
+ self.ix_load.waitForTestFinish()
+
+ test_controller.releaseConfigWaitFinish()
+
+ # Stop the collector (running in the tcl event loop)
+ self.stat_utils.StopCollector()
+
+ # Cleanup
+ test_controller.generateReport(detailedReport=1, format="PDF;HTML")
+ test_controller.releaseConfigWaitFinish()
+
+ self.ix_load.delete(test)
+ self.ix_load.delete(test_controller)
+ self.ix_load.delete(logger)
+ self.ix_load.delete(log_engine)
+
+ LOG.debug('Retrieving CSV stats from Windows Client PC ...')
+ for stat_file in STATS_TO_GET:
+ enhanced_stat_file = stat_file.replace('-', '')
+ enhanced_stat_file = enhanced_stat_file.replace(' ', '_')
+ enhanced_stat_file = enhanced_stat_file.replace('__', '_')
+
+ LOG.debug('Getting csv stat file: %s', stat_file)
+ src_file = os.path.join(self.results_on_windows, stat_file)
+ dst_file = os.path.join(self.result_dir, '_'.join(['ixLoad', enhanced_stat_file]))
+ self.ix_load.retrieveFileCopy(src_file, dst_file)
+
+ self.ix_load.disconnect()
+
+ def parse_run_test(self):
+ self.remote_server = self.test_input["remote_server"]
+ LOG.debug("remote tcl server: %s", self.remote_server)
+
+ self.config_file = self.test_input["ixload_cfg"]
+ LOG.debug("ixload config: %s", self.remote_server)
+
+ self.results_on_windows = 'C:/Results'
+ self.result_dir = self.test_input["result_dir"]
+ self.chassis = self.test_input["ixia_chassis"]
+ LOG.debug("remote ixia chassis: %s", self.chassis)
+
+ self.card = self.test_input["IXIA"]["card"]
+ self.ports_to_reassign = [
+ [self.chassis, self.card, port] for port in
+ self.test_input["IXIA"]["ports"]
+ ]
+
+ LOG.debug("Ports to be reassigned: %s", self.ports_to_reassign)
+
+
+def main(args):
+ # Get the args from cmdline and parse and run the test
+ test_input = "".join(args[1:])
+ if test_input:
+ ixload_obj = IXLOADHttpTest(test_input)
+ ixload_obj.start_http_test()
+
+if __name__ == '__main__':
+ main(sys.argv)
diff --git a/yardstick/network_services/traffic_profile/ixia_rfc2544.py b/yardstick/network_services/traffic_profile/ixia_rfc2544.py
new file mode 100644
index 000000000..5ba00180b
--- /dev/null
+++ b/yardstick/network_services/traffic_profile/ixia_rfc2544.py
@@ -0,0 +1,155 @@
+# Copyright (c) 2016-2017 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import absolute_import
+import logging
+import json
+
+from yardstick.network_services.traffic_profile.traffic_profile import \
+ TrexProfile
+
+LOG = logging.getLogger(__name__)
+
+
+class IXIARFC2544Profile(TrexProfile):
+ def _get_ixia_traffic_profile(self, profile_data, mac={},
+ xfile=None, static_traffic={}):
+ result = {}
+ if xfile:
+ with open(xfile, 'r') as stream:
+ try:
+ static_traffic = json.load(stream)
+ except Exception as exc:
+ LOG.debug(exc)
+
+ for traffickey, trafficvalue in static_traffic.items():
+ traffic = static_traffic[traffickey]
+ # outer_l2
+ index = 0
+ for key, value in profile_data[traffickey].items():
+ framesize = value['outer_l2']['framesize']
+ traffic['outer_l2']['framesize'] = framesize
+ traffic['framesPerSecond'] = True
+ traffic['bidir'] = False
+ traffic['outer_l2']['srcmac'] = \
+ mac["src_mac_{}".format(traffic['id'])]
+ traffic['outer_l2']['dstmac'] = \
+ mac["dst_mac_{}".format(traffic['id'])]
+ # outer_l3
+ if "outer_l3v6" in list(value.keys()):
+ traffic['outer_l3'] = value['outer_l3v6']
+ srcip4 = value['outer_l3v6']['srcip6']
+ traffic['outer_l3']['srcip4'] = srcip4.split("-")[0]
+ dstip4 = value['outer_l3v6']['dstip6']
+ traffic['outer_l3']['dstip4'] = dstip4.split("-")[0]
+ else:
+ traffic['outer_l3'] = value['outer_l3v4']
+ srcip4 = value['outer_l3v4']['srcip4']
+ traffic['outer_l3']['srcip4'] = srcip4.split("-")[0]
+ dstip4 = value['outer_l3v4']['dstip4']
+ traffic['outer_l3']['dstip4'] = dstip4.split("-")[0]
+
+ traffic['outer_l3']['type'] = key
+ # outer_l4
+ traffic['outer_l4'] = value['outer_l4']
+ index = index + 1
+ result.update({traffickey: traffic})
+
+ return result
+
+ def _ixia_traffic_generate(self, traffic_generator, traffic, ixia_obj):
+ for key, value in traffic.items():
+ if "public" in key or "private" in key:
+ traffic[key]["iload"] = str(self.rate)
+ ixia_obj.ix_update_frame(traffic)
+ ixia_obj.ix_update_ether(traffic)
+ # ixia_obj.ix_update_ipv4(traffic)
+ ixia_obj.ix_start_traffic()
+ self.tmp_drop = 0
+ self.tmp_throughput = 0
+
+ def execute(self, traffic_generator, ixia_obj, mac={}, xfile=None):
+ if self.first_run:
+ self.full_profile = {}
+ self.pg_id = 0
+ self.profile = 'private_1'
+ for key, value in self.params.items():
+ if "private" in key or "public" in key:
+ self.profile_data = self.params[key]
+ self.get_streams(self.profile_data)
+ self.full_profile.update({key: self.profile_data})
+ traffic = \
+ self._get_ixia_traffic_profile(self.full_profile, mac, xfile)
+ self.max_rate = self.rate
+ self.min_rate = 0
+ self.get_multiplier()
+ self._ixia_traffic_generate(traffic_generator, traffic, ixia_obj)
+
+ def get_multiplier(self):
+ self.rate = round((self.max_rate + self.min_rate) / 2.0, 2)
+ multiplier = round(self.rate / self.pps, 2)
+ return str(multiplier)
+
+ def start_ixia_latency(self, traffic_generator, ixia_obj,
+ mac={}, xfile=None):
+ traffic = self._get_ixia_traffic_profile(self.full_profile, mac)
+ self._ixia_traffic_generate(traffic_generator, traffic,
+ ixia_obj, xfile)
+
+ def get_drop_percentage(self, traffic_generator, samples, tol_min,
+ tolerance, ixia_obj, mac={}, xfile=None):
+ status = 'Running'
+ drop_percent = 100
+ in_packets = sum([samples[iface]['in_packets'] for iface in samples])
+ out_packets = sum([samples[iface]['out_packets'] for iface in samples])
+ rx_throughput = \
+ sum([samples[iface]['RxThroughput'] for iface in samples])
+ tx_throughput = \
+ sum([samples[iface]['TxThroughput'] for iface in samples])
+ packet_drop = abs(out_packets - in_packets)
+ try:
+ drop_percent = round((packet_drop / float(out_packets)) * 100, 2)
+ except ZeroDivisionError:
+ LOG.info('No traffic is flowing')
+ samples['TxThroughput'] = round(tx_throughput / 1.0, 2)
+ samples['RxThroughput'] = round(rx_throughput / 1.0, 2)
+ samples['CurrentDropPercentage'] = drop_percent
+ samples['Throughput'] = self.tmp_throughput
+ samples['DropPercentage'] = self.tmp_drop
+ if drop_percent > tolerance and self.tmp_throughput == 0:
+ samples['Throughput'] = round(rx_throughput / 1.0, 2)
+ samples['DropPercentage'] = drop_percent
+ if self.first_run:
+ max_supported_rate = out_packets / 30.0
+ self.rate = max_supported_rate
+ self.first_run = False
+ if drop_percent <= tolerance:
+ status = 'Completed'
+ if drop_percent > tolerance:
+ self.max_rate = self.rate
+ elif drop_percent < tol_min:
+ self.min_rate = self.rate
+ if drop_percent >= self.tmp_drop:
+ self.tmp_drop = drop_percent
+ self.tmp_throughput = round((rx_throughput / 1.0), 2)
+ samples['Throughput'] = round(rx_throughput / 1.0, 2)
+ samples['DropPercentage'] = drop_percent
+ else:
+ samples['Throughput'] = round(rx_throughput / 1.0, 2)
+ samples['DropPercentage'] = drop_percent
+ return status, samples
+ self.get_multiplier()
+ traffic = self._get_ixia_traffic_profile(self.full_profile, mac, xfile)
+ self._ixia_traffic_generate(traffic_generator, traffic, ixia_obj)
+ return status, samples
diff --git a/yardstick/network_services/vnf_generic/vnf/tg_ixload.py b/yardstick/network_services/vnf_generic/vnf/tg_ixload.py
new file mode 100644
index 000000000..c15f7b954
--- /dev/null
+++ b/yardstick/network_services/vnf_generic/vnf/tg_ixload.py
@@ -0,0 +1,176 @@
+# Copyright (c) 2016-2017 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import absolute_import
+import csv
+import glob
+import logging
+import os
+import shutil
+
+from collections import OrderedDict
+from subprocess import call
+
+import six
+
+from yardstick.common.utils import makedirs
+from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNFTrafficGen
+from yardstick.network_services.vnf_generic.vnf.sample_vnf import ClientResourceHelper
+
+LOG = logging.getLogger(__name__)
+
+VNF_PATH = os.path.dirname(os.path.realpath(__file__))
+
+MOUNT_CMD = """\
+mount.cifs //{0[ip]}/Results {1.RESULTS_MOUNT} \
+-o username={0[user]},password={0[password]}\
+"""
+
+IXLOAD_CONFIG_TEMPLATE = '''\
+{
+ "ixia_chassis": "%s",
+ "IXIA": {
+ "ports": %s,
+ "card": %s
+ },
+ "remote_server": "%s",
+ "result_dir": "%s",
+ "ixload_cfg": '"C:/Results/%s"
+}'''
+
+IXLOAD_CMD = "{ixloadpy} {http_ixload} {args}"
+
+
+class ResourceDataHelper(list):
+
+ def get_aggregates(self):
+ return {
+ "min": min(self),
+ "max": max(self),
+ "avg": sum(self) / len(self),
+ }
+
+
+class IxLoadResourceHelper(ClientResourceHelper):
+
+ RESULTS_MOUNT = "/mnt/Results"
+
+ KPI_LIST = OrderedDict((
+ ('http_throughput', 'HTTP Total Throughput (Kbps)'),
+ ('simulated_users', 'HTTP Simulated Users'),
+ ('concurrent_connections', 'HTTP Concurrent Connections'),
+ ('connection_rate', 'HTTP Connection Rate'),
+ ('transaction_rate', 'HTTP Transaction Rate'),
+ ))
+
+ def __init__(self, setup_helper):
+ super(IxLoadResourceHelper, self).__init__(setup_helper)
+ self.result = OrderedDict((key, ResourceDataHelper()) for key in self.KPI_LIST)
+ self.resource_file_name = ''
+
+ def parse_csv_read(self, reader):
+ for row in reader:
+ try:
+ new_data = {key_left: int(row[key_right])
+ for key_left, key_right in self.KPI_LIST.items()}
+ except (TypeError, ValueError):
+ continue
+ else:
+ for key, value in new_data.items():
+ self.result[key].append(value)
+
+ def setup(self):
+ # TODO: fixupt scenario_helper to hanlde ixia
+ self.resource_file_name = str(self.scenario_helper.scenario_cfg['ixia_profile'])
+ makedirs(self.RESULTS_MOUNT)
+ cmd = MOUNT_CMD.format(self.vnfd_helper.mgmt_interface, self)
+ LOG.debug(cmd)
+
+ if not os.path.ismount(self.RESULTS_MOUNT):
+ call(cmd, shell=True)
+
+ shutil.rmtree(self.RESULTS_MOUNT, ignore_errors=True)
+ makedirs(self.RESULTS_MOUNT)
+ shutil.copy(self.resource_file_name, self.RESULTS_MOUNT)
+
+ def make_aggregates(self):
+ return {key_right: self.result[key_left].get_aggregates()
+ for key_left, key_right in self.KPI_LIST.items()}
+
+ def log(self):
+ for key in self.KPI_LIST:
+ LOG.debug(self.result[key])
+
+
+class IxLoadTrafficGen(SampleVNFTrafficGen):
+
+ def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None):
+ if resource_helper_type is None:
+ resource_helper_type = IxLoadResourceHelper
+
+ super(IxLoadTrafficGen, self).__init__(name, vnfd, setup_env_helper_type,
+ resource_helper_type)
+ self._result = {}
+ self.done = False
+ self.data = None
+
+ def run_traffic(self, traffic_profile):
+ ports = []
+ card = None
+ for interface in self.vnfd_helper.interfaces:
+ vpci_list = interface['virtual-interface']["vpci"].split(":")
+ card = vpci_list[0]
+ ports.append(vpci_list[1])
+
+ for csv_file in glob.iglob(self.ssh_helper.join_bin_path('*.csv')):
+ os.unlink(csv_file)
+
+ ixia_config = self.vnfd_helper.mgmt_interface["tg-config"]
+ ixload_config = IXLOAD_CONFIG_TEMPLATE % (
+ ixia_config["ixchassis"], ports, card,
+ self.vnfd_helper.mgmt_interface["ip"], self.ssh_helper.bin_path,
+ os.path.basename(self.resource_helper.resource_file_name))
+
+ http_ixload_path = os.path.join(VNF_PATH, "../../traffic_profile")
+ cmd = IXLOAD_CMD.format(
+ ixloadpy=os.path.join(ixia_config["py_bin_path"], "ixloadpython"),
+ http_ixload=os.path.join(http_ixload_path, "http_ixload.py"),
+ args="'%s'" % ixload_config)
+
+ LOG.debug(cmd)
+ call(cmd, shell=True)
+
+ with open(self.ssh_helper.join_bin_path("ixLoad_HTTP_Client.csv")) as csv_file:
+ lines = csv_file.readlines()[10:]
+
+ with open(self.ssh_helper.join_bin_path("http_result.csv"), 'wb+') as result_file:
+ result_file.writelines(six.text_type(lines[:-1]))
+ result_file.flush()
+ result_file.seek(0)
+ reader = csv.DictReader(result_file)
+ self.resource_helper.parse_csv_read(reader)
+
+ self.resource_helper.log()
+ self.data = self.resource_helper.make_aggregates()
+
+ def listen_traffic(self, traffic_profile):
+ pass
+
+ def instantiate(self, scenario_cfg, context_cfg):
+ super(IxLoadTrafficGen, self).instantiate(scenario_cfg, context_cfg)
+ self.done = False
+
+ def terminate(self):
+ call(["pkill", "-9", "http_ixload.py"])
+ super(IxLoadTrafficGen, self).terminate()
diff --git a/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py b/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py
new file mode 100644
index 000000000..07bbdae95
--- /dev/null
+++ b/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py
@@ -0,0 +1,165 @@
+# Copyright (c) 2016-2017 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import absolute_import
+import time
+import os
+import logging
+import sys
+
+from yardstick.common.utils import ErrorClass
+from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNFTrafficGen
+from yardstick.network_services.vnf_generic.vnf.sample_vnf import ClientResourceHelper
+from yardstick.network_services.vnf_generic.vnf.sample_vnf import Rfc2544ResourceHelper
+
+try:
+ from IxNet import IxNextgen
+except ImportError:
+ IxNextgen = ErrorClass
+
+LOG = logging.getLogger(__name__)
+
+WAIT_AFTER_CFG_LOAD = 10
+WAIT_FOR_TRAFFIC = 30
+IXIA_LIB = os.path.dirname(os.path.realpath(__file__))
+IXNET_LIB = os.path.join(IXIA_LIB, "../../libs/ixia_libs/IxNet")
+sys.path.append(IXNET_LIB)
+
+
+class IxiaRfc2544Helper(Rfc2544ResourceHelper):
+
+ pass
+
+
+class IxiaResourceHelper(ClientResourceHelper):
+
+ def __init__(self, setup_helper, rfc_helper_type=None):
+ super(IxiaResourceHelper, self).__init__(setup_helper)
+ self.scenario_helper = setup_helper.scenario_helper
+
+ self.client = IxNextgen()
+
+ if rfc_helper_type is None:
+ rfc_helper_type = IxiaRfc2544Helper
+
+ self.rfc_helper = rfc_helper_type(self.scenario_helper)
+ self.tg_port_pairs = []
+ self.priv_ports = None
+ self.pub_ports = None
+
+ def _connect(self, client=None):
+ self.client.connect(self.vnfd_helper)
+
+ def _build_ports(self):
+ # self.generate_port_pairs(self.topology)
+ self.priv_ports = [int(x[0][-1]) for x in self.tg_port_pairs]
+ self.pub_ports = [int(x[1][-1]) for x in self.tg_port_pairs]
+ self.my_ports = list(set(self.priv_ports).union(set(self.pub_ports)))
+
+ def get_stats(self, *args, **kwargs):
+ return self.client.ix_get_statistics()[1]
+
+ def stop_collect(self):
+ self._terminated.value = 0
+ if self.client:
+ self.client.ix_stop_traffic()
+
+ def generate_samples(self, key=None, default=None):
+ last_result = self.get_stats()
+
+ samples = {}
+ for vpci_idx, interface in enumerate(self.vnfd_helper.interfaces):
+ name = "xe{0}".format(vpci_idx)
+ samples[name] = {
+ "rx_throughput_kps": float(last_result["Rx_Rate_Kbps"][vpci_idx]),
+ "tx_throughput_kps": float(last_result["Tx_Rate_Kbps"][vpci_idx]),
+ "rx_throughput_mbps": float(last_result["Rx_Rate_Mbps"][vpci_idx]),
+ "tx_throughput_mbps": float(last_result["Tx_Rate_Mbps"][vpci_idx]),
+ "in_packets": int(last_result["Valid_Frames_Rx"][vpci_idx]),
+ "out_packets": int(last_result["Frames_Tx"][vpci_idx]),
+ "RxThroughput": int(last_result["Valid_Frames_Rx"][vpci_idx]) / 30,
+ "TxThroughput": int(last_result["Frames_Tx"][vpci_idx]) / 30,
+ }
+
+ return samples
+
+ def run_traffic(self, traffic_profile):
+ min_tol = self.rfc_helper.tolerance_low
+ max_tol = self.rfc_helper.tolerance_high
+
+ self._build_ports()
+ self._connect()
+
+ # we don't know client_file_name until runtime as instantiate
+ client_file_name = self.scenario_helper.scenario_cfg['ixia_profile']
+ self.client.ix_load_config(client_file_name)
+ time.sleep(WAIT_AFTER_CFG_LOAD)
+
+ self.client.ix_assign_ports()
+
+ mac = {}
+ for index, interface in enumerate(self.vnfd_helper.interfaces):
+ virt_intf = interface["virtual-interface"]
+ mac.update({
+ "src_mac_{}".format(index): virt_intf["local_mac"],
+ "dst_mac_{}".format(index): virt_intf["dst_mac"],
+ })
+
+ samples = {}
+ ixia_file = os.path.join(os.getcwd(), "ixia_traffic.cfg")
+ # Generate ixia traffic config...
+ while not self._terminated.value:
+ traffic_profile.execute(self, self.client, mac, ixia_file)
+ self.client_started.value = 1
+ time.sleep(WAIT_FOR_TRAFFIC)
+ self.client.ix_stop_traffic()
+ samples = self.generate_samples()
+ self._queue.put(samples)
+ status, samples = traffic_profile.get_drop_percentage(self, samples, min_tol,
+ max_tol, self.client, mac,
+ ixia_file)
+
+ current = samples['CurrentDropPercentage']
+ if min_tol <= current <= max_tol or status == 'Completed':
+ self._terminated.value = 1
+
+ self.client.ix_stop_traffic()
+ self._queue.put(samples)
+
+
+class IxiaTrafficGen(SampleVNFTrafficGen):
+
+ def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None):
+ if resource_helper_type is None:
+ resource_helper_type = IxiaResourceHelper
+
+ super(IxiaTrafficGen, self).__init__(name, vnfd, setup_env_helper_type,
+ resource_helper_type)
+ self._ixia_traffic_gen = None
+ self.ixia_file_name = ''
+ self.tg_port_pairs = []
+ self.vnf_port_pairs = []
+
+ def _check_status(self):
+ pass
+
+ def scale(self, flavor=""):
+ pass
+
+ def listen_traffic(self, traffic_profile):
+ pass
+
+ def terminate(self):
+ self.resource_helper.stop_collect()
+ super(IxiaTrafficGen, self).terminate()