aboutsummaryrefslogtreecommitdiffstats
path: root/tools/pkt_gen
diff options
context:
space:
mode:
Diffstat (limited to 'tools/pkt_gen')
-rwxr-xr-xtools/pkt_gen/ixnet/ixnet.py86
-rw-r--r--tools/pkt_gen/testcenter/testcenter-rfc2544-rest.py270
-rw-r--r--tools/pkt_gen/testcenter/testcenter.py33
-rw-r--r--tools/pkt_gen/trex/trex_client.py (renamed from tools/pkt_gen/trex/trex.py)87
4 files changed, 436 insertions, 40 deletions
diff --git a/tools/pkt_gen/ixnet/ixnet.py b/tools/pkt_gen/ixnet/ixnet.py
index 87fb2c65..c7036606 100755
--- a/tools/pkt_gen/ixnet/ixnet.py
+++ b/tools/pkt_gen/ixnet/ixnet.py
@@ -83,6 +83,7 @@ import logging
import os
import re
import csv
+import random
from collections import OrderedDict
from tools.pkt_gen import trafficgen
@@ -129,7 +130,7 @@ def _build_set_cmds(values, prefix='dict set'):
if isinstance(value, list):
value = '{{{}}}'.format(' '.join(str(x) for x in value))
- yield ' '.join([prefix, 'set', key, value]).strip()
+ yield ' '.join([prefix, key, value]).strip()
continue
# tcl doesn't recognise the strings "True" or "False", only "1"
@@ -176,10 +177,9 @@ class IxNet(trafficgen.ITrafficGenerator):
:returns: Output of command, where applicable.
"""
self._logger.debug('%s%s', trafficgen.CMD_PREFIX, cmd)
-
output = self._tclsh.eval(cmd)
- return output.split()
+ return output
def configure(self):
"""Configure system for IxNetwork.
@@ -193,12 +193,16 @@ class IxNet(trafficgen.ITrafficGenerator):
'port': settings.getValue('TRAFFICGEN_IXNET_PORT'),
'user': settings.getValue('TRAFFICGEN_IXNET_USER'),
# IXIA chassis configuration
- 'chassis': settings.getValue('TRAFFICGEN_IXIA_HOST'),
- 'card': settings.getValue('TRAFFICGEN_IXIA_CARD'),
- 'port1': settings.getValue('TRAFFICGEN_IXIA_PORT1'),
- 'port2': settings.getValue('TRAFFICGEN_IXIA_PORT2'),
+ 'chassis_east': settings.getValue('TRAFFICGEN_EAST_IXIA_HOST'),
+ 'card_east': settings.getValue('TRAFFICGEN_EAST_IXIA_CARD'),
+ 'port_east': settings.getValue('TRAFFICGEN_EAST_IXIA_PORT'),
+ 'chassis_west': settings.getValue('TRAFFICGEN_WEST_IXIA_HOST'),
+ 'card_west': settings.getValue('TRAFFICGEN_WEST_IXIA_CARD'),
+ 'port_west': settings.getValue('TRAFFICGEN_WEST_IXIA_PORT'),
'output_dir':
settings.getValue('TRAFFICGEN_IXNET_TESTER_RESULT_DIR'),
+ 'frame_size_list':
+ settings.getValue('TRAFFICGEN_PKT_SIZES'),
}
self._logger.debug('IXIA configuration configuration : %s', self._cfg)
@@ -256,11 +260,12 @@ class IxNet(trafficgen.ITrafficGenerator):
'An error occured when connecting to IxNetwork machine...')
raise RuntimeError('Ixia failed to initialise.')
- self.run_tcl('startRfc2544Test $config $traffic')
+ results_path = self.run_tcl('startRfc2544Test $config $traffic')
if output:
self._logger.critical(
'Failed to start continuous traffic test')
raise RuntimeError('Continuous traffic test failed to start.')
+ return results_path
def stop_cont_traffic(self):
"""See ITrafficGenerator for description
@@ -271,9 +276,12 @@ class IxNet(trafficgen.ITrafficGenerator):
lossrate=0.0):
"""See ITrafficGenerator for description
"""
- self.start_rfc2544_throughput(traffic, tests, duration, lossrate)
-
- return self.wait_rfc2544_throughput()
+ results_file = self.start_rfc2544_throughput(traffic, tests, duration, lossrate)
+ run_result = self.wait_rfc2544_throughput()
+ dest_file_name = 'Traffic_Item_Statistics_' + str(random.randrange(1, 100)) + '.csv'
+ self.copy_results_file(results_file,
+ os.path.join(settings.getValue('RESULTS_PATH'), dest_file_name))
+ return run_result
def start_rfc2544_throughput(self, traffic=None, tests=1, duration=20,
lossrate=0.0):
@@ -313,12 +321,14 @@ class IxNet(trafficgen.ITrafficGenerator):
'An error occured when connecting to IxNetwork machine...')
raise RuntimeError('Ixia failed to initialise.')
- self.run_tcl('startRfc2544Test $config $traffic')
+ results_file = self.run_tcl('startRfc2544Test $config $traffic')
if output:
self._logger.critical(
'Failed to start RFC2544 test')
raise RuntimeError('RFC2544 test failed to start.')
+ return results_file
+
def wait_rfc2544_throughput(self):
"""See ITrafficGenerator for description
"""
@@ -397,12 +407,34 @@ class IxNet(trafficgen.ITrafficGenerator):
return results
output = self.run_tcl('waitForRfc2544Test')
-
# the run_tcl function will return a list with one element. We extract
# that one element (a string representation of an IXIA-specific Tcl
# datatype), parse it to find the path of the results file then parse
# the results file
- return parse_ixnet_rfc_results(parse_result_string(output[0]))
+ test_result = parse_ixnet_rfc_results(parse_result_string(output))
+ return test_result
+
+ def copy_results_file(self, source_file=None, dest_file=None):
+ """Copy a file from a source address to destination
+ """
+ dest_dict = {}
+ source_dict = {}
+ srcfile = ''
+ if isinstance(source_file, list):
+ for i in source_file:
+ srcfile = srcfile + ' ' + i
+ else:
+ srcfile = source_file
+
+ source = (srcfile.replace("\\", "/")).strip()
+ source_dict['source_file'] = {'source_file': '\"{}\"'.format(source)}
+ dest_dict['dest_file'] = {'dest_file': '{}'.format(dest_file)}
+ for cmd in _build_set_cmds(source_dict):
+ self.run_tcl(cmd)
+ for cmd in _build_set_cmds(dest_dict):
+ self.run_tcl(cmd)
+ self.run_tcl('copyFileResults $source_file $dest_file')
+ return dest_dict['dest_file']
def send_rfc2544_back2back(self, traffic=None, tests=1, duration=2,
lossrate=0.0):
@@ -411,9 +443,12 @@ class IxNet(trafficgen.ITrafficGenerator):
# NOTE 2 seconds is the recommended duration for a back 2 back
# test in RFC2544. 50 trials is the recommended number from the
# RFC also.
- self.start_rfc2544_back2back(traffic, tests, duration, lossrate)
-
- return self.wait_rfc2544_back2back()
+ b2b_results_file = self.start_rfc2544_back2back(traffic, tests, duration, lossrate)
+ b2b_run_result = self.wait_rfc2544_back2back()
+ dest_file_name = 'Traffic_Item_Statistics_' + str(random.randrange(1, 100)) + '.csv'
+ self.copy_results_file(b2b_results_file,
+ os.path.join(settings.getValue('RESULTS_PATH'), dest_file_name))
+ return b2b_run_result
def start_rfc2544_back2back(self, traffic=None, tests=1, duration=2,
lossrate=0.0):
@@ -453,15 +488,18 @@ class IxNet(trafficgen.ITrafficGenerator):
'An error occured when connecting to IxNetwork machine...')
raise RuntimeError('Ixia failed to initialise.')
- self.run_tcl('startRfc2544Test $config $traffic')
+ results_file = self.run_tcl('startRfc2544Test $config $traffic')
if output:
self._logger.critical(
'Failed to start RFC2544 test')
raise RuntimeError('RFC2544 test failed to start.')
+ return results_file
+
def wait_rfc2544_back2back(self):
"""Wait for results.
"""
+
def parse_result_string(results):
"""Get path to results file from output
@@ -487,7 +525,7 @@ class IxNet(trafficgen.ITrafficGenerator):
# transform path into something useful
path = result_path.group(1).replace('\\', '/')
- path = os.path.join(path, 'iteration.csv')
+ path = os.path.join(path, 'AggregateResults.csv')
path = path.replace(
settings.getValue('TRAFFICGEN_IXNET_TESTER_RESULT_DIR'),
settings.getValue('TRAFFICGEN_IXNET_DUT_RESULT_DIR'))
@@ -511,11 +549,11 @@ class IxNet(trafficgen.ITrafficGenerator):
for row in reader:
# if back2back count higher than previously found, store it
# Note: row[N] here refers to the Nth column of a row
- if float(row[14]) <= self._params['config']['lossrate']:
- if int(row[12]) > \
+ if float(row[10]) <= self._params['config']['lossrate']:
+ if int(float(row[8])) > \
int(results[ResultsConstants.B2B_FRAMES]):
- results[ResultsConstants.B2B_FRAMES] = int(row[12])
- results[ResultsConstants.B2B_FRAME_LOSS_PERCENT] = float(row[14])
+ results[ResultsConstants.B2B_FRAMES] = int(float(row[8]))
+ results[ResultsConstants.B2B_FRAME_LOSS_PERCENT] = float(row[10])
return results
@@ -526,7 +564,7 @@ class IxNet(trafficgen.ITrafficGenerator):
# datatype), parse it to find the path of the results file then parse
# the results file
- return parse_ixnet_rfc_results(parse_result_string(output[0]))
+ return parse_ixnet_rfc_results(parse_result_string(output))
def send_burst_traffic(self, traffic=None, duration=20):
return NotImplementedError('IxNet does not implement send_burst_traffic')
diff --git a/tools/pkt_gen/testcenter/testcenter-rfc2544-rest.py b/tools/pkt_gen/testcenter/testcenter-rfc2544-rest.py
index 6c30b130..8089ef42 100644
--- a/tools/pkt_gen/testcenter/testcenter-rfc2544-rest.py
+++ b/tools/pkt_gen/testcenter/testcenter-rfc2544-rest.py
@@ -22,12 +22,27 @@ TestCenter REST APIs. This test supports Python 3.4
'''
import argparse
+import collections
import logging
import os
-
+import sqlite3
+import time
_LOGGER = logging.getLogger(__name__)
+GENOME_PKTSIZE_ENCODING = {"a": 64, "b": 128, "c": 256, "d": 512,
+ "e": 1024, "f": 1280, "g": 1518, "h": 2112}
+
+
+def genome2weights(sequence):
+ """ Convert genome sequence to packetsize weights"""
+ weights = collections.defaultdict(int)
+ for char in GENOME_PKTSIZE_ENCODING:
+ charcount = sequence.count(char)
+ if charcount:
+ weights[GENOME_PKTSIZE_ENCODING[char]] = charcount
+ return weights
+
def create_dir(path):
"""Create the directory as specified in path """
@@ -39,6 +54,17 @@ def create_dir(path):
raise
+def write_histogram_to_csv(results_path, csv_results_file_prefix,
+ counts, ranges):
+ """ Write the results of the query to the CSV """
+ filec = os.path.join(results_path, csv_results_file_prefix + ".csv")
+ with open(filec, "wb") as result_file:
+ for key in counts:
+ result_file.write(str(key) + "\n")
+ result_file.write(str(ranges) + "\n")
+ result_file.write(str(counts[key]) + "\n")
+
+
def write_query_results_to_csv(results_path, csv_results_file_prefix,
query_results):
""" Write the results of the query to the CSV """
@@ -51,6 +77,46 @@ def write_query_results_to_csv(results_path, csv_results_file_prefix,
result_file.write(row.replace(" ", ",") + "\n")
+def write_headers(results_path, file_name, rx_tx):
+ """ Write headers for the live-results files """
+ filec = os.path.join(results_path, file_name + rx_tx)
+ with open(filec, "a") as result_file:
+ if 'rx' in rx_tx:
+ result_file.write('Time,RxPrt,DrpFrCnt,SeqRnLen,AvgLat,' +
+ 'DrpFrRate,FrCnt,FrRate,MaxLat,MinLat,' +
+ 'OctCnt,OctRate\n')
+ else:
+ result_file.write('Time,StrId,BlkId,FrCnt,FrRate,ERxFrCnt,' +
+ 'OctCnt,OctRate,bitCnt,bitRate\n')
+
+
+def write_rx_live_results_to_file(results_path, file_name, results):
+ """ Write live results from the rx-ports"""
+ filec = os.path.join(results_path, file_name + ".rx")
+ with open(filec, "a") as result_file:
+ result_file.write('{0},{3},{1},{2},{4},{5},{6},{7},{8},{9},{10},{11}\n'
+ .format(time.time(), results['DroppedFrameCount'],
+ results['SeqRunLength'], results['RxPort'],
+ results['AvgLatency'],
+ results['DroppedFrameRate'],
+ results['FrameCount'], results['FrameRate'],
+ results['MaxLatency'], results['MinLatency'],
+ results['OctetCount'], results['OctetRate']))
+
+
+def write_tx_live_results_to_file(results_path, file_name, results):
+ """ Write live results from the tx-ports"""
+ filec = os.path.join(results_path, file_name + ".tx")
+ with open(filec, "a") as result_file:
+ result_file.write('{0},{1},{9},{2},{3},{4},{5},{6},{7},{8}\n'
+ .format(time.time(), results['StreamId'],
+ results['FrameCount'], results['FrameRate'],
+ results['ExpectedRxFrameCount'],
+ results['OctetCount'], results['OctetRate'],
+ results['BitCount'], results['BitRate'],
+ results['BlockId']))
+
+
def positive_int(value):
""" Positive Integer type for Arguments """
ivalue = int(value)
@@ -68,7 +134,8 @@ def percent_float(value):
"%s not in range [0.0, 100.0]" % pvalue)
return pvalue
-# pylint: disable=too-many-branches, too-many-statements
+
+# pylint: disable=too-many-branches, too-many-statements, too-many-locals
def main():
""" Read the arguments, Invoke Test and Return the results"""
parser = argparse.ArgumentParser()
@@ -146,6 +213,11 @@ def main():
default="./Results",
help="The directory to copy results to",
dest="results_dir")
+ optional_named.add_argument("--vsperf_results_dir",
+ required=False,
+ default="./Results",
+ help="The directory to copy results to",
+ dest="vsperf_results_dir")
optional_named.add_argument("--csv_results_file_prefix",
required=False,
default="Rfc2544Tput",
@@ -269,6 +341,27 @@ def main():
"the first emulated device interface"
"on the first west port"),
dest="west_intf_gateway_addr")
+ optional_named.add_argument("--latency_histogram",
+ required=False,
+ action="store_true",
+ help="latency histogram is required in output?",
+ dest="latency_histogram")
+ optional_named.add_argument("--imix",
+ required=False,
+ default="",
+ help=("IMIX specification as genome"
+ "Encoding - RFC 6985"),
+ dest="imix")
+ optional_named.add_argument("--live_results",
+ required=False,
+ action="store_true",
+ help="Live Results required?",
+ dest="live_results")
+ optional_named.add_argument("--logfile",
+ required=False,
+ default="./traffic_gen.log",
+ help="Log file to log live results",
+ dest="logfile")
parser.add_argument("-v",
"--verbose",
required=False,
@@ -309,6 +402,7 @@ def main():
_LOGGER.debug("SpirentTestCenter system version: %s",
stc.get("system1", "version"))
+ # pylint: disable=too-many-nested-blocks
try:
device_list = []
port_list = []
@@ -325,6 +419,10 @@ def main():
_LOGGER.debug("Creating project ...")
project = stc.get("System1", "children-Project")
+ # Configure the Result view
+ resultopts = stc.get('project1', 'children-resultoptions')
+ stc.config(resultopts, {'ResultViewMode': 'BASIC'})
+
# Configure any custom traffic parameters
if args.traffic_custom == "cont":
if args.verbose:
@@ -353,7 +451,9 @@ def main():
east_chassis_port})
# Create the DeviceGenEthIIIfParams object
stc.create("DeviceGenEthIIIfParams",
- under=east_device_gen_params)
+ under=east_device_gen_params,
+ attributes={'UseDefaultPhyMac': True})
+
# Configuring Ipv4 interfaces
stc.create("DeviceGenIpv4IfParams",
under=east_device_gen_params,
@@ -374,7 +474,9 @@ def main():
west_chassis_port})
# Create the DeviceGenEthIIIfParams object
stc.create("DeviceGenEthIIIfParams",
- under=west_device_gen_params)
+ under=west_device_gen_params,
+ attributes={'UseDefaultPhyMac': True})
+
# Configuring Ipv4 interfaces
stc.create("DeviceGenIpv4IfParams",
under=west_device_gen_params,
@@ -390,6 +492,45 @@ def main():
if args.verbose:
_LOGGER.debug(device_list)
+ # Configure Histogram
+ if args.latency_histogram:
+ # Generic Configuration
+ histResOptions = stc.get("project1", 'children-ResultOptions')
+ stc.config(histResOptions, {'ResultViewMode': 'HISTOGRAM'})
+ # East Port Configuration
+ histAnaEast = stc.get(east_chassis_port, 'children-Analyzer')
+ histAnaEastConfig = stc.get(histAnaEast, 'children-AnalyzerConfig')
+ stc.config(histAnaEastConfig, {'HistogramMode': 'LATENCY'})
+ eLatHist = stc.get(histAnaEastConfig, 'children-LatencyHistogram')
+ stc.config(eLatHist, {'ConfigMode': 'CONFIG_LIMIT_MODE',
+ 'BucketSizeUnit': 'ten_nanoseconds',
+ 'Active': 'TRUE',
+ 'DistributionMode': 'CENTERED_MODE'})
+ # West Port Configuration
+ histAnaWest = stc.get(west_chassis_port, 'children-Analyzer')
+ histAnaWestConfig = stc.get(histAnaWest, 'children-AnalyzerConfig')
+ stc.config(histAnaWestConfig, {'HistogramMode': 'LATENCY'})
+ wLatHist = stc.get(histAnaWestConfig, 'children-LatencyHistogram')
+ stc.config(wLatHist, {'ConfigMode': 'CONFIG_LIMIT_MODE',
+ 'BucketSizeUnit': 'ten_nanoseconds',
+ 'Active': 'TRUE',
+ 'DistributionMode': 'CENTERED_MODE'})
+ gBucketSizeList = stc.get(wLatHist, 'BucketSizeList')
+ # gLimitSizeList = stc.get(wLatHist, 'LimitList')
+
+ # IMIX configuration
+ fld = None
+ if args.imix:
+ args.frame_size_list = []
+ weights = genome2weights(args.imix)
+ fld = stc.create('FrameLengthDistribution', under=project)
+ def_slots = stc.get(fld, "children-framelengthdistributionslot")
+ stc.perform("Delete", params={"ConfigList": def_slots})
+ for fsize in weights:
+ stc.create('framelengthdistributionslot', under=fld,
+ attributes={'FixedFrameLength': fsize,
+ 'Weight': weights[fsize]})
+
# Create the RFC 2544 'metric test
if args.metric == "throughput":
if args.verbose:
@@ -407,7 +548,8 @@ def main():
"RateUpperLimit": args.rate_upper_limit_pct,
"Resolution": args.resolution_pct,
"SearchMode": args.search_mode,
- "TrafficPattern": args.traffic_pattern})
+ "TrafficPattern": args.traffic_pattern,
+ "FrameSizeDistributionList": fld})
elif args.metric == "backtoback":
stc.perform("Rfc2544SetupBackToBackTestCommand",
params={"AcceptableFrameLoss":
@@ -467,24 +609,133 @@ def main():
_LOGGER.debug("Apply configuration...")
stc.apply()
+ # Register for the results
+ hResDataRx = stc.create('ResultDataSet', under='project1')
+ strmBlockList = stc.get('project1', 'children-streamblock')
+ stc.create('ResultQuery', under=hResDataRx, attributes={
+ 'ResultRootList': strmBlockList,
+ 'ConfigClassId': 'StreamBlock',
+ 'ResultClassId': 'RxStreamSummaryResults',
+ 'PropertyIdArray': "RxStreamSummaryResults.RxPort \
+ RxStreamSummaryResults.AvgLatency \
+ RxStreamSummaryResults.BitCount \
+ RxStreamSummaryResults.BitRate \
+ RxStreamSummaryResults.DroppedFrameCount\
+ RxStreamSummaryResults.DroppedFrameRate \
+ RxStreamSummaryResults.FrameCount \
+ RxStreamSummaryResults.FrameRate \
+ RxStreamSummaryResults.MaxLatency \
+ RxStreamSummaryResults.MinLatency \
+ RxStreamSummaryResults.OctetCount \
+ RxStreamSummaryResults.OctetRate \
+ RxStreamSummaryResults.SeqRunLength"})
+ hResDataTx = stc.create('ResultDataSet', under='project1')
+ strmBlockList = stc.get('project1', 'children-streamblock')
+ stc.create('ResultQuery', under=hResDataTx, attributes={
+ 'ResultRootList': strmBlockList,
+ 'ConfigClassId': 'StreamBlock',
+ 'ResultClassId': 'TxStreamResults',
+ 'PropertyIdArray': "TxStreamResults.BlockId \
+ TxStreamResults.BitCount \
+ TxStreamResults.BitRate \
+ TxStreamResults.FrameCount \
+ TxStreamResults.FrameRate \
+ TxStreamResults.OctetCount \
+ TxStreamResults.OctetRate"})
+ stc.perform('ResultDataSetSubscribe', params={'ResultDataSet': hResDataRx})
+ stc.perform('ResultDataSetSubscribe', params={'ResultDataSet': hResDataTx})
+ time.sleep(3)
+ stc.perform('RefreshResultView', params={'ResultDataSet': hResDataTx})
+ hndListRx = stc.get(hResDataRx, 'ResultHandleList')
+ hndListTx = stc.get(hResDataTx, 'ResultHandleList')
+
if args.verbose:
_LOGGER.debug("Starting the sequencer...")
stc.perform("SequencerStart")
- # Wait for sequencer to finish
- _LOGGER.info(
- "Starting test... Please wait for the test to complete...")
- stc.wait_until_complete()
+ sequencer = stc.get("system1", "children-sequencer")
+ state = stc.get(sequencer, 'State')
+
+ # If Live-results are required, we don't wait for the test to complete
+ if args.live_results:
+ write_headers(args.vsperf_results_dir, args.logfile, '.rx')
+ write_headers(args.vsperf_results_dir, args.logfile, '.tx')
+ while state != 'IDLE':
+ state = stc.get(sequencer, 'State')
+ hndListTx = stc.get(hResDataTx, 'ResultHandleList')
+ if hndListTx:
+ handles = hndListTx.split(' ')
+ for handle in handles:
+ tx_values = stc.get(handle)
+ write_tx_live_results_to_file(args.vsperf_results_dir,
+ args.logfile,
+ tx_values)
+ if hndListRx:
+ handles = hndListRx.split(' ')
+ for handle in handles:
+ rx_values = stc.get(handle)
+ write_rx_live_results_to_file(args.vsperf_results_dir,
+ args.logfile,
+ rx_values)
+ time.sleep(1)
+ # Live results not needed, so just wait!
+ else:
+ # Wait for sequencer to finish
+ _LOGGER.info(
+ "Starting test... Please wait for the test to complete...")
+ stc.wait_until_complete()
+
_LOGGER.info("The test has completed... Saving results...")
# Determine what the results database filename is...
lab_server_resultsdb = stc.get(
"system1.project.TestResultSetting", "CurrentResultFileName")
+ if not lab_server_resultsdb or 'Results' not in lab_server_resultsdb:
+ _LOGGER.info("Failed to find results.")
+ stc.end_session()
+ return
+
if args.verbose:
_LOGGER.debug("The lab server results database is %s",
lab_server_resultsdb)
+ # Create Latency Histogram CSV file()
+ if args.latency_histogram:
+ hist_dict_counts = {}
+ for file_url in stc.files():
+ if '-FrameSize-' in file_url:
+ stc.download(file_url)
+ filename = file_url.split('/')[-1]
+ if os.path.exists(os.getcwd() + '/' + filename):
+ conn = sqlite3.connect(os.getcwd() + '/' + filename)
+ # cursor = conn.execute(
+ # 'select * from RxEotStreamResults')
+ # names = [desc[0] for desc in cursor.description]
+ counts = conn.execute("SELECT \
+ HistBin1Count, HistBin2Count,\
+ HistBin3Count, HistBin4Count,\
+ HistBin5Count, HistBin6Count,\
+ HistBin7Count, HistBin8Count,\
+ HistBin9Count, HistBin10Count,\
+ HistBin11Count, HistBin12Count,\
+ HistBin13Count, HistBin14Count, \
+ HistBin15Count, HistBin16Count \
+ from RxEotStreamResults")
+ strs = filename.split('-')
+ key = strs[strs.index('FrameSize')+1]
+ if key in hist_dict_counts:
+ hist_dict_counts[key] = [a+b for a, b in
+ zip(counts.fetchone(),
+ hist_dict_counts[key])]
+ else:
+ hist_dict_counts[key] = counts.fetchone()
+ conn.close()
+
+ write_histogram_to_csv(args.vsperf_results_dir, 'Histogram',
+ hist_dict_counts,
+ gBucketSizeList)
+
stc.perform("CSSynchronizeFiles",
params={"DefaultDownloadDir": args.results_dir})
@@ -565,6 +816,7 @@ def main():
args.results_dir, args.csv_results_file_prefix, resultsdict)
except RuntimeError as e:
+ stc.end_session()
_LOGGER.error(e)
if args.verbose:
diff --git a/tools/pkt_gen/testcenter/testcenter.py b/tools/pkt_gen/testcenter/testcenter.py
index 487566bf..a15c502c 100644
--- a/tools/pkt_gen/testcenter/testcenter.py
+++ b/tools/pkt_gen/testcenter/testcenter.py
@@ -98,7 +98,9 @@ def get_rfc2544_common_settings():
"--trial_duration_sec",
settings.getValue("TRAFFICGEN_STC_TRIAL_DURATION_SEC"),
"--traffic_pattern",
- settings.getValue("TRAFFICGEN_STC_TRAFFIC_PATTERN")]
+ settings.getValue("TRAFFICGEN_STC_TRAFFIC_PATTERN"),
+ "--vsperf_results_dir",
+ settings.getValue("RESULTS_PATH")]
return args
@@ -169,6 +171,7 @@ class TestCenter(trafficgen.ITrafficGenerator):
Spirent TestCenter
"""
_logger = logging.getLogger(__name__)
+ _liveresults_file = settings.getValue("TRAFFICGEN_STC_LIVERESULTS_FILE")
def connect(self):
"""
@@ -330,11 +333,13 @@ class TestCenter(trafficgen.ITrafficGenerator):
return self.get_rfc2889_addr_learning_results(filec)
- def get_rfc2544_results(self, filename):
+ def get_rfc2544_results(self, filename, genome=None):
"""
Reads the CSV file and return the results
"""
result = {}
+ if not os.path.exists(filename):
+ return result
with open(filename, "r") as csvfile:
csvreader = csv.DictReader(csvfile)
for row in csvreader:
@@ -365,6 +370,10 @@ class TestCenter(trafficgen.ITrafficGenerator):
row["AverageLatency(us)"]) * 1000
result[ResultsConstants.FRAME_LOSS_PERCENT] = float(
row["PercentLoss"])
+ if genome:
+ result[ResultsConstants.IMIX_GENOME] = genome
+ result[ResultsConstants.IMIX_AVG_FRAMESIZE] = float(
+ row["AvgFrameSize"])
return result
def send_cont_traffic(self, traffic=None, duration=30):
@@ -419,6 +428,24 @@ class TestCenter(trafficgen.ITrafficGenerator):
tests)
args = rfc2544_common_args + stc_common_args + rfc2544_custom_args
+ if traffic and 'latency_histogram' in traffic:
+ if traffic['latency_histogram']['enabled']:
+ if traffic['latency_histogram']['type'] == 'Default':
+ args.append("--latency_histogram")
+
+ genome = ''
+ if traffic and 'imix' in traffic:
+ if traffic['imix']['enabled']:
+ if traffic['imix']['type'] == 'genome':
+ genome = traffic['imix']['genome']
+ args.append('--imix')
+ args.append(genome)
+
+ if settings.getValue("TRAFFICGEN_STC_LIVE_RESULTS") == "True":
+ args.append('--live_results')
+ args.append('--logfile')
+ args.append(self._liveresults_file)
+
if settings.getValue("TRAFFICGEN_STC_VERBOSE") == "True":
args.append("--verbose")
verbose = True
@@ -433,7 +460,7 @@ class TestCenter(trafficgen.ITrafficGenerator):
if verbose:
self._logger.info("file: %s", filec)
- return self.get_rfc2544_results(filec)
+ return self.get_rfc2544_results(filec, genome)
def send_rfc2544_back2back(self, traffic=None, tests=1, duration=20,
lossrate=0.0):
diff --git a/tools/pkt_gen/trex/trex.py b/tools/pkt_gen/trex/trex_client.py
index 94b793d6..3d6836d8 100644
--- a/tools/pkt_gen/trex/trex.py
+++ b/tools/pkt_gen/trex/trex_client.py
@@ -26,7 +26,7 @@ import re
from collections import OrderedDict
# pylint: disable=unused-import
import netaddr
-import zmq
+#import zmq
from conf import settings
from conf import merge_spec
from core.results.results_constants import ResultsConstants
@@ -35,7 +35,7 @@ try:
# pylint: disable=wrong-import-position, import-error
sys.path.append(settings.getValue('PATHS')['trafficgen']['Trex']['src']['path'])
from trex_stl_lib.api import *
- from trex_stl_lib import trex_stl_exceptions
+ # from trex_stl_lib import trex_stl_exceptions
except ImportError:
# VSPERF performs detection of T-Rex api during testcase initialization. So if
# T-Rex is requsted and API is not available it will fail before this code
@@ -160,7 +160,7 @@ class Trex(ITrafficGenerator):
try:
self._stlclient = STLClient(username=self._trex_user, server=self._trex_host_ip_addr,
- verbose_level=0)
+ verbose_level='info')
self._stlclient.connect()
except STLError:
raise RuntimeError('T-Rex: Cannot connect to T-Rex server. Please check if it is '
@@ -351,6 +351,8 @@ class Trex(ITrafficGenerator):
return (stream_1, stream_2, stream_1_lat, stream_2_lat)
+
+ # pylint: disable=too-many-locals, too-many-statements
def generate_traffic(self, traffic, duration, disable_capture=False):
"""The method that generate a stream
"""
@@ -414,7 +416,70 @@ class Trex(ITrafficGenerator):
core_mask=self._stlclient.CORE_MASK_PIN)
except STLError:
self._stlclient.start(ports=my_ports, force=True, duration=duration, mult="{}gbps".format(gbps_speed))
- self._stlclient.wait_on_traffic(ports=my_ports)
+
+ if settings.getValue('TRAFFICGEN_TREX_LIVE_RESULTS'):
+ filec = os.path.join(settings.getValue('RESULTS_PATH'),
+ settings.getValue('TRAFFICGEN_TREX_LC_FILE'))
+ filee = os.path.join(settings.getValue('RESULTS_PATH'),
+ settings.getValue('TRAFFICGEN_TREX_LE_FILE'))
+ pgids = self._stlclient.get_active_pgids()
+ rx_port_0 = 1
+ tx_port_0 = 0
+ rx_port_1 = 0
+ tx_port_1 = 1
+ with open(filec, 'a') as fcp, open(filee, 'a') as fep:
+ fcp.write("ts,rx_port,tx_port,rx_pkts,tx_pkts,rx_pps,tx_pps,"+
+ "rx_bps_num,rx_bps_den,tx_bps_num,tx_bps_den\n")
+ fep.write('ts,dropped,ooo,dup,seq_too_high,seq_too_low\n')
+ while True:
+ tr_status = self._stlclient.is_traffic_active(ports=my_ports)
+ if not tr_status:
+ break
+ time.sleep(1)
+ stats = self._stlclient.get_pgid_stats(pgids['flow_stats'])
+ lat_stats = stats['latency'].get(0)
+ flow_stats_0 = stats['flow_stats'].get(0)
+ flow_stats_1 = stats['flow_stats'].get(1)
+ if flow_stats_0:
+ rx_pkts = flow_stats_0['rx_pkts'][rx_port_0]
+ tx_pkts = flow_stats_0['tx_pkts'][tx_port_0]
+ rx_pps = flow_stats_0['rx_pps'][rx_port_0]
+ tx_pps = flow_stats_0['tx_pps'][tx_port_0]
+ rx_bps = flow_stats_0['rx_bps'][rx_port_0]
+ tx_bps = flow_stats_0['tx_bps'][tx_port_0]
+ rx_bps_l1 = flow_stats_0['rx_bps_l1'][rx_port_0]
+ tx_bps_l1 = flow_stats_0['tx_bps_l1'][tx_port_0]
+ # https://github.com/cisco-system-traffic-generator/\
+ # trex-core/blob/master/scripts/automation/\
+ # trex_control_plane/interactive/trex/examples/\
+ # stl/stl_flow_latency_stats.py
+ fcp.write("{10},{8},{9},{0},{1},{2},{3},{4},{5},{6},{7}\n"
+ .format(rx_pkts, tx_pkts, rx_pps, tx_pps,
+ rx_bps, rx_bps_l1, tx_bps, tx_bps_l1,
+ rx_port_0, tx_port_0, time.time()))
+ if flow_stats_1:
+ rx_pkts = flow_stats_1['rx_pkts'][rx_port_1]
+ tx_pkts = flow_stats_1['tx_pkts'][tx_port_1]
+ rx_pps = flow_stats_1['rx_pps'][rx_port_1]
+ tx_pps = flow_stats_1['tx_pps'][tx_port_1]
+ rx_bps = flow_stats_1['rx_bps'][rx_port_1]
+ tx_bps = flow_stats_1['tx_bps'][tx_port_1]
+ rx_bps_l1 = flow_stats_1['rx_bps_l1'][rx_port_1]
+ tx_bps_l1 = flow_stats_1['tx_bps_l1'][tx_port_1]
+ fcp.write("{10},{8},{9},{0},{1},{2},{3},{4},{5},{6},{7}\n"
+ .format(rx_pkts, tx_pkts, rx_pps, tx_pps,
+ rx_bps, rx_bps_l1, tx_bps, tx_bps_l1,
+ rx_port_1, tx_port_1, time.time()))
+ if lat_stats:
+ drops = lat_stats['err_cntrs']['dropped']
+ ooo = lat_stats['err_cntrs']['out_of_order']
+ dup = lat_stats['err_cntrs']['dup']
+ sth = lat_stats['err_cntrs']['seq_too_high']
+ stl = lat_stats['err_cntrs']['seq_too_low']
+ fep.write('{5},{0},{1},{2},{3},{4}\n'
+ .format(drops, ooo, dup, sth, stl, time.time()))
+ else:
+ self._stlclient.wait_on_traffic(ports=my_ports)
stats = self._stlclient.get_stats(sync_now=True)
# export captured data into pcap file if possible
@@ -529,9 +594,14 @@ class Trex(ITrafficGenerator):
:return: passing stats as dictionary
"""
threshold = settings.getValue('TRAFFICGEN_TREX_RFC2544_TPUT_THRESHOLD')
+ max_repeat = settings.getValue('TRAFFICGEN_TREX_RFC2544_MAX_REPEAT')
+ loss_verification = settings.getValue('TRAFFICGEN_TREX_RFC2544_BINARY_SEARCH_LOSS_VERIFICATION')
+ if loss_verification:
+ self._logger.info("Running Binary Search with Loss Verification")
stats_ok = _EMPTY_STATS
new_params = copy.deepcopy(traffic)
iteration = 1
+ repeat = 0
left = boundaries['left']
right = boundaries['right']
center = boundaries['center']
@@ -555,11 +625,20 @@ class Trex(ITrafficGenerator):
if test_lossrate == 0.0 and new_params['frame_rate'] == traffic['frame_rate']:
return copy.deepcopy(stats)
elif test_lossrate > lossrate:
+ if loss_verification:
+ if repeat < max_repeat:
+ repeat += 1
+ iteration += 1
+ continue
+ else:
+ repeat = 0
right = center
center = (left + right) / 2
new_params = copy.deepcopy(traffic)
new_params['frame_rate'] = center
else:
+ if loss_verification:
+ repeat = 0
stats_ok = copy.deepcopy(stats)
left = center
center = (left + right) / 2