Merge "test_spec: LTD: MatchAction Performance testing"
[vswitchperf.git] / tools / pkt_gen / ixnet / ixnet.py
index fdea4bf..5e4ae56 100755 (executable)
@@ -1,4 +1,4 @@
-# Copyright 2015 Intel Corporation.
+# Copyright 2015-2016 Intel Corporation.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -19,8 +19,6 @@ This requires the following settings in your config file:
 
 * TRAFFICGEN_IXNET_LIB_PATH
     IxNetwork libraries path
-* TRAFFICGEN_IXNET_HOST
-    IxNetwork host IP address
 * TRAFFICGEN_IXNET_PORT
     IxNetwork host port number
 * TRAFFICGEN_IXNET_USER
@@ -32,7 +30,7 @@ This requires the following settings in your config file:
     as the previous one
 
 The following settings are also required. These can likely be shared
-an 'Ixia' traffic generator instance:
+with an 'Ixia' traffic generator instance:
 
 * TRAFFICGEN_IXIA_HOST
     IXIA chassis IP address
@@ -95,7 +93,7 @@ from core.results.results_constants import ResultsConstants
 _ROOT_DIR = os.path.dirname(os.path.realpath(__file__))
 
 _RESULT_RE = r'(?:\{kString,result\},\{kString,)(\w+)(?:\})'
-_RESULTPATH_RE = r'(?:\{kString,resultPath\},\{kString,)([\\\w\.\-]+)(?:\})'
+_RESULTPATH_RE = r'(?:\{kString,resultPath\},\{kString,)([\\\w\.\-\:]+)(?:\})'
 
 
 def _build_set_cmds(values, prefix='dict set'):
@@ -153,11 +151,16 @@ class IxNet(trafficgen.ITrafficGenerator):
 
     Currently only the RFC2544 tests are implemented.
     """
-    _script = os.path.join(os.path.dirname(__file__), 'ixnetrfc2544.tcl')
+    if settings.getValue('TRAFFICGEN_IXNET_TCL_SCRIPT') == '':
+        _script = os.path.join(os.path.dirname(__file__), 'ixnetrfc2544.tcl')
+    else:
+        _script = os.path.join(os.path.dirname(__file__),
+                               settings.getValue('TRAFFICGEN_IXNET_TCL_SCRIPT'))
     _tclsh = tkinter.Tcl()
     _cfg = None
     _logger = logging.getLogger(__name__)
     _params = None
+    _bidir = None
 
     def run_tcl(self, cmd):
         """Run a TCL script using the TCL interpreter found in ``tkinter``.
@@ -186,8 +189,8 @@ class IxNet(trafficgen.ITrafficGenerator):
             'card': settings.getValue('TRAFFICGEN_IXIA_CARD'),
             'port1': settings.getValue('TRAFFICGEN_IXIA_PORT1'),
             'port2': settings.getValue('TRAFFICGEN_IXIA_PORT2'),
-            'output_dir': settings.getValue(
-                          'TRAFFICGEN_IXNET_TESTER_RESULT_DIR'),
+            'output_dir':
+                settings.getValue('TRAFFICGEN_IXNET_TESTER_RESULT_DIR'),
         }
 
         self._logger.debug('IXIA configuration configuration : %s', self._cfg)
@@ -199,25 +202,25 @@ class IxNet(trafficgen.ITrafficGenerator):
         """
         pass
 
-    def send_cont_traffic(self, traffic=None, time=20, framerate=0,
-                          multistream=False):
+    def send_cont_traffic(self, traffic=None, duration=30):
         """See ITrafficGenerator for description
         """
-        self.start_cont_traffic(traffic, time, framerate, multistream)
+        self.start_cont_traffic(traffic, duration)
 
         return self.stop_cont_traffic()
 
-    def start_cont_traffic(self, traffic=None, time=20, framerate=0,
-                           multistream=False):
+    def start_cont_traffic(self, traffic=None, duration=30):
         """Start transmission.
         """
+        self._bidir = traffic['bidir']
         self._params = {}
 
         self._params['config'] = {
             'binary': False,  # don't do binary search and send one stream
-            'time': time,
-            'framerate': framerate,
-            'multipleStreams': multistream,
+            'duration': duration,
+            'framerate': traffic['frame_rate'],
+            'multipleStreams': traffic['multistream'],
+            'streamType': traffic['stream_type'],
             'rfc2544TestType': 'throughput',
         }
         self._params['traffic'] = self.traffic_defaults.copy()
@@ -225,6 +228,7 @@ class IxNet(trafficgen.ITrafficGenerator):
         if traffic:
             self._params['traffic'] = trafficgen.merge_spec(
                 self._params['traffic'], traffic)
+        self._cfg['bidir'] = self._bidir
 
         for cmd in _build_set_cmds(self._cfg, prefix='set'):
             self.run_tcl(cmd)
@@ -249,27 +253,28 @@ class IxNet(trafficgen.ITrafficGenerator):
         """
         return self._wait_result()
 
-    def send_rfc2544_throughput(self, traffic=None, trials=3, duration=20,
-                                lossrate=0.0, multistream=False):
+    def send_rfc2544_throughput(self, traffic=None, tests=1, duration=20,
+                                lossrate=0.0):
         """See ITrafficGenerator for description
         """
-        self.start_rfc2544_throughput(traffic, trials, duration, lossrate,
-                                      multistream)
+        self.start_rfc2544_throughput(traffic, tests, duration, lossrate)
 
         return self.wait_rfc2544_throughput()
 
-    def start_rfc2544_throughput(self, traffic=None, trials=3, duration=20,
-                                 lossrate=0.0, multistream=False):
+    def start_rfc2544_throughput(self, traffic=None, tests=1, duration=20,
+                                 lossrate=0.0):
         """Start transmission.
         """
+        self._bidir = traffic['bidir']
         self._params = {}
 
         self._params['config'] = {
             'binary': True,
-            'trials': trials,
+            'tests': tests,
             'duration': duration,
             'lossrate': lossrate,
-            'multipleStreams': multistream,
+            'multipleStreams': traffic['multistream'],
+            'streamType': traffic['stream_type'],
             'rfc2544TestType': 'throughput',
         }
         self._params['traffic'] = self.traffic_defaults.copy()
@@ -277,6 +282,7 @@ class IxNet(trafficgen.ITrafficGenerator):
         if traffic:
             self._params['traffic'] = trafficgen.merge_spec(
                 self._params['traffic'], traffic)
+        self._cfg['bidir'] = self._bidir
 
         for cmd in _build_set_cmds(self._cfg, prefix='set'):
             self.run_tcl(cmd)
@@ -329,7 +335,7 @@ class IxNet(trafficgen.ITrafficGenerator):
             # transform path into someting useful
 
             path = result_path.group(1).replace('\\', '/')
-            path = os.path.join(path, 'results.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'))
@@ -348,27 +354,29 @@ class IxNet(trafficgen.ITrafficGenerator):
                 for row in reader:
                     #Replace null entries added by Ixia with 0s.
                     row = [entry if len(entry) > 0 else '0' for entry in row]
-                    # calculate tx fps by (rx fps * (tx % / rx %))
-                    tx_fps = float(row[9]) * (float(row[8]) / float(row[7]))
-                    # calculate tx mbps by (rx mbps * (tx % / rx %))
-                    tx_mbps = float(row[10]) * (float(row[8]) / float(row[7]))
+
+                    # tx_fps and tx_mps cannot be reliably calculated
+                    # as the DUT may be modifying the frame size
+                    tx_fps = 'Unknown'
+                    tx_mbps = 'Unknown'
 
                     if bool(results.get(ResultsConstants.THROUGHPUT_RX_FPS)) \
-                                                                == False:
+                                                                is False:
                         prev_percent_rx = 0.0
                     else:
                         prev_percent_rx = \
                         float(results.get(ResultsConstants.THROUGHPUT_RX_FPS))
-                    if float(row[9]) >= prev_percent_rx:
-                        results[ResultsConstants.THROUGHPUT_TX_FPS] = tx_fps
-                        results[ResultsConstants.THROUGHPUT_RX_FPS] = row[9]
-                        results[ResultsConstants.THROUGHPUT_TX_MBPS] = tx_mbps
-                        results[ResultsConstants.THROUGHPUT_RX_MBPS] = row[10]
-                        results[ResultsConstants.THROUGHPUT_TX_PERCENT] = row[7]
-                        results[ResultsConstants.THROUGHPUT_TX_PERCENT] = row[8]
-                        results[ResultsConstants.MIN_LATENCY_NS] = row[15]
-                        results[ResultsConstants.MAX_LATENCY_NS] = row[16]
-                        results[ResultsConstants.AVG_LATENCY_NS] = row[17]
+                    if float(row[5]) >= prev_percent_rx:
+                        results[ResultsConstants.TX_RATE_FPS] = tx_fps
+                        results[ResultsConstants.THROUGHPUT_RX_FPS] = row[5]
+                        results[ResultsConstants.TX_RATE_MBPS] = tx_mbps
+                        results[ResultsConstants.THROUGHPUT_RX_MBPS] = row[6]
+                        results[ResultsConstants.TX_RATE_PERCENT] = row[3]
+                        results[ResultsConstants.THROUGHPUT_RX_PERCENT] = row[4]
+                        results[ResultsConstants.FRAME_LOSS_PERCENT] = row[10]
+                        results[ResultsConstants.MIN_LATENCY_NS] = row[11]
+                        results[ResultsConstants.MAX_LATENCY_NS] = row[12]
+                        results[ResultsConstants.AVG_LATENCY_NS] = row[13]
             return results
 
         output = self.run_tcl('waitForRfc2544Test')
@@ -379,27 +387,31 @@ class IxNet(trafficgen.ITrafficGenerator):
         # the results file
         return parse_ixnet_rfc_results(parse_result_string(output[0]))
 
-    def send_rfc2544_back2back(self, traffic=None, trials=1, duration=20,
-                               lossrate=0.0, multistream=False):
+    def send_rfc2544_back2back(self, traffic=None, tests=1, duration=2,
+                               lossrate=0.0):
         """See ITrafficGenerator for description
         """
-        self.start_rfc2544_back2back(traffic, trials, duration, lossrate,
-                                     multistream)
+        # 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()
 
-    def start_rfc2544_back2back(self, traffic=None, trials=1, duration=20,
-                                lossrate=0.0, multistream=False):
+    def start_rfc2544_back2back(self, traffic=None, tests=1, duration=2,
+                                lossrate=0.0):
         """Start transmission.
         """
+        self._bidir = traffic['bidir']
         self._params = {}
 
         self._params['config'] = {
             'binary': True,
-            'trials': trials,
+            'tests': tests,
             'duration': duration,
             'lossrate': lossrate,
-            'multipleStreams': multistream,
+            'multipleStreams': traffic['multistream'],
+            'streamType': traffic['stream_type'],
             'rfc2544TestType': 'back2back',
         }
         self._params['traffic'] = self.traffic_defaults.copy()
@@ -407,6 +419,7 @@ class IxNet(trafficgen.ITrafficGenerator):
         if traffic:
             self._params['traffic'] = trafficgen.merge_spec(
                 self._params['traffic'], traffic)
+        self._cfg['bidir'] = self._bidir
 
         for cmd in _build_set_cmds(self._cfg, prefix='set'):
             self.run_tcl(cmd)
@@ -468,7 +481,9 @@ class IxNet(trafficgen.ITrafficGenerator):
 
             :returns: Best parsed result from CSV file.
             """
-            results = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
+            results = OrderedDict()
+            results[ResultsConstants.B2B_FRAMES] = 0
+            results[ResultsConstants.B2B_FRAME_LOSS_PERCENT] = 100
 
             with open(path, 'r') as in_file:
                 reader = csv.reader(in_file, delimiter=',')
@@ -477,29 +492,21 @@ class IxNet(trafficgen.ITrafficGenerator):
                     # 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]) > int(results[5]):
-                            results = [
-                                float(row[9]),  # rx throughput (fps)
-                                float(row[10]),  # rx throughput (mbps)
-                                float(row[7]),  # tx rate (% linerate)
-                                float(row[8]),  # rx rate (% linerate)
-                                int(row[11]),  # tx count (frames)
-                                int(row[12]),  # back2back count (frames)
-                                int(row[13]),  # frame loss (frames)
-                                float(row[14]),  # frame loss (%)
-                            ]
+                        if int(row[12]) > \
+                         int(results[ResultsConstants.B2B_FRAMES]):
+                            results[ResultsConstants.B2B_FRAMES] = int(row[12])
+                            results[ResultsConstants.B2B_FRAME_LOSS_PERCENT] = float(row[14])
 
             return results
 
-        self.run_tcl('waitForRfc2544Test')
+        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
 
-        #TODO implement back2back result via IResult interface.
-        #return parse_ixnet_rfc_results(parse_result_string(output[0]))
+        return parse_ixnet_rfc_results(parse_result_string(output[0]))
 
 
 if __name__ == '__main__':