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
31 import xml.etree.ElementTree as ET
32 from collections import OrderedDict
33 from time import sleep
35 from conf import merge_spec
36 from conf import settings
37 from core.results.results_constants import ResultsConstants
38 from tools.pkt_gen.trafficgen.trafficgen import ITrafficGenerator
39 from tools.pkt_gen.xena.XenaDriver import (
46 from tools.pkt_gen.xena.json.xena_json_mesh import XenaJSONMesh
47 from tools.pkt_gen.xena.json.xena_json_blocks import XenaJSONBlocks
48 from tools.pkt_gen.xena.json.xena_json_pairs import XenaJSONPairs
50 _CURR_DIR = os.path.dirname(os.path.realpath(__file__))
52 class Xena(ITrafficGenerator):
54 Xena Traffic generator wrapper class
56 _logger = logging.getLogger(__name__)
67 self._log_handle = None
69 user_home = os.path.expanduser('~')
70 self._log_path = '{}/Xena/Xena2544-2G/Logs/xena2544.log'.format(
73 # make the folder and log file if they doesn't exist
74 if not os.path.exists(self._log_path):
75 os.makedirs(os.path.dirname(self._log_path))
77 # empty the file contents
78 open(self._log_path, 'w').close()
81 def _create_throughput_result(root):
83 Create the results based off the output xml file from the Xena2544.exe
85 :param root: root dictionary from xml import
86 :return: Results Ordered dictionary based off ResultsConstants
88 # get the test type from the report file
89 test_type = root[0][1].get('TestType')
90 # set the version from the report file
91 settings.setValue('XENA_VERSION', root[0][0][1].get('GeneratedBy'))
93 if test_type == 'Throughput':
94 results = OrderedDict()
95 results[ResultsConstants.THROUGHPUT_RX_FPS] = float(
96 root[0][1][0][0].get('PortRxPps')) + float(
97 root[0][1][0][1].get('PortRxPps'))
98 results[ResultsConstants.THROUGHPUT_RX_MBPS] = (float(
99 root[0][1][0][0].get('PortRxBpsL1')) + float(
100 root[0][1][0][1].get('PortRxBpsL1')))/ 1000000
101 results[ResultsConstants.THROUGHPUT_RX_PERCENT] = (
102 100 - float(root[0][1][0].get('TotalLossRatioPcnt'))) * float(
103 root[0][1][0].get('TotalTxRatePcnt'))/100
104 results[ResultsConstants.TX_RATE_FPS] = root[0][1][0].get(
106 results[ResultsConstants.TX_RATE_MBPS] = float(
107 root[0][1][0].get('TotalTxRateBpsL1')) / 1000000
108 results[ResultsConstants.TX_RATE_PERCENT] = root[0][1][0].get(
111 results[ResultsConstants.MIN_LATENCY_NS] = float(
112 root[0][1][0][0].get('MinLatency')) * 1000
114 # Stats for latency returned as N/A so just post them
115 results[ResultsConstants.MIN_LATENCY_NS] = root[0][1][0][0].get(
118 results[ResultsConstants.MAX_LATENCY_NS] = float(
119 root[0][1][0][0].get('MaxLatency')) * 1000
121 # Stats for latency returned as N/A so just post them
122 results[ResultsConstants.MAX_LATENCY_NS] = root[0][1][0][0].get(
125 results[ResultsConstants.AVG_LATENCY_NS] = float(
126 root[0][1][0][0].get('AvgLatency')) * 1000
128 # Stats for latency returned as N/A so just post them
129 results[ResultsConstants.AVG_LATENCY_NS] = root[0][1][0][0].get(
131 elif test_type == 'Back2Back':
132 results = OrderedDict()
134 # Just mimic what Ixia does and only return the b2b frame count.
135 # This may change later once its decided the common results stats
136 # to be returned should be.
137 results[ResultsConstants.B2B_FRAMES] = root[0][1][0][0].get(
138 'TotalTxBurstFrames')
140 raise NotImplementedError('Unknown test type in report file.')
144 def _build_packet_header(self, reverse=False):
146 Build a packet header based on traffic profile using scapy external
148 :param reverse: Swap source and destination info when building header
149 :return: packet header in hex
151 # import can't be performed at module level, because it conflicts with import
152 # of customized scapy version by T-Rex
153 import scapy.layers.inet as inet
155 srcmac = self._params['traffic']['l2'][
156 'srcmac'] if not reverse else self._params['traffic']['l2'][
158 dstmac = self._params['traffic']['l2'][
159 'dstmac'] if not reverse else self._params['traffic']['l2'][
161 srcip = self._params['traffic']['l3'][
162 'srcip'] if not reverse else self._params['traffic']['l3']['dstip']
163 dstip = self._params['traffic']['l3'][
164 'dstip'] if not reverse else self._params['traffic']['l3']['srcip']
165 layer2 = inet.Ether(src=srcmac, dst=dstmac)
166 layer3 = inet.IP(src=srcip, dst=dstip,
167 proto=self._params['traffic']['l3']['proto'])
168 layer4 = inet.UDP(sport=self._params['traffic']['l4']['srcport'],
169 dport=self._params['traffic']['l4']['dstport'])
170 if self._params['traffic']['vlan']['enabled']:
171 vlan = inet.Dot1Q(vlan=self._params['traffic']['vlan']['id'],
172 prio=self._params['traffic']['vlan']['priority'],
173 id=self._params['traffic']['vlan']['cfi'])
176 packet = layer2/vlan/layer3/layer4 if vlan else layer2/layer3/layer4
177 packet_bytes = bytes(packet)
178 packet_hex = '0x' + binascii.hexlify(packet_bytes).decode('utf-8')
181 def _create_api_result(self):
183 Create result dictionary per trafficgen specifications from socket API
184 stats. If stats are not available return values of 0.
185 :return: ResultsConstants as dictionary
187 # Handle each case of statistics based on if the data is available.
188 # This prevents uncaught exceptions when the stats aren't available.
189 result_dict = OrderedDict()
190 if self.tx_stats.data.get(self.tx_stats.pt_stream_keys[0]):
191 result_dict[ResultsConstants.TX_FRAMES] = self.tx_stats.data[
192 self.tx_stats.pt_stream_keys[0]]['packets']
193 result_dict[ResultsConstants.TX_RATE_FPS] = self.tx_stats.data[
194 self.tx_stats.pt_stream_keys[0]]['packets'] / self._duration
195 result_dict[ResultsConstants.TX_RATE_MBPS] = ((
196 self.tx_stats.data[self.tx_stats.pt_stream_keys[0]]['bytes']
197 * 8) / 1000000) / self._duration
198 result_dict[ResultsConstants.TX_BYTES] = self.tx_stats.data[
199 self.tx_stats.pt_stream_keys[0]]['bytes']
200 # tx rate percent may need to be halved if bi directional
201 result_dict[ResultsConstants.TX_RATE_PERCENT] = line_percentage(
202 self.xmanager.ports[0], self.tx_stats, self._duration,
203 self._params['traffic']['l2']['framesize']) if \
204 self._params['traffic']['bidir'] == 'False' else\
206 self.xmanager.ports[0], self.tx_stats, self._duration,
207 self._params['traffic']['l2']['framesize']) / 2
209 self._logger.error('Transmit stats not available.')
210 result_dict[ResultsConstants.TX_FRAMES] = 0
211 result_dict[ResultsConstants.TX_RATE_FPS] = 0
212 result_dict[ResultsConstants.TX_RATE_MBPS] = 0
213 result_dict[ResultsConstants.TX_BYTES] = 0
214 result_dict[ResultsConstants.TX_RATE_PERCENT] = 0
216 if self.rx_stats.data.get('pr_tpldstraffic'):
217 result_dict[ResultsConstants.RX_FRAMES] = self.rx_stats.data[
218 'pr_tpldstraffic']['0']['packets']
220 ResultsConstants.THROUGHPUT_RX_FPS] = self.rx_stats.data[
221 'pr_tpldstraffic']['0']['packets'] / self._duration
223 ResultsConstants.THROUGHPUT_RX_MBPS] = ((
224 self.rx_stats.data['pr_tpldstraffic']['0']['bytes']
225 *8) / 1000000) / self._duration
226 result_dict[ResultsConstants.RX_BYTES] = self.rx_stats.data[
227 'pr_tpldstraffic']['0']['bytes']
228 # throughput percent may need to be halved if bi directional
230 ResultsConstants.THROUGHPUT_RX_PERCENT] = line_percentage(
231 self.xmanager.ports[1], self.rx_stats, self._duration,
232 self._params['traffic']['l2']['framesize']) if \
233 self._params['traffic']['bidir'] == 'False' else \
235 self.xmanager.ports[1], self.rx_stats, self._duration,
236 self._params['traffic']['l2']['framesize']) / 2
239 self._logger.error('Receive stats not available.')
240 result_dict[ResultsConstants.RX_FRAMES] = 0
241 result_dict[ResultsConstants.THROUGHPUT_RX_FPS] = 0
242 result_dict[ResultsConstants.THROUGHPUT_RX_MBPS] = 0
243 result_dict[ResultsConstants.RX_BYTES] = 0
244 result_dict[ResultsConstants.THROUGHPUT_RX_PERCENT] = 0
246 if self.rx_stats.data.get('pr_tplderrors'):
247 result_dict[ResultsConstants.PAYLOAD_ERR] = self.rx_stats.data[
248 'pr_tplderrors']['0']['pld']
249 result_dict[ResultsConstants.SEQ_ERR] = self.rx_stats.data[
250 'pr_tplderrors']['0']['seq']
252 result_dict[ResultsConstants.PAYLOAD_ERR] = 0
253 result_dict[ResultsConstants.SEQ_ERR] = 0
255 if self.rx_stats.data.get('pr_tpldlatency'):
256 result_dict[ResultsConstants.MIN_LATENCY_NS] = self.rx_stats.data[
257 'pr_tpldlatency']['0']['min']
258 result_dict[ResultsConstants.MAX_LATENCY_NS] = self.rx_stats.data[
259 'pr_tpldlatency']['0']['max']
260 result_dict[ResultsConstants.AVG_LATENCY_NS] = self.rx_stats.data[
261 'pr_tpldlatency']['0']['avg']
263 result_dict[ResultsConstants.MIN_LATENCY_NS] = 0
264 result_dict[ResultsConstants.MAX_LATENCY_NS] = 0
265 result_dict[ResultsConstants.AVG_LATENCY_NS] = 0
269 def _setup_json_config(self, tests, loss_rate, testtype=None,
272 Create a 2bUsed json file that will be used for xena2544.exe execution.
273 :param tests: Number of tests
274 :param loss_rate: The acceptable loss rate as float
275 :param testtype: Either '2544_b2b' or '2544_throughput' as string
276 :param bonding_test: Specify if the test is a bonding test which will
277 enable the pairs topology
281 if self._params['traffic']['bidir'] == "True":
282 j_file = XenaJSONMesh()
283 elif self._params['traffic']['bidir'] == "False":
284 j_file = XenaJSONBlocks()
286 j_file = XenaJSONPairs()
287 else: # just default to mesh config
288 self._logger.error('Invalid traffic type defaulting to Mesh config')
289 j_file = XenaJSONMesh()
291 j_file.set_chassis_info(
292 settings.getValue('TRAFFICGEN_XENA_IP'),
293 settings.getValue('TRAFFICGEN_XENA_PASSWORD')
295 j_file.set_port(0, settings.getValue('TRAFFICGEN_XENA_MODULE1'),
296 settings.getValue('TRAFFICGEN_XENA_PORT1'))
297 j_file.set_port(1, settings.getValue('TRAFFICGEN_XENA_MODULE2'),
298 settings.getValue('TRAFFICGEN_XENA_PORT2'))
299 j_file.set_port_ip_v4(
300 0, settings.getValue("TRAFFICGEN_XENA_PORT0_IP"),
301 settings.getValue("TRAFFICGEN_XENA_PORT0_CIDR"),
302 settings.getValue("TRAFFICGEN_XENA_PORT0_GATEWAY"))
303 j_file.set_port_ip_v4(
304 1, settings.getValue("TRAFFICGEN_XENA_PORT1_IP"),
305 settings.getValue("TRAFFICGEN_XENA_PORT1_CIDR"),
306 settings.getValue("TRAFFICGEN_XENA_PORT1_GATEWAY"))
308 if testtype == '2544_throughput':
309 j_file.set_test_options_tput(
310 packet_sizes=self._params['traffic']['l2']['framesize'],
311 iterations=tests, loss_rate=loss_rate,
312 duration=self._duration, micro_tpld=True if self._params[
313 'traffic']['l2']['framesize'] == 64 else False)
314 j_file.enable_throughput_test()
315 j_file.modify_2544_tput_options(
316 settings.getValue('TRAFFICGEN_XENA_2544_TPUT_INIT_VALUE'),
317 settings.getValue('TRAFFICGEN_XENA_2544_TPUT_MIN_VALUE'),
318 settings.getValue('TRAFFICGEN_XENA_2544_TPUT_MAX_VALUE'),
320 'TRAFFICGEN_XENA_2544_TPUT_VALUE_RESOLUTION'),
322 'TRAFFICGEN_XENA_2544_TPUT_USEPASS_THRESHHOLD'),
324 'TRAFFICGEN_XENA_2544_TPUT_PASS_THRESHHOLD')
327 elif testtype == '2544_b2b':
328 j_file.set_test_options_back2back(
329 packet_sizes=self._params['traffic']['l2']['framesize'],
330 iterations=tests, duration=self._duration,
331 startvalue=self._params['traffic']['frame_rate'],
332 endvalue=self._params['traffic']['frame_rate'],
333 micro_tpld=True if self._params[
334 'traffic']['l2']['framesize'] == 64 else False)
335 j_file.enable_back2back_test()
337 j_file.set_header_layer2(
338 dst_mac=self._params['traffic']['l2']['dstmac'],
339 src_mac=self._params['traffic']['l2']['srcmac'])
340 j_file.set_header_layer3(
341 src_ip=self._params['traffic']['l3']['srcip'],
342 dst_ip=self._params['traffic']['l3']['dstip'],
343 protocol=self._params['traffic']['l3']['proto'])
344 j_file.set_header_layer4_udp(
345 source_port=self._params['traffic']['l4']['srcport'],
346 destination_port=self._params['traffic']['l4']['dstport'])
347 if self._params['traffic']['vlan']['enabled']:
348 j_file.set_header_vlan(
349 vlan_id=self._params['traffic']['vlan']['id'],
350 id=self._params['traffic']['vlan']['cfi'],
351 prio=self._params['traffic']['vlan']['priority'])
352 j_file.add_header_segments(
353 flows=self._params['traffic']['multistream'] - 1,
354 multistream_layer=self._params['traffic']['stream_type'])
356 j_file.write_config(os.path.join(
357 _CURR_DIR, 'profiles/2bUsed.x2544'))
358 except Exception as exc:
359 self._logger.exception("Error during Xena JSON setup: %s", exc)
362 def _start_traffic_api(self, packet_limit):
364 Start the Xena traffic using the socket API driver
365 :param packet_limit: packet limit for stream, set to -1 for no limit
368 if not self.xmanager:
369 self._xsocket = XenaSocketDriver(
370 settings.getValue('TRAFFICGEN_XENA_IP'))
371 self.xmanager = XenaManager(
372 self._xsocket, settings.getValue('TRAFFICGEN_XENA_USER'),
373 settings.getValue('TRAFFICGEN_XENA_PASSWORD'))
375 # for the report file version info ask the chassis directly for its
377 settings.setValue('XENA_VERSION', 'XENA Socket API - {}'.format(
378 self.xmanager.get_version()))
380 if not self.xmanager.ports:
381 self.xmanager.ports[0] = self.xmanager.add_module_port(
382 settings.getValue('TRAFFICGEN_XENA_MODULE1'),
383 settings.getValue('TRAFFICGEN_XENA_PORT1'))
384 if not self.xmanager.ports[0].reserve_port():
386 'Unable to reserve port 0. Please release Xena Port')
388 if len(self.xmanager.ports) < 2:
389 self.xmanager.ports[1] = self.xmanager.add_module_port(
390 settings.getValue('TRAFFICGEN_XENA_MODULE2'),
391 settings.getValue('TRAFFICGEN_XENA_PORT2'))
392 if not self.xmanager.ports[1].reserve_port():
394 'Unable to reserve port 1. Please release Xena Port')
396 # Clear port configuration for a clean start
397 self.xmanager.ports[0].reset_port()
398 self.xmanager.ports[1].reset_port()
399 if settings.getValue('TRAFFICGEN_XENA_CONT_PORT_LEARNING_ENABLED'):
400 # turn on port learning
401 self.xmanager.ports[0].set_port_learning(1)
402 self.xmanager.ports[1].set_port_learning(1)
403 sleep(settings.getValue('TRAFFICGEN_XENA_CONT_PORT_LEARNING_DURATION'))
404 # turn off port learning
405 self.xmanager.ports[0].set_port_learning(0)
406 self.xmanager.ports[1].set_port_learning(0)
408 self.xmanager.ports[0].clear_stats()
409 self.xmanager.ports[1].clear_stats()
411 # set the port IP from the conf file
412 self.xmanager.ports[0].set_port_ip(
413 settings.getValue('TRAFFICGEN_XENA_PORT0_IP'),
414 settings.getValue('TRAFFICGEN_XENA_PORT0_CIDR'),
415 settings.getValue('TRAFFICGEN_XENA_PORT0_GATEWAY'))
416 self.xmanager.ports[1].set_port_ip(
417 settings.getValue('TRAFFICGEN_XENA_PORT1_IP'),
418 settings.getValue('TRAFFICGEN_XENA_PORT1_CIDR'),
419 settings.getValue('TRAFFICGEN_XENA_PORT1_GATEWAY'))
420 self.xmanager.ports[0].set_port_time_limit(self._duration)
421 self.xmanager.ports[1].set_port_time_limit(self._duration)
423 def setup_stream(stream, port, payload_id, flip_addr=False):
425 Helper function to configure streams.
426 :param stream: Stream object from XenaDriver module
427 :param port: Port object from XenaDriver module
428 :param payload_id: payload ID as int
429 :param flip_addr: Boolean if the source and destination addresses
434 if packet_limit != -1:
435 stream.set_packet_limit(packet_limit)
437 port.set_port_arp_reply(is_on=True)
438 port.set_port_arp_reply(is_on=True, ipv6=True)
439 port.set_port_ping_reply(is_on=True)
440 port.set_port_ping_reply(is_on=True, ipv6=True)
442 stream.set_rate_fraction(int(
443 10000 * self._params['traffic']['frame_rate']))
444 stream.set_packet_header(self._build_packet_header(
446 stream.set_header_protocol(
447 'ETHERNET VLAN IP UDP' if self._params['traffic']['vlan'][
448 'enabled'] else 'ETHERNET IP UDP')
449 stream.set_packet_length(
450 'fixed', self._params['traffic']['l2']['framesize'],
451 self._params['traffic']['l2']['framesize'])
452 stream.set_packet_payload('incrementing', '0x00')
453 stream.set_payload_id(payload_id)
454 port.set_port_time_limit(self._duration * 1000000)
456 if self._params['traffic']['l2']['framesize'] == 64:
458 port.micro_tpld_enable()
460 if self._params['traffic']['multistream']:
461 if self._params['traffic']['stream_type'] == 'L2':
462 modobj = ModSet(mod_src_mac=True, mod_dst_mac=True)
463 elif self._params['traffic']['stream_type'] == 'L3':
464 modobj = ModSet(mod_src_ip=True, mod_dst_ip=True)
465 elif self._params['traffic']['stream_type'] == 'L4':
466 modobj = ModSet(mod_src_port=True, mod_dst_port=True)
468 self._logger.error('Invalid segment for multistream. Using L2..')
469 modobj = ModSet(mod_src_mac=True, mod_dst_mac=True)
470 stream.enable_multistream(
471 flows=self._params['traffic']['multistream'], mod_class=modobj)
473 s1_p0 = self.xmanager.ports[0].add_stream()
474 setup_stream(s1_p0, self.xmanager.ports[0], 0)
476 if self._params['traffic']['bidir'] == 'True':
477 s1_p1 = self.xmanager.ports[1].add_stream()
478 setup_stream(s1_p1, self.xmanager.ports[1], 1, flip_addr=True)
480 if not self.xmanager.ports[0].traffic_on():
482 "Failure to start port 0. Check settings and retry.")
483 if self._params['traffic']['bidir'] == 'True':
484 if not self.xmanager.ports[1].traffic_on():
486 "Failure to start port 1. Check settings and retry.")
487 sleep(self._duration + 5) # the extra 5 seconds is to allow packets in flight to complete
489 if self._params['traffic']['bidir'] == 'True':
490 # need to aggregate out both ports stats and assign that data
491 self.rx_stats = self.xmanager.ports[1].get_rx_stats()
492 self.tx_stats = self.xmanager.ports[0].get_tx_stats()
493 self.tx_stats.data = aggregate_stats(
495 self.xmanager.ports[1].get_tx_stats().data)
496 self.rx_stats.data = aggregate_stats(
498 self.xmanager.ports[0].get_rx_stats().data)
500 # no need to aggregate, just grab the appropriate port stats
501 self.tx_stats = self.xmanager.ports[0].get_tx_stats()
502 self.rx_stats = self.xmanager.ports[1].get_rx_stats()
505 def _start_xena_2544(self):
507 Start the xena2544 exe.
510 args = ["mono", os.path.join(_CURR_DIR, "Xena2544.exe"), "-c",
511 os.path.join(_CURR_DIR, "profiles/2bUsed.x2544"), "-e", "-r",
513 settings.getValue('TRAFFICGEN_XENA_USER')]
514 # Sometimes Xena2544.exe completes, but mono holds the process without
515 # releasing it, this can cause a deadlock of the main thread. Use the
516 # xena log file as a way to detect this.
517 self._log_handle = open(self._log_path, 'r')
518 # read the contents of the log before we start so the next read in the
519 # wait method are only looking at the text from this test instance
520 self._log_handle.read()
521 self.mono_pipe = subprocess.Popen(args, stdout=sys.stdout)
523 def _wait_xena_2544_complete(self):
525 Wait for Xena2544.exe completion.
531 self.mono_pipe.wait(60)
532 self._log_handle.close()
534 except subprocess.TimeoutExpired:
535 # check the log to see if Xena2544 has completed and mono is
537 data += self._log_handle.read()
538 if 'TestCompletedSuccessfully' in data:
539 self._log_handle.close()
540 self.mono_pipe.terminate()
543 def _stop_api_traffic(self):
545 Stop traffic through the socket API
546 :return: Return results from _create_api_result method
548 self.xmanager.ports[0].traffic_off()
549 if self._params['traffic']['bidir'] == 'True':
550 self.xmanager.ports[1].traffic_off()
553 stat = self._create_api_result()
558 self._logger.debug('Connect')
561 def disconnect(self):
562 """Disconnect from the traffic generator.
564 As with :func:`connect`, this function is optional.
567 Where implemented, this function should raise an exception on
572 self._logger.debug('disconnect')
574 self.xmanager.disconnect()
578 self._xsocket.disconnect()
581 def send_burst_traffic(self, traffic=None, duration=20):
582 """Send a burst of traffic.
584 See ITrafficGenerator for description
586 self._duration = duration
588 self._params['traffic'] = self.traffic_defaults.copy()
590 self._params['traffic'] = merge_spec(self._params['traffic'],
592 self._start_traffic_api(traffic['burst_size'])
593 return self._stop_api_traffic()
595 def send_cont_traffic(self, traffic=None, duration=20):
596 """Send a continuous flow of traffic.
598 See ITrafficGenerator for description
600 self._duration = duration
603 self._params['traffic'] = self.traffic_defaults.copy()
605 self._params['traffic'] = merge_spec(self._params['traffic'],
607 self._start_traffic_api(-1)
608 return self._stop_api_traffic()
610 def start_cont_traffic(self, traffic=None, duration=20):
611 """Non-blocking version of 'send_cont_traffic'.
613 See ITrafficGenerator for description
615 self._duration = duration
618 self._params['traffic'] = self.traffic_defaults.copy()
620 self._params['traffic'] = merge_spec(self._params['traffic'],
622 self._start_traffic_api(-1)
624 def stop_cont_traffic(self):
625 """Stop continuous transmission and return results.
627 return self._stop_api_traffic()
629 def send_rfc2544_throughput(self, traffic=None, tests=1, duration=20,
631 """Send traffic per RFC2544 throughput test specifications.
633 See ITrafficGenerator for description
635 self._duration = duration
638 self._params['traffic'] = self.traffic_defaults.copy()
640 self._params['traffic'] = merge_spec(self._params['traffic'],
642 self._setup_json_config(tests, lossrate, '2544_throughput')
643 self._start_xena_2544()
644 self._wait_xena_2544_complete()
646 root = ET.parse(os.path.join(_CURR_DIR, "xena2544-report.xml")).getroot()
648 if settings.getValue('TRAFFICGEN_XENA_RFC2544_VERIFY'):
649 # make sure we have a pass before even trying the verify. No need
650 # to run verify on a failed iteration.
652 os.path.join(_CURR_DIR, "xena2544-report.xml")).getroot()
653 if root[0][1][0].get('TestState') == "FAIL":
654 self._logger.info('Test failed, skipping verify')
655 return Xena._create_throughput_result(root)
657 # record the previous settings so we can revert to them if needed to
658 # run the binary search again if the verify fails.
660 old_duration = self._duration
661 old_min = settings.getValue('TRAFFICGEN_XENA_2544_TPUT_MIN_VALUE')
663 # record the original values to restore after execution
664 orig_min = settings.getValue('TRAFFICGEN_XENA_2544_TPUT_MIN_VALUE')
665 orig_max = settings.getValue('TRAFFICGEN_XENA_2544_TPUT_MAX_VALUE')
666 orig_init = settings.getValue('TRAFFICGEN_XENA_2544_TPUT_INIT_VALUE')
668 for attempt in range(
669 1, settings.getValue(
670 'TRAFFICGEN_XENA_RFC2544_MAXIMUM_VERIFY_ATTEMPTS')+1):
671 self._logger.info('Running verify attempt %s', attempt)
672 # get the last pass tx rate from the binary search
673 pass_rate = float(root[0][1][0].get('TotalTxRatePcnt'))
674 # run a one pass rfc2544 with the pass rate to see if it passes
675 # the verify duration
677 'TRAFFICGEN_XENA_2544_TPUT_INIT_VALUE', pass_rate)
679 'TRAFFICGEN_XENA_2544_TPUT_MIN_VALUE', pass_rate)
681 'TRAFFICGEN_XENA_2544_TPUT_MAX_VALUE', pass_rate)
682 self.start_rfc2544_throughput(
683 traffic, 1, settings.getValue(
684 'TRAFFICGEN_XENA_RFC2544_VERIFY_DURATION'), lossrate)
685 self.wait_rfc2544_throughput()
687 os.path.join(_CURR_DIR, "xena2544-report.xml")).getroot()
689 # If it passed, report the number of lost frames and exit the
691 if root[0][1][0].get('TestState') == "PASS":
692 self._logger.info('Verify passed, packets lost = %s',
693 root[0][1][0].get('TotalLossFrames'))
695 elif attempt < settings.getValue(
696 'TRAFFICGEN_XENA_RFC2544_MAXIMUM_VERIFY_ATTEMPTS'):
698 'Verify failed, resuming binary search, packets lost = %s',
699 root[0][1][0].get('TotalLossFrames'))
701 'TRAFFICGEN_XENA_2544_TPUT_MAX_VALUE',
702 pass_rate - float(settings.getValue(
703 'TRAFFICGEN_XENA_2544_TPUT_VALUE_RESOLUTION')))
704 if settings.getValue(
705 'TRAFFICGEN_XENA_RFC2544_BINARY_RESTART_SMART_SEARCH'):
707 'TRAFFICGEN_XENA_2544_TPUT_INIT_VALUE',
708 (pass_rate - float(old_min)) / 2)
711 'TRAFFICGEN_XENA_2544_TPUT_INIT_VALUE',
712 pass_rate - float(settings.getValue(
713 'TRAFFICGEN_XENA_2544_TPUT_VALUE_RESOLUTION')))
715 'TRAFFICGEN_XENA_2544_TPUT_MIN_VALUE', old_min)
717 'RFC2544 Initial rate: %s',
718 settings.getValue('TRAFFICGEN_XENA_2544_TPUT_INIT_VALUE'))
720 'RFC2544 Maximum rate: %s',
721 settings.getValue('TRAFFICGEN_XENA_2544_TPUT_MAX_VALUE'))
723 'RFC2544 Minimum rate: %s',
724 settings.getValue('TRAFFICGEN_XENA_2544_TPUT_MIN_VALUE'))
725 self._duration = old_duration
726 self.start_rfc2544_throughput(
727 traffic, old_tests, self._duration, lossrate)
728 self.wait_rfc2544_throughput()
730 os.path.join(_CURR_DIR, "xena2544-report.xml")).getroot()
733 'Maximum number of verify attempts reached. Reporting last result')
735 #restore original values
736 settings.setValue('TRAFFICGEN_XENA_2544_TPUT_MIN_VALUE', orig_min)
737 settings.setValue('TRAFFICGEN_XENA_2544_TPUT_MAX_VALUE', orig_max)
738 settings.setValue('TRAFFICGEN_XENA_2544_TPUT_INIT_VALUE', orig_init)
740 return Xena._create_throughput_result(root)
742 def start_rfc2544_throughput(self, traffic=None, tests=1, duration=20,
744 """Non-blocking version of 'send_rfc2544_throughput'.
746 See ITrafficGenerator for description
748 self._duration = duration
750 self._params['traffic'] = self.traffic_defaults.copy()
752 self._params['traffic'] = merge_spec(self._params['traffic'],
754 self._setup_json_config(tests, lossrate, '2544_throughput')
755 self._start_xena_2544()
757 def wait_rfc2544_throughput(self):
758 """Wait for and return results of RFC2544 test.
760 See ITrafficGenerator for description
762 self._wait_xena_2544_complete()
763 root = ET.parse(os.path.join(_CURR_DIR, "xena2544-report.xml")).getroot()
764 return Xena._create_throughput_result(root)
766 def send_rfc2544_back2back(self, traffic=None, tests=1, duration=20,
768 """Send traffic per RFC2544 back2back test specifications.
770 See ITrafficGenerator for description
772 self._duration = duration
775 self._params['traffic'] = self.traffic_defaults.copy()
777 self._params['traffic'] = merge_spec(self._params['traffic'],
779 self._setup_json_config(tests, lossrate, '2544_b2b')
780 self._start_xena_2544()
781 self._wait_xena_2544_complete()
782 root = ET.parse(os.path.join(_CURR_DIR, "xena2544-report.xml")).getroot()
783 return Xena._create_throughput_result(root)
785 def start_rfc2544_back2back(self, traffic=None, tests=1, duration=20,
787 """Non-blocking version of 'send_rfc2544_back2back'.
789 See ITrafficGenerator for description
791 self._duration = duration
793 self._params['traffic'] = self.traffic_defaults.copy()
795 self._params['traffic'] = merge_spec(self._params['traffic'],
797 self._setup_json_config(tests, lossrate, '2544_b2b')
798 self._start_xena_2544()
800 def wait_rfc2544_back2back(self):
801 """Wait and set results of RFC2544 test.
803 self._wait_xena_2544_complete()
804 root = ET.parse(os.path.join(_CURR_DIR, "xena2544-report.xml")).getroot()
805 return Xena._create_throughput_result(root)
808 if __name__ == "__main__":