pkt_gen: Spirent Testcenter RFC 2889 Support
[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             "--trial_duration_sec",
99             settings.getValue("TRAFFICGEN_STC_TRIAL_DURATION_SEC"),
100             "--traffic_pattern",
101             settings.getValue("TRAFFICGEN_STC_TRAFFIC_PATTERN")]
102     return args
103
104
105 def get_rfc2544_custom_settings(framesize, custom_tr, tests):
106     """
107     Return RFC2544 Custom Settings
108     """
109     args = ["--frame_size_list",
110             str(framesize),
111             "--traffic_custom",
112             str(custom_tr),
113             "--num_trials",
114             str(tests)]
115     return args
116
117
118 def get_rfc2889_settings(framesize, tests, duration):
119     args = [settings.getValue("TRAFFICGEN_STC_PYTHON2_PATH"),
120             os.path.join(
121                 settings.getValue("TRAFFICGEN_STC_TESTCENTER_PATH"),
122                 settings.getValue(
123                     "TRAFFICGEN_STC_RFC2889_TEST_FILE_NAME")),
124                 "--lab_server_addr",
125                 settings.getValue("TRAFFICGEN_STC_LAB_SERVER_ADDR"),
126                 "--license_server_addr",
127                 settings.getValue("TRAFFICGEN_STC_LICENSE_SERVER_ADDR"),
128                 "--location_list",
129                 settings.getValue("TRAFFICGEN_STC_RFC2889_LOCATIONS"),
130                 "--frame_size_list",
131                 str(framesize),
132                 "--num_trials",
133                 str(tests)]
134     return args
135
136
137 class TestCenter(trafficgen.ITrafficGenerator):
138     """
139     Spirent TestCenter
140     """
141     _logger = logging.getLogger(__name__)
142
143     def connect(self):
144         """
145         Do nothing.
146         """
147         return self
148
149     def disconnect(self):
150         """
151         Do nothing.
152         """
153         pass
154
155     def send_burst_traffic(self, traffic=None, numpkts=100, duration=20):
156         """
157         Do nothing.
158         """
159         return None
160
161     def send_rfc2889_congestion(self, traffic=None, tests=1, duration=20):
162         """
163         Do nothing.
164         """
165         return None
166
167     def send_rfc2889_caching(self, traffic=None, tests=1, duration=20):
168         """
169         Do nothing.
170         """
171         return None
172
173     def get_rfc2889_results(self, filename):
174         """
175         Reads the CSV file and return the results
176         """
177         result = {}
178         with open(filename, "r") as csvfile:
179             csvreader = csv.DictReader(csvfile)
180             for row in csvreader:
181                 self._logger.info("Row: %s", row)
182                 duration = int((float(row["TxSignatureFrameCount"])) /
183                                (float(row["OfferedLoad(fps)"])))
184                 tx_fps = (float(row["OfferedLoad(fps)"]))
185                 rx_fps = float((float(row["RxFrameCount"])) /
186                                float(duration))
187                 tx_mbps = ((tx_fps * float(row["FrameSize"])) /
188                            (1000000.0))
189                 rx_mbps = ((rx_fps * float(row["FrameSize"])) /
190                            (1000000.0))
191                 result[ResultsConstants.TX_RATE_FPS] = tx_fps
192                 result[ResultsConstants.THROUGHPUT_RX_FPS] = rx_fps
193                 result[ResultsConstants.TX_RATE_MBPS] = tx_mbps
194                 result[ResultsConstants.THROUGHPUT_RX_MBPS] = rx_mbps
195                 result[ResultsConstants.TX_RATE_PERCENT] = float(
196                     row["OfferedLoad(%)"])
197                 result[ResultsConstants.FRAME_LOSS_PERCENT] = float(
198                     row["PercentFrameLoss(%)"])
199                 result[ResultsConstants.FORWARDING_RATE_FPS] = float(
200                     row["ForwardingRate(fps)"])
201         return result
202
203     def get_rfc2544_results(self, filename):
204         """
205         Reads the CSV file and return the results
206         """
207         result = {}
208         with open(filename, "r") as csvfile:
209             csvreader = csv.DictReader(csvfile)
210             for row in csvreader:
211                 self._logger.info("Row: %s", row)
212                 tx_fps = ((float(row["TxFrameCount"])) /
213                           (float(row["Duration(sec)"])))
214                 rx_fps = ((float(row["RxFrameCount"])) /
215                           (float(row["Duration(sec)"])))
216                 tx_mbps = ((float(row["TxFrameCount"]) *
217                             float(row["ConfiguredFrameSize"])) /
218                            (float(row["Duration(sec)"]) * 1000000.0))
219                 rx_mbps = ((float(row["RxFrameCount"]) *
220                             float(row["ConfiguredFrameSize"])) /
221                            (float(row["Duration(sec)"]) * 1000000.0))
222                 result[ResultsConstants.TX_RATE_FPS] = tx_fps
223                 result[ResultsConstants.THROUGHPUT_RX_FPS] = rx_fps
224                 result[ResultsConstants.TX_RATE_MBPS] = tx_mbps
225                 result[ResultsConstants.THROUGHPUT_RX_MBPS] = rx_mbps
226                 result[ResultsConstants.TX_RATE_PERCENT] = float(
227                     row["OfferedLoad(%)"])
228                 result[ResultsConstants.THROUGHPUT_RX_PERCENT] = float(
229                     row["Throughput(%)"])
230                 result[ResultsConstants.MIN_LATENCY_NS] = float(
231                     row["MinimumLatency(us)"]) * 1000
232                 result[ResultsConstants.MAX_LATENCY_NS] = float(
233                     row["MaximumLatency(us)"]) * 1000
234                 result[ResultsConstants.AVG_LATENCY_NS] = float(
235                     row["AverageLatency(us)"]) * 1000
236                 result[ResultsConstants.FRAME_LOSS_PERCENT] = float(
237                     row["PercentLoss"])
238         return result
239
240     def send_cont_traffic(self, traffic=None, duration=30):
241         """
242         Send Custom - Continuous Test traffic
243         Reuse RFC2544 throughput test specifications along with
244         'custom' configuration
245         """
246         verbose = False
247         custom = "cont"
248         framesize = settings.getValue("TRAFFICGEN_STC_FRAME_SIZE")
249         if traffic and 'l2' in traffic:
250             if 'framesize' in traffic['l2']:
251                 framesize = traffic['l2']['framesize']
252
253         stc_common_args = get_stc_common_settings()
254         rfc2544_common_args = get_rfc2544_common_settings()
255         rfc2544_custom_args = get_rfc2544_custom_settings(framesize,
256                                                           custom, 1)
257         args = stc_common_args + rfc2544_common_args + rfc2544_custom_args
258
259         if settings.getValue("TRAFFICGEN_STC_VERBOSE") is "True":
260             args.append("--verbose")
261             verbose = True
262             self._logger.debug("Arguments used to call test: %s", args)
263         subprocess.check_call(args)
264
265         filec = os.path.join(settings.getValue("TRAFFICGEN_STC_RESULTS_DIR"),
266                              settings.getValue(
267                                  "TRAFFICGEN_STC_CSV_RESULTS_FILE_PREFIX") +
268                              ".csv")
269
270         if verbose:
271             self._logger.info("file: %s", filec)
272
273         return self.get_rfc2544_results(filec)
274
275     def send_rfc2889_forwarding(self, traffic=None, tests=1, duration=20):
276         """
277         Send traffic per RFC2544 throughput test specifications.
278         """
279         framesize = settings.getValue("TRAFFICGEN_STC_FRAME_SIZE")
280         if traffic and 'l2' in traffic:
281             if 'framesize' in traffic['l2']:
282                 framesize = traffic['l2']['framesize']
283         args = get_rfc2889_settings(framesize, tests, duration)
284         if settings.getValue("TRAFFICGEN_STC_VERBOSE") is "True":
285             args.append("--verbose")
286             verbose = True
287             self._logger.debug("Arguments used to call test: %s", args)
288         subprocess.check_call(args)
289
290         filec = os.path.join(settings.getValue("TRAFFICGEN_STC_RESULTS_DIR"),
291                              settings.getValue(
292                                  "TRAFFICGEN_STC_CSV_RESULTS_FILE_PREFIX") +
293                              ".csv")
294
295         if verbose:
296             self._logger.debug("file: %s", filec)
297
298         return self.get_rfc2889_results(filec)
299
300     def send_rfc2544_throughput(self, traffic=None, tests=1, duration=20,
301                                 lossrate=0.0):
302         """
303         Send traffic per RFC2544 throughput test specifications.
304         """
305         verbose = False
306         framesize = settings.getValue("TRAFFICGEN_STC_FRAME_SIZE")
307         if traffic and 'l2' in traffic:
308             if 'framesize' in traffic['l2']:
309                 framesize = traffic['l2']['framesize']
310
311         stc_common_args = get_stc_common_settings()
312         rfc2544_common_args = get_rfc2544_common_settings()
313         rfc2544_custom_args = get_rfc2544_custom_settings(framesize, '',
314                                                           tests)
315         args = stc_common_args + rfc2544_common_args + rfc2544_custom_args
316
317         if settings.getValue("TRAFFICGEN_STC_VERBOSE") is "True":
318             args.append("--verbose")
319             verbose = True
320             self._logger.debug("Arguments used to call test: %s", args)
321         subprocess.check_call(args)
322
323         filec = os.path.join(settings.getValue("TRAFFICGEN_STC_RESULTS_DIR"),
324                              settings.getValue(
325                                  "TRAFFICGEN_STC_CSV_RESULTS_FILE_PREFIX") +
326                              ".csv")
327
328         if verbose:
329             self._logger.info("file: %s", filec)
330
331         return self.get_rfc2544_results(filec)
332
333     def send_rfc2544_back2back(self, traffic=None, tests=1, duration=20,
334                                lossrate=0.0):
335         """
336         Send traffic per RFC2544 BacktoBack test specifications.
337         """
338         verbose = False
339         framesize = settings.getValue("TRAFFICGEN_STC_FRAME_SIZE")
340         if traffic and 'l2' in traffic:
341             if 'framesize' in traffic['l2']:
342                 framesize = traffic['l2']['framesize']
343
344         stc_common_args = get_stc_common_settings()
345         rfc2544_common_args = get_rfc2544_common_settings()
346         rfc2544_custom_args = get_rfc2544_custom_settings(framesize, '',
347                                                           tests)
348         args = stc_common_args + rfc2544_common_args + rfc2544_custom_args
349
350         if settings.getValue("TRAFFICGEN_STC_VERBOSE") is "True":
351             args.append("--verbose")
352             verbose = True
353             self._logger.info("Arguments used to call test: %s", args)
354         subprocess.check_call(args)
355
356         filecs = os.path.join(settings.getValue("TRAFFICGEN_STC_RESULTS_DIR"),
357                               settings.getValue(
358                                   "TRAFFICGEN_STC_CSV_RESULTS_FILE_PREFIX") +
359                               ".csv")
360         if verbose:
361             self._logger.debug("file: %s", filecs)
362
363         return self.get_rfc2544_results(filecs)
364
365 if __name__ == '__main__':
366     TRAFFIC = {
367         'l3': {
368             'proto': 'tcp',
369             'srcip': '1.1.1.1',
370             'dstip': '90.90.90.90',
371         },
372     }
373     with TestCenter() as dev:
374         print(dev.send_rfc2544_throughput(traffic=TRAFFIC))
375         print(dev.send_rfc2544_backtoback(traffic=TRAFFIC))