aboutsummaryrefslogtreecommitdiffstats
path: root/tools/pkt_gen/testcenter
diff options
context:
space:
mode:
Diffstat (limited to 'tools/pkt_gen/testcenter')
-rw-r--r--tools/pkt_gen/testcenter/testcenter-rfc2544-rest.py270
-rw-r--r--tools/pkt_gen/testcenter/testcenter.py55
2 files changed, 302 insertions, 23 deletions
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 9980ae7c..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):
"""
@@ -182,7 +185,7 @@ class TestCenter(trafficgen.ITrafficGenerator):
"""
pass
- def send_burst_traffic(self, traffic=None, numpkts=100, duration=20):
+ def send_burst_traffic(self, traffic=None, duration=20):
"""
Do nothing.
"""
@@ -246,8 +249,7 @@ class TestCenter(trafficgen.ITrafficGenerator):
row["ForwardingRate(fps)"])
return result
- # pylint: disable=unused-argument
- def send_rfc2889_forwarding(self, traffic=None, tests=1, duration=20):
+ def send_rfc2889_forwarding(self, traffic=None, tests=1, _duration=20):
"""
Send traffic per RFC2889 Forwarding test specifications.
"""
@@ -257,7 +259,7 @@ class TestCenter(trafficgen.ITrafficGenerator):
framesize = traffic['l2']['framesize']
args = get_rfc2889_common_settings(framesize, tests,
traffic['traffic_type'])
- if settings.getValue("TRAFFICGEN_STC_VERBOSE") is "True":
+ if settings.getValue("TRAFFICGEN_STC_VERBOSE") == "True":
args.append("--verbose")
verbose = True
self._logger.debug("Arguments used to call test: %s", args)
@@ -273,7 +275,7 @@ class TestCenter(trafficgen.ITrafficGenerator):
return self.get_rfc2889_forwarding_results(filec)
- def send_rfc2889_caching(self, traffic=None, tests=1, duration=20):
+ def send_rfc2889_caching(self, traffic=None, tests=1, _duration=20):
"""
Send as per RFC2889 Addr-Caching test specifications.
"""
@@ -286,7 +288,7 @@ class TestCenter(trafficgen.ITrafficGenerator):
custom_args = get_rfc2889_custom_settings()
args = common_args + custom_args
- if settings.getValue("TRAFFICGEN_STC_VERBOSE") is "True":
+ if settings.getValue("TRAFFICGEN_STC_VERBOSE") == "True":
args.append("--verbose")
verbose = True
self._logger.debug("Arguments used to call test: %s", args)
@@ -302,7 +304,7 @@ class TestCenter(trafficgen.ITrafficGenerator):
return self.get_rfc2889_addr_caching_results(filec)
- def send_rfc2889_learning(self, traffic=None, tests=1, duration=20):
+ def send_rfc2889_learning(self, traffic=None, tests=1, _duration=20):
"""
Send traffic per RFC2889 Addr-Learning test specifications.
"""
@@ -315,7 +317,7 @@ class TestCenter(trafficgen.ITrafficGenerator):
custom_args = get_rfc2889_custom_settings()
args = common_args + custom_args
- if settings.getValue("TRAFFICGEN_STC_VERBOSE") is "True":
+ if settings.getValue("TRAFFICGEN_STC_VERBOSE") == "True":
args.append("--verbose")
verbose = True
self._logger.debug("Arguments used to call test: %s", args)
@@ -331,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:
@@ -366,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):
@@ -387,7 +395,7 @@ class TestCenter(trafficgen.ITrafficGenerator):
custom, 1)
args = rfc2544_common_args + stc_common_args + rfc2544_custom_args
- if settings.getValue("TRAFFICGEN_STC_VERBOSE") is "True":
+ if settings.getValue("TRAFFICGEN_STC_VERBOSE") == "True":
args.append("--verbose")
verbose = True
self._logger.debug("Arguments used to call test: %s", args)
@@ -420,7 +428,25 @@ class TestCenter(trafficgen.ITrafficGenerator):
tests)
args = rfc2544_common_args + stc_common_args + rfc2544_custom_args
- if settings.getValue("TRAFFICGEN_STC_VERBOSE") is "True":
+ 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
self._logger.debug("Arguments used to call test: %s", args)
@@ -434,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):
@@ -453,7 +479,7 @@ class TestCenter(trafficgen.ITrafficGenerator):
tests)
args = rfc2544_common_args + stc_common_args + rfc2544_custom_args
- if settings.getValue("TRAFFICGEN_STC_VERBOSE") is "True":
+ if settings.getValue("TRAFFICGEN_STC_VERBOSE") == "True":
args.append("--verbose")
verbose = True
self._logger.info("Arguments used to call test: %s", args)
@@ -498,4 +524,5 @@ if __name__ == '__main__':
}
with TestCenter() as dev:
print(dev.send_rfc2544_throughput(traffic=TRAFFIC))
+ # pylint: disable=no-member
print(dev.send_rfc2544_backtoback(traffic=TRAFFIC))