diff options
Diffstat (limited to 'tools/pkt_gen/testcenter')
-rw-r--r-- | tools/pkt_gen/testcenter/testcenter-rfc2544-rest.py | 270 | ||||
-rw-r--r-- | tools/pkt_gen/testcenter/testcenter.py | 55 |
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)) |