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')
78 # set the version from the report file
79 settings.setValue('XENA_VERSION', root[0][0][1].get('GeneratedBy'))
81 if test_type == 'Throughput':
82 results = OrderedDict()
83 results[ResultsConstants.THROUGHPUT_RX_FPS] = int(
84 root[0][1][0][1].get('PortRxPps'))
85 results[ResultsConstants.THROUGHPUT_RX_MBPS] = int(
86 root[0][1][0][1].get('PortRxBpsL1')) / 1000000
87 results[ResultsConstants.THROUGHPUT_RX_PERCENT] = (
88 100 - int(root[0][1][0].get('TotalLossRatioPcnt'))) * float(
89 root[0][1][0].get('TotalTxRatePcnt'))/100
90 results[ResultsConstants.TX_RATE_FPS] = root[0][1][0].get(
92 results[ResultsConstants.TX_RATE_MBPS] = float(
93 root[0][1][0].get('TotalTxRateBpsL1')) / 1000000
94 results[ResultsConstants.TX_RATE_PERCENT] = root[0][1][0].get(
97 results[ResultsConstants.MIN_LATENCY_NS] = float(
98 root[0][1][0][0].get('MinLatency')) * 1000
100 # Stats for latency returned as N/A so just post them
101 results[ResultsConstants.MIN_LATENCY_NS] = root[0][1][0][0].get(
104 results[ResultsConstants.MAX_LATENCY_NS] = float(
105 root[0][1][0][0].get('MaxLatency')) * 1000
107 # Stats for latency returned as N/A so just post them
108 results[ResultsConstants.MAX_LATENCY_NS] = root[0][1][0][0].get(
111 results[ResultsConstants.AVG_LATENCY_NS] = float(
112 root[0][1][0][0].get('AvgLatency')) * 1000
114 # Stats for latency returned as N/A so just post them
115 results[ResultsConstants.AVG_LATENCY_NS] = root[0][1][0][0].get(
117 elif test_type == 'Back2Back':
118 results = OrderedDict()
120 # Just mimic what Ixia does and only return the b2b frame count.
121 # This may change later once its decided the common results stats
122 # to be returned should be.
123 results[ResultsConstants.B2B_FRAMES] = root[0][1][0][0].get(
124 'TotalTxBurstFrames')
126 raise NotImplementedError('Unknown test type in report file.')
130 def _setup_json_config(self, trials, loss_rate, testtype=None):
132 Create a 2bUsed json file that will be used for xena2544.exe execution.
133 :param trials: Number of trials
134 :param loss_rate: The acceptable loss rate as float
135 :param testtype: Either '2544_b2b' or '2544_throughput' as string
139 j_file = XenaJSON('./tools/pkt_gen/xena/profiles/baseconfig.x2544')
140 j_file.set_chassis_info(
141 settings.getValue('TRAFFICGEN_XENA_IP'),
142 settings.getValue('TRAFFICGEN_XENA_PASSWORD')
144 j_file.set_port(0, settings.getValue('TRAFFICGEN_XENA_MODULE1'),
145 settings.getValue('TRAFFICGEN_XENA_PORT1')
147 j_file.set_port(1, settings.getValue('TRAFFICGEN_XENA_MODULE2'),
148 settings.getValue('TRAFFICGEN_XENA_PORT2')
150 j_file.set_test_options(
151 packet_sizes=self._params['traffic']['l2']['framesize'],
152 iterations=trials, loss_rate=loss_rate,
153 duration=self._duration, micro_tpld=True if self._params[
154 'traffic']['l2']['framesize'] == 64 else False)
155 if testtype == '2544_throughput':
156 j_file.enable_throughput_test()
157 elif testtype == '2544_b2b':
158 j_file.enable_back2back_test()
160 j_file.set_header_layer2(
161 dst_mac=self._params['traffic']['l2']['dstmac'],
162 src_mac=self._params['traffic']['l2']['srcmac'])
163 j_file.set_header_layer3(
164 src_ip=self._params['traffic']['l3']['srcip'],
165 dst_ip=self._params['traffic']['l3']['dstip'],
166 protocol=self._params['traffic']['l3']['proto'])
167 j_file.set_header_layer4_udp(
168 source_port=self._params['traffic']['l4']['srcport'],
169 destination_port=self._params['traffic']['l4']['dstport'])
170 if self._params['traffic']['vlan']['enabled']:
171 j_file.set_header_vlan(
172 vlan_id=self._params['traffic']['vlan']['id'],
173 id=self._params['traffic']['vlan']['cfi'],
174 prio=self._params['traffic']['vlan']['priority'])
175 j_file.add_header_segments(
176 flows=self._params['traffic']['multistream'],
177 multistream_layer=self._params['traffic']['stream_type'])
179 if bool(self._params['traffic']['bidir']):
180 j_file.set_topology_mesh()
182 j_file.set_topology_blocks()
184 j_file.write_config('./tools/pkt_gen/xena/profiles/2bUsed.x2544')
185 except Exception as exc:
186 self._logger.exception("Error during Xena JSON setup: %s", exc)
190 """Connect to the traffic generator.
192 This is an optional function, designed for traffic generators
193 which must be "connected to" (i.e. via SSH or an API) before
194 they can be used. If not required, simply do nothing here.
196 Where implemented, this function should raise an exception on
203 def disconnect(self):
204 """Disconnect from the traffic generator.
206 As with :func:`connect`, this function is optional.
208 Where implemented, this function should raise an exception on
215 def send_burst_traffic(self, traffic=None, numpkts=100, duration=20):
216 """Send a burst of traffic.
218 Send a ``numpkts`` packets of traffic, using ``traffic``
219 configuration, with a timeout of ``time``.
222 :param traffic: Detailed "traffic" spec, i.e. IP address, VLAN tags
223 :param numpkts: Number of packets to send
224 :param duration: Time to wait to receive packets
226 :returns: dictionary of strings with following data:
230 - List of List of Rx Bytes,
231 - Payload Errors and Sequence Errors.
233 raise NotImplementedError('Xena burst traffic not implemented')
235 def send_cont_traffic(self, traffic=None, duration=20):
236 """Send a continuous flow of traffic.r
238 Send packets at ``framerate``, using ``traffic`` configuration,
239 until timeout ``time`` occurs.
241 :param traffic: Detailed "traffic" spec, i.e. IP address, VLAN tags
242 :param duration: Time to wait to receive packets (secs)
243 :returns: dictionary of strings with following data:
244 - Tx Throughput (fps),
245 - Rx Throughput (fps),
246 - Tx Throughput (mbps),
247 - Rx Throughput (mbps),
248 - Tx Throughput (% linerate),
249 - Rx Throughput (% linerate),
254 raise NotImplementedError('Xena continuous traffic not implemented')
256 def start_cont_traffic(self, traffic=None, duration=20):
257 """Non-blocking version of 'send_cont_traffic'.
259 Start transmission and immediately return. Do not wait for
261 :param traffic: Detailed "traffic" spec, i.e. IP address, VLAN tags
262 :param duration: Time to wait to receive packets (secs)
264 raise NotImplementedError('Xena continuous traffic not implemented')
266 def stop_cont_traffic(self):
267 """Stop continuous transmission and return results.
269 raise NotImplementedError('Xena continuous traffic not implemented')
271 def send_rfc2544_throughput(self, traffic=None, trials=3, duration=20,
273 """Send traffic per RFC2544 throughput test specifications.
275 See ITrafficGenerator for description
277 self._duration = duration
280 self._params['traffic'] = self.traffic_defaults.copy()
282 self._params['traffic'] = merge_spec(self._params['traffic'],
285 self._setup_json_config(trials, lossrate, '2544_throughput')
287 args = ["mono", "./tools/pkt_gen/xena/Xena2544.exe", "-c",
288 "./tools/pkt_gen/xena/profiles/2bUsed.x2544", "-e", "-r",
289 "./tools/pkt_gen/xena", "-u",
290 settings.getValue('TRAFFICGEN_XENA_USER')]
291 self.mono_pipe = subprocess.Popen(args, stdout=sys.stdout)
292 self.mono_pipe.communicate()
293 root = ET.parse(r'./tools/pkt_gen/xena/xena2544-report.xml').getroot()
294 return Xena._create_throughput_result(root)
296 def start_rfc2544_throughput(self, traffic=None, trials=3, duration=20,
298 """Non-blocking version of 'send_rfc2544_throughput'.
300 See ITrafficGenerator for description
302 self._duration = duration
304 self._params['traffic'] = self.traffic_defaults.copy()
306 self._params['traffic'] = merge_spec(self._params['traffic'],
309 self._setup_json_config(trials, lossrate, '2544_throughput')
311 args = ["mono", "./tools/pkt_gen/xena/Xena2544.exe", "-c",
312 "./tools/pkt_gen/xena/profiles/2bUsed.x2544", "-e", "-r",
313 "./tools/pkt_gen/xena", "-u",
314 settings.getValue('TRAFFICGEN_XENA_USER')]
315 self.mono_pipe = subprocess.Popen(args, stdout=sys.stdout)
317 def wait_rfc2544_throughput(self):
318 """Wait for and return results of RFC2544 test.
320 See ITrafficGenerator for description
322 self.mono_pipe.communicate()
324 root = ET.parse(r'./tools/pkt_gen/xena/xena2544-report.xml').getroot()
325 return Xena._create_throughput_result(root)
327 def send_rfc2544_back2back(self, traffic=None, trials=1, duration=20,
329 """Send traffic per RFC2544 back2back test specifications.
331 See ITrafficGenerator for description
333 self._duration = duration
336 self._params['traffic'] = self.traffic_defaults.copy()
338 self._params['traffic'] = merge_spec(self._params['traffic'],
341 self._setup_json_config(trials, lossrate, '2544_b2b')
343 args = ["mono", "./tools/pkt_gen/xena/Xena2544.exe", "-c",
344 "./tools/pkt_gen/xena/profiles/2bUsed.x2544", "-e", "-r",
345 "./tools/pkt_gen/xena", "-u",
346 settings.getValue('TRAFFICGEN_XENA_USER')]
347 self.mono_pipe = subprocess.Popen(
348 args, stdout=sys.stdout)
349 self.mono_pipe.communicate()
350 root = ET.parse(r'./tools/pkt_gen/xena/xena2544-report.xml').getroot()
351 return Xena._create_throughput_result(root)
353 def start_rfc2544_back2back(self, traffic=None, trials=1, duration=20,
355 """Non-blocking version of 'send_rfc2544_back2back'.
357 See ITrafficGenerator for description
359 self._duration = duration
362 self._params['traffic'] = self.traffic_defaults.copy()
364 self._params['traffic'] = merge_spec(self._params['traffic'],
367 self._setup_json_config(trials, lossrate, '2544_b2b')
369 args = ["mono", "./tools/pkt_gen/xena/Xena2544.exe", "-c",
370 "./tools/pkt_gen/xena/profiles/2bUsed.x2544", "-e", "-r",
371 "./tools/pkt_gen/xena", "-u",
372 settings.getValue('TRAFFICGEN_XENA_USER')]
373 self.mono_pipe = subprocess.Popen(
374 args, stdout=sys.stdout)
376 def wait_rfc2544_back2back(self):
377 """Wait and set results of RFC2544 test.
379 self.mono_pipe.communicate()
381 root = ET.parse(r'./tools/pkt_gen/xena/xena2544-report.xml').getroot()
382 return Xena._create_throughput_result(root)
385 if __name__ == "__main__":