1 # Copyright 2016 Red Hat Inc & Xena Networks.
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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.
16 # Rick Alongi, Red Hat Inc.
17 # Amit Supugade, Red Hat Inc.
18 # Dan Amzulescu, Xena Networks
19 # Christian Trautman, Red Hat Inc.
22 Xena Traffic Generator Model
29 from time import sleep
30 import xml.etree.ElementTree as ET
31 from collections import OrderedDict
34 from conf import settings
35 from core.results.results_constants import ResultsConstants
36 from tools.pkt_gen.trafficgen.trafficgenhelper import (
39 from tools.pkt_gen.trafficgen.trafficgen import ITrafficGenerator
42 from tools.pkt_gen.xena.xena_json import XenaJSON
45 class Xena(ITrafficGenerator):
47 Xena Traffic generator wrapper class
49 _traffic_defaults = TRAFFIC_DEFAULTS.copy()
50 _logger = logging.getLogger(__name__)
58 def traffic_defaults(self):
59 """Default traffic values.
61 These can be expected to be constant across traffic generators,
62 so no setter is provided. Changes to the structure or contents
63 will likely break traffic generator implementations or tests
66 return self._traffic_defaults
69 def _create_throughput_result(root):
71 Create the results based off the output xml file from the Xena2544.exe
73 :param root: root dictionary from xml import
74 :return: Results Ordered dictionary based off ResultsConstants
76 # get the test type from the report file
77 test_type = root[0][1].get('TestType')
79 if test_type == 'Throughput':
80 results = OrderedDict()
81 results[ResultsConstants.THROUGHPUT_RX_FPS] = int(
82 root[0][1][0][1].get('PortRxPps'))
83 results[ResultsConstants.THROUGHPUT_RX_MBPS] = int(
84 root[0][1][0][1].get('PortRxBpsL1')) / 1000000
85 results[ResultsConstants.THROUGHPUT_RX_PERCENT] = (
86 100 - int(root[0][1][0].get('TotalLossRatioPcnt'))) * float(
87 root[0][1][0].get('TotalTxRatePcnt'))/100
88 results[ResultsConstants.TX_RATE_FPS] = root[0][1][0].get(
90 results[ResultsConstants.TX_RATE_MBPS] = float(
91 root[0][1][0].get('TotalTxRateBpsL1')) / 1000000
92 results[ResultsConstants.TX_RATE_PERCENT] = root[0][1][0].get(
95 results[ResultsConstants.MIN_LATENCY_NS] = float(
96 root[0][1][0][0].get('MinLatency')) * 1000
98 # Stats for latency returned as N/A so just post them
99 results[ResultsConstants.MIN_LATENCY_NS] = root[0][1][0][0].get(
102 results[ResultsConstants.MAX_LATENCY_NS] = float(
103 root[0][1][0][0].get('MaxLatency')) * 1000
105 # Stats for latency returned as N/A so just post them
106 results[ResultsConstants.MAX_LATENCY_NS] = root[0][1][0][0].get(
109 results[ResultsConstants.AVG_LATENCY_NS] = float(
110 root[0][1][0][0].get('AvgLatency')) * 1000
112 # Stats for latency returned as N/A so just post them
113 results[ResultsConstants.AVG_LATENCY_NS] = root[0][1][0][0].get(
115 elif test_type == 'Back2Back':
116 results = OrderedDict()
118 # Just mimic what Ixia does and only return the b2b frame count.
119 # This may change later once its decided the common results stats
120 # to be returned should be.
121 results[ResultsConstants.B2B_FRAMES] = root[0][1][0][0].get(
122 'TotalTxBurstFrames')
124 raise NotImplementedError('Unknown test type in report file.')
128 def _setup_json_config(self, trials, loss_rate, testtype=None):
130 Create a 2bUsed json file that will be used for xena2544.exe execution.
131 :param trials: Number of trials
132 :param loss_rate: The acceptable loss rate as float
133 :param testtype: Either '2544_b2b' or '2544_throughput' as string
137 j_file = XenaJSON('./tools/pkt_gen/xena/profiles/baseconfig.x2544')
138 j_file.set_chassis_info(
139 settings.getValue('TRAFFICGEN_XENA_IP'),
140 settings.getValue('TRAFFICGEN_XENA_PASSWORD')
142 j_file.set_port(0, settings.getValue('TRAFFICGEN_XENA_MODULE1'),
143 settings.getValue('TRAFFICGEN_XENA_PORT1')
145 j_file.set_port(1, settings.getValue('TRAFFICGEN_XENA_MODULE2'),
146 settings.getValue('TRAFFICGEN_XENA_PORT2')
148 j_file.set_test_options(
149 packet_sizes=self._params['traffic']['l2']['framesize'],
150 iterations=trials, loss_rate=loss_rate,
151 duration=self._duration, micro_tpld=True if self._params[
152 'traffic']['l2']['framesize'] == 64 else False)
153 if testtype == '2544_throughput':
154 j_file.enable_throughput_test()
155 elif testtype == '2544_b2b':
156 j_file.enable_back2back_test()
158 j_file.set_header_layer2(
159 dst_mac=self._params['traffic']['l2']['dstmac'],
160 src_mac=self._params['traffic']['l2']['srcmac'])
161 j_file.set_header_layer3(
162 src_ip=self._params['traffic']['l3']['srcip'],
163 dst_ip=self._params['traffic']['l3']['dstip'],
164 protocol=self._params['traffic']['l3']['proto'])
165 j_file.set_header_layer4_udp(
166 source_port=self._params['traffic']['l4']['srcport'],
167 destination_port=self._params['traffic']['l4']['dstport'])
168 if self._params['traffic']['vlan']['enabled']:
169 j_file.set_header_vlan(
170 vlan_id=self._params['traffic']['vlan']['id'],
171 id=self._params['traffic']['vlan']['cfi'],
172 prio=self._params['traffic']['vlan']['priority'])
173 j_file.add_header_segments(
174 flows=self._params['traffic']['multistream'],
175 multistream_layer=self._params['traffic']['stream_type'])
177 if bool(self._params['traffic']['bidir']):
178 j_file.set_topology_mesh()
180 j_file.set_topology_blocks()
182 j_file.write_config('./tools/pkt_gen/xena/profiles/2bUsed.x2544')
183 except Exception as exc:
184 self._logger.exception("Error during Xena JSON setup: %s", exc)
188 """Connect to the traffic generator.
190 This is an optional function, designed for traffic generators
191 which must be "connected to" (i.e. via SSH or an API) before
192 they can be used. If not required, simply do nothing here.
194 Where implemented, this function should raise an exception on
201 def disconnect(self):
202 """Disconnect from the traffic generator.
204 As with :func:`connect`, this function is optional.
206 Where implemented, this function should raise an exception on
213 def send_burst_traffic(self, traffic=None, numpkts=100, duration=20):
214 """Send a burst of traffic.
216 Send a ``numpkts`` packets of traffic, using ``traffic``
217 configuration, with a timeout of ``time``.
220 :param traffic: Detailed "traffic" spec, i.e. IP address, VLAN tags
221 :param numpkts: Number of packets to send
222 :param duration: Time to wait to receive packets
224 :returns: dictionary of strings with following data:
228 - List of List of Rx Bytes,
229 - Payload Errors and Sequence Errors.
231 raise NotImplementedError('Xena burst traffic not implemented')
233 def send_cont_traffic(self, traffic=None, duration=20):
234 """Send a continuous flow of traffic.r
236 Send packets at ``framerate``, using ``traffic`` configuration,
237 until timeout ``time`` occurs.
239 :param traffic: Detailed "traffic" spec, i.e. IP address, VLAN tags
240 :param duration: Time to wait to receive packets (secs)
241 :returns: dictionary of strings with following data:
242 - Tx Throughput (fps),
243 - Rx Throughput (fps),
244 - Tx Throughput (mbps),
245 - Rx Throughput (mbps),
246 - Tx Throughput (% linerate),
247 - Rx Throughput (% linerate),
252 raise NotImplementedError('Xena continuous traffic not implemented')
254 def start_cont_traffic(self, traffic=None, duration=20):
255 """Non-blocking version of 'send_cont_traffic'.
257 Start transmission and immediately return. Do not wait for
259 :param traffic: Detailed "traffic" spec, i.e. IP address, VLAN tags
260 :param duration: Time to wait to receive packets (secs)
262 raise NotImplementedError('Xena continuous traffic not implemented')
264 def stop_cont_traffic(self):
265 """Stop continuous transmission and return results.
267 raise NotImplementedError('Xena continuous traffic not implemented')
269 def send_rfc2544_throughput(self, traffic=None, trials=3, duration=20,
271 """Send traffic per RFC2544 throughput test specifications.
273 See ITrafficGenerator for description
275 self._duration = duration
278 self._params['traffic'] = self.traffic_defaults.copy()
280 self._params['traffic'] = merge_spec(self._params['traffic'],
283 self._setup_json_config(trials, lossrate, '2544_throughput')
285 args = ["mono", "./tools/pkt_gen/xena/Xena2544.exe", "-c",
286 "./tools/pkt_gen/xena/profiles/2bUsed.x2544", "-e", "-r",
287 "./tools/pkt_gen/xena", "-u",
288 settings.getValue('TRAFFICGEN_XENA_USER')]
289 self.mono_pipe = subprocess.Popen(args, stdout=sys.stdout)
290 self.mono_pipe.communicate()
291 root = ET.parse(r'./tools/pkt_gen/xena/xena2544-report.xml').getroot()
292 return Xena._create_throughput_result(root)
294 def start_rfc2544_throughput(self, traffic=None, trials=3, duration=20,
296 """Non-blocking version of 'send_rfc2544_throughput'.
298 See ITrafficGenerator for description
300 self._duration = duration
302 self._params['traffic'] = self.traffic_defaults.copy()
304 self._params['traffic'] = merge_spec(self._params['traffic'],
307 self._setup_json_config(trials, lossrate, '2544_throughput')
309 args = ["mono", "./tools/pkt_gen/xena/Xena2544.exe", "-c",
310 "./tools/pkt_gen/xena/profiles/2bUsed.x2544", "-e", "-r",
311 "./tools/pkt_gen/xena", "-u",
312 settings.getValue('TRAFFICGEN_XENA_USER')]
313 self.mono_pipe = subprocess.Popen(args, stdout=sys.stdout)
315 def wait_rfc2544_throughput(self):
316 """Wait for and return results of RFC2544 test.
318 See ITrafficGenerator for description
320 self.mono_pipe.communicate()
322 root = ET.parse(r'./tools/pkt_gen/xena/xena2544-report.xml').getroot()
323 return Xena._create_throughput_result(root)
325 def send_rfc2544_back2back(self, traffic=None, trials=1, duration=20,
327 """Send traffic per RFC2544 back2back test specifications.
329 See ITrafficGenerator for description
331 self._duration = duration
334 self._params['traffic'] = self.traffic_defaults.copy()
336 self._params['traffic'] = merge_spec(self._params['traffic'],
339 self._setup_json_config(trials, lossrate, '2544_b2b')
341 args = ["mono", "./tools/pkt_gen/xena/Xena2544.exe", "-c",
342 "./tools/pkt_gen/xena/profiles/2bUsed.x2544", "-e", "-r",
343 "./tools/pkt_gen/xena", "-u",
344 settings.getValue('TRAFFICGEN_XENA_USER')]
345 self.mono_pipe = subprocess.Popen(
346 args, stdout=sys.stdout)
347 self.mono_pipe.communicate()
348 root = ET.parse(r'./tools/pkt_gen/xena/xena2544-report.xml').getroot()
349 return Xena._create_throughput_result(root)
351 def start_rfc2544_back2back(self, traffic=None, trials=1, duration=20,
353 """Non-blocking version of 'send_rfc2544_back2back'.
355 See ITrafficGenerator for description
357 self._duration = duration
360 self._params['traffic'] = self.traffic_defaults.copy()
362 self._params['traffic'] = merge_spec(self._params['traffic'],
365 self._setup_json_config(trials, lossrate, '2544_b2b')
367 args = ["mono", "./tools/pkt_gen/xena/Xena2544.exe", "-c",
368 "./tools/pkt_gen/xena/profiles/2bUsed.x2544", "-e", "-r",
369 "./tools/pkt_gen/xena", "-u",
370 settings.getValue('TRAFFICGEN_XENA_USER')]
371 self.mono_pipe = subprocess.Popen(
372 args, stdout=sys.stdout)
374 def wait_rfc2544_back2back(self):
375 """Wait and set results of RFC2544 test.
377 self.mono_pipe.communicate()
379 root = ET.parse(r'./tools/pkt_gen/xena/xena2544-report.xml').getroot()
380 return Xena._create_throughput_result(root)
383 if __name__ == "__main__":