Merge "Spirent-TestCenter: Code Cleanup."
[vswitchperf.git] / tools / pkt_gen / testcenter / testcenter.py
1 # Copyright 2016 Spirent Communications.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #   http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 """
16 Code to integrate Spirent TestCenter with the vsperf test framework.
17
18 Provides a model for Spirent TestCenter as a test tool for implementing
19 various performance tests of a virtual switch.
20 """
21
22 import csv
23 import logging
24 import os
25 import subprocess
26
27 from conf import settings
28 from core.results.results_constants import ResultsConstants
29 from tools.pkt_gen import trafficgen
30
31
32 def get_stc_common_settings():
33     """
34     Return the common Settings
35     These settings would apply to almost all the tests.
36     """
37     args = ["--lab_server_addr",
38             settings.getValue("TRAFFICGEN_STC_LAB_SERVER_ADDR"),
39             "--license_server_addr",
40             settings.getValue("TRAFFICGEN_STC_LICENSE_SERVER_ADDR"),
41             "--east_chassis_addr",
42             settings.getValue("TRAFFICGEN_STC_EAST_CHASSIS_ADDR"),
43             "--east_slot_num",
44             settings.getValue("TRAFFICGEN_STC_EAST_SLOT_NUM"),
45             "--east_port_num",
46             settings.getValue("TRAFFICGEN_STC_EAST_PORT_NUM"),
47             "--west_chassis_addr",
48             settings.getValue("TRAFFICGEN_STC_WEST_CHASSIS_ADDR"),
49             "--west_slot_num",
50             settings.getValue("TRAFFICGEN_STC_WEST_SLOT_NUM"),
51             "--west_port_num",
52             settings.getValue("TRAFFICGEN_STC_WEST_PORT_NUM"),
53             "--test_session_name",
54             settings.getValue("TRAFFICGEN_STC_TEST_SESSION_NAME"),
55             "--results_dir",
56             settings.getValue("TRAFFICGEN_STC_RESULTS_DIR"),
57             "--csv_results_file_prefix",
58             settings.getValue("TRAFFICGEN_STC_CSV_RESULTS_FILE_PREFIX")]
59     return args
60
61
62 def get_rfc2544_common_settings():
63     """
64     Retrun Generic RFC 2544 settings.
65     These settings apply to all the 2544 tests
66     """
67     args = [settings.getValue("TRAFFICGEN_STC_PYTHON2_PATH"),
68             os.path.join(
69                 settings.getValue("TRAFFICGEN_STC_TESTCENTER_PATH"),
70                 settings.getValue(
71                     "TRAFFICGEN_STC_RFC2544_TPUT_TEST_FILE_NAME")),
72             "--metric",
73             settings.getValue("TRAFFICGEN_STC_RFC2544_METRIC"),
74             "--search_mode",
75             settings.getValue("TRAFFICGEN_STC_SEARCH_MODE"),
76             "--learning_mode",
77             settings.getValue("TRAFFICGEN_STC_LEARNING_MODE"),
78             "--rate_lower_limit_pct",
79             settings.getValue("TRAFFICGEN_STC_RATE_LOWER_LIMIT_PCT"),
80             "--rate_upper_limit_pct",
81             settings.getValue("TRAFFICGEN_STC_RATE_UPPER_LIMIT_PCT"),
82             "--rate_initial_pct",
83             settings.getValue("TRAFFICGEN_STC_RATE_INITIAL_PCT"),
84             "--rate_step_pct",
85             settings.getValue("TRAFFICGEN_STC_RATE_STEP_PCT"),
86             "--resolution_pct",
87             settings.getValue("TRAFFICGEN_STC_RESOLUTION_PCT"),
88             "--acceptable_frame_loss_pct",
89             settings.getValue("TRAFFICGEN_STC_ACCEPTABLE_FRAME_LOSS_PCT"),
90             "--east_intf_addr",
91             settings.getValue("TRAFFICGEN_STC_EAST_INTF_ADDR"),
92             "--east_intf_gateway_addr",
93             settings.getValue("TRAFFICGEN_STC_EAST_INTF_GATEWAY_ADDR"),
94             "--west_intf_addr",
95             settings.getValue("TRAFFICGEN_STC_WEST_INTF_ADDR"),
96             "--west_intf_gateway_addr",
97             settings.getValue("TRAFFICGEN_STC_WEST_INTF_GATEWAY_ADDR"),
98             "--num_trials",
99             settings.getValue("TRAFFICGEN_STC_NUMBER_OF_TRIALS"),
100             "--trial_duration_sec",
101             settings.getValue("TRAFFICGEN_STC_TRIAL_DURATION_SEC"),
102             "--traffic_pattern",
103             settings.getValue("TRAFFICGEN_STC_TRAFFIC_PATTERN")]
104     return args
105
106
107 def get_rfc2544_custom_settings(framesize, custom_tr):
108     """
109     Return RFC2544 Custom Settings
110     """
111     args = ["--frame_size_list",
112             str(framesize),
113             "--traffic_custom",
114             str(custom_tr)]
115     return args
116
117
118 class TestCenter(trafficgen.ITrafficGenerator):
119     """
120     Spirent TestCenter
121     """
122     _logger = logging.getLogger(__name__)
123
124     def connect(self):
125         """
126         Do nothing.
127         """
128         return self
129
130     def disconnect(self):
131         """
132         Do nothing.
133         """
134         pass
135
136     def send_burst_traffic(self, traffic=None, numpkts=100, duration=20):
137         """
138         Do nothing.
139         """
140         return None
141
142     def get_rfc2544_results(self, filename):
143         """
144         Reads the CSV file and return the results
145         """
146         result = {}
147         with open(filename, "r") as csvfile:
148             csvreader = csv.DictReader(csvfile)
149             for row in csvreader:
150                 self._logger.info("Row: %s", row)
151                 tx_fps = ((float(row["TxFrameCount"])) /
152                           (float(row["Duration(sec)"])))
153                 rx_fps = ((float(row["RxFrameCount"])) /
154                           (float(row["Duration(sec)"])))
155                 tx_mbps = ((float(row["TxFrameCount"]) *
156                             float(row["ConfiguredFrameSize"])) /
157                            (float(row["Duration(sec)"]) * 1000000.0))
158                 rx_mbps = ((float(row["RxFrameCount"]) *
159                             float(row["ConfiguredFrameSize"])) /
160                            (float(row["Duration(sec)"]) * 1000000.0))
161                 result[ResultsConstants.TX_RATE_FPS] = tx_fps
162                 result[ResultsConstants.THROUGHPUT_RX_FPS] = rx_fps
163                 result[ResultsConstants.TX_RATE_MBPS] = tx_mbps
164                 result[ResultsConstants.THROUGHPUT_RX_MBPS] = rx_mbps
165                 result[ResultsConstants.TX_RATE_PERCENT] = float(
166                     row["OfferedLoad(%)"])
167                 result[ResultsConstants.THROUGHPUT_RX_PERCENT] = float(
168                     row["Throughput(%)"])
169                 result[ResultsConstants.MIN_LATENCY_NS] = float(
170                     row["MinimumLatency(us)"]) * 1000
171                 result[ResultsConstants.MAX_LATENCY_NS] = float(
172                     row["MaximumLatency(us)"]) * 1000
173                 result[ResultsConstants.AVG_LATENCY_NS] = float(
174                     row["AverageLatency(us)"]) * 1000
175                 result[ResultsConstants.FRAME_LOSS_PERCENT] = float(
176                     row["PercentLoss"])
177         return result
178
179     def send_cont_traffic(self, traffic=None, duration=30):
180         """
181         Send Custom - Continuous Test traffic
182         Reuse RFC2544 throughput test specifications along with
183         'custom' configuration
184         """
185         verbose = False
186         custom = "cont"
187         framesize = settings.getValue("TRAFFICGEN_STC_FRAME_SIZE")
188         if traffic and 'l2' in traffic:
189             if 'framesize' in traffic['l2']:
190                 framesize = traffic['l2']['framesize']
191
192         stc_common_args = get_stc_common_settings()
193         rfc2544_common_args = get_rfc2544_common_settings()
194         rfc2544_custom_args = get_rfc2544_custom_settings(framesize,
195                                                           custom)
196         args = stc_common_args + rfc2544_common_args + rfc2544_custom_args
197
198         if settings.getValue("TRAFFICGEN_STC_VERBOSE") is "True":
199             args.append("--verbose")
200             verbose = True
201             self._logger.debug("Arguments used to call test: %s", args)
202         subprocess.check_call(args)
203
204         filec = os.path.join(settings.getValue("TRAFFICGEN_STC_RESULTS_DIR"),
205                              settings.getValue(
206                                  "TRAFFICGEN_STC_CSV_RESULTS_FILE_PREFIX") +
207                              ".csv")
208
209         if verbose:
210             self._logger.info("file: %s", filec)
211
212         return self.get_rfc2544_results(filec)
213
214     def send_rfc2544_throughput(self, traffic=None, trials=3, duration=20,
215                                 lossrate=0.0):
216         """
217         Send traffic per RFC2544 throughput test specifications.
218         """
219         verbose = False
220         framesize = settings.getValue("TRAFFICGEN_STC_FRAME_SIZE")
221         if traffic and 'l2' in traffic:
222             if 'framesize' in traffic['l2']:
223                 framesize = traffic['l2']['framesize']
224
225         stc_common_args = get_stc_common_settings()
226         rfc2544_common_args = get_rfc2544_common_settings()
227         rfc2544_custom_args = get_rfc2544_custom_settings(framesize, '')
228         args = stc_common_args + rfc2544_common_args + rfc2544_custom_args
229
230         if settings.getValue("TRAFFICGEN_STC_VERBOSE") is "True":
231             args.append("--verbose")
232             verbose = True
233             self._logger.debug("Arguments used to call test: %s", args)
234         subprocess.check_call(args)
235
236         filec = os.path.join(settings.getValue("TRAFFICGEN_STC_RESULTS_DIR"),
237                              settings.getValue(
238                                  "TRAFFICGEN_STC_CSV_RESULTS_FILE_PREFIX") +
239                              ".csv")
240
241         if verbose:
242             self._logger.info("file: %s", filec)
243
244         return self.get_rfc2544_results(filec)
245
246     def send_rfc2544_back2back(self, traffic=None, trials=1, duration=20,
247                                lossrate=0.0):
248         """
249         Send traffic per RFC2544 BacktoBack test specifications.
250         """
251         verbose = False
252         framesize = settings.getValue("TRAFFICGEN_STC_FRAME_SIZE")
253         if traffic and 'l2' in traffic:
254             if 'framesize' in traffic['l2']:
255                 framesize = traffic['l2']['framesize']
256
257         stc_common_args = get_stc_common_settings()
258         rfc2544_common_args = get_rfc2544_common_settings()
259         rfc2544_custom_args = get_rfc2544_custom_settings(framesize, '')
260         args = stc_common_args + rfc2544_common_args + rfc2544_custom_args
261
262         if settings.getValue("TRAFFICGEN_STC_VERBOSE") is "True":
263             args.append("--verbose")
264             verbose = True
265             self._logger.info("Arguments used to call test: %s", args)
266         subprocess.check_call(args)
267
268         filecs = os.path.join(settings.getValue("TRAFFICGEN_STC_RESULTS_DIR"),
269                               settings.getValue(
270                                   "TRAFFICGEN_STC_CSV_RESULTS_FILE_PREFIX") +
271                               ".csv")
272         if verbose:
273             self._logger.debug("file: %s", filecs)
274
275         return self.get_rfc2544_results(filecs)
276
277 if __name__ == '__main__':
278     TRAFFIC = {
279         'l3': {
280             'proto': 'tcp',
281             'srcip': '1.1.1.1',
282             'dstip': '90.90.90.90',
283         },
284     }
285     with TestCenter() as dev:
286         print(dev.send_rfc2544_throughput(traffic=TRAFFIC))
287         print(dev.send_rfc2544_backtoback(traffic=TRAFFIC))