Xena_cont_accuracy: Modify continuous from duration to packet limit
[vswitchperf.git] / tools / pkt_gen / xena / xena.py
1 # Copyright 2016 Red Hat Inc & Xena Networks.
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 # Contributors:
16 #   Rick Alongi, Red Hat Inc.
17 #   Amit Supugade, Red Hat Inc.
18 #   Dan Amzulescu, Xena Networks
19 #   Christian Trautman, Red Hat Inc.
20
21 """
22 Xena Traffic Generator Model
23 """
24
25 # python imports
26 import binascii
27 import logging
28 import os
29 import subprocess
30 import sys
31 from time import sleep
32 import xml.etree.ElementTree as ET
33 from collections import OrderedDict
34 # scapy imports
35 import scapy.layers.inet as inet
36
37 # VSPerf imports
38 from conf import settings
39 from core.results.results_constants import ResultsConstants
40 from tools.pkt_gen.trafficgen.trafficgenhelper import (
41     TRAFFIC_DEFAULTS,
42     merge_spec)
43 from tools.pkt_gen.trafficgen.trafficgen import ITrafficGenerator
44
45 # Xena module imports
46 from tools.pkt_gen.xena.xena_json import XenaJSON
47 from tools.pkt_gen.xena.XenaDriver import (
48     aggregate_stats,
49     line_percentage,
50     XenaSocketDriver,
51     XenaManager,
52     )
53
54
55 class Xena(ITrafficGenerator):
56     """
57     Xena Traffic generator wrapper class
58     """
59     _traffic_defaults = TRAFFIC_DEFAULTS.copy()
60     _logger = logging.getLogger(__name__)
61
62     def __init__(self):
63         self.mono_pipe = None
64         self.xmanager = None
65         self._params = {}
66         self._xsocket = None
67         self._duration = None
68         self.tx_stats = None
69         self.rx_stats = None
70         self._log_handle = None
71
72         user_home = os.path.expanduser('~')
73         self._log_path = '{}/Xena/Xena2544-2G/Logs/xena2544.log'.format(
74                 user_home)
75
76         # make the folder and log file if they doesn't exist
77         if not os.path.exists(self._log_path):
78             os.makedirs(os.path.dirname(self._log_path))
79
80         # empty the file contents
81         open(self._log_path, 'w').close()
82
83
84     @property
85     def traffic_defaults(self):
86         """Default traffic values.
87
88         These can be expected to be constant across traffic generators,
89         so no setter is provided. Changes to the structure or contents
90         will likely break traffic generator implementations or tests
91         respectively.
92         """
93         return self._traffic_defaults
94
95     @staticmethod
96     def _create_throughput_result(root):
97         """
98         Create the results based off the output xml file from the Xena2544.exe
99         execution
100         :param root: root dictionary from xml import
101         :return: Results Ordered dictionary based off ResultsConstants
102         """
103         # get the test type from the report file
104         test_type = root[0][1].get('TestType')
105         # set the version from the report file
106         settings.setValue('XENA_VERSION', root[0][0][1].get('GeneratedBy'))
107
108         if test_type == 'Throughput':
109             results = OrderedDict()
110             results[ResultsConstants.THROUGHPUT_RX_FPS] = float(
111                 root[0][1][0][0].get('PortRxPps')) + float(
112                     root[0][1][0][1].get('PortRxPps'))
113             results[ResultsConstants.THROUGHPUT_RX_MBPS] = (float(
114                 root[0][1][0][0].get('PortRxBpsL1')) + float(
115                     root[0][1][0][1].get('PortRxBpsL1')))/ 1000000
116             results[ResultsConstants.THROUGHPUT_RX_PERCENT] = (
117                 100 - float(root[0][1][0].get('TotalLossRatioPcnt'))) * float(
118                     root[0][1][0].get('TotalTxRatePcnt'))/100
119             results[ResultsConstants.TX_RATE_FPS] = root[0][1][0].get(
120                 'TotalTxRateFps')
121             results[ResultsConstants.TX_RATE_MBPS] = float(
122                 root[0][1][0].get('TotalTxRateBpsL1')) / 1000000
123             results[ResultsConstants.TX_RATE_PERCENT] = root[0][1][0].get(
124                 'TotalTxRatePcnt')
125             try:
126                 results[ResultsConstants.MIN_LATENCY_NS] = float(
127                     root[0][1][0][0].get('MinLatency')) * 1000
128             except ValueError:
129                 # Stats for latency returned as N/A so just post them
130                 results[ResultsConstants.MIN_LATENCY_NS] = root[0][1][0][0].get(
131                     'MinLatency')
132             try:
133                 results[ResultsConstants.MAX_LATENCY_NS] = float(
134                     root[0][1][0][0].get('MaxLatency')) * 1000
135             except ValueError:
136                 # Stats for latency returned as N/A so just post them
137                 results[ResultsConstants.MAX_LATENCY_NS] = root[0][1][0][0].get(
138                     'MaxLatency')
139             try:
140                 results[ResultsConstants.AVG_LATENCY_NS] = float(
141                     root[0][1][0][0].get('AvgLatency')) * 1000
142             except ValueError:
143                 # Stats for latency returned as N/A so just post them
144                 results[ResultsConstants.AVG_LATENCY_NS] = root[0][1][0][0].get(
145                     'AvgLatency')
146         elif test_type == 'Back2Back':
147             results = OrderedDict()
148
149             # Just mimic what Ixia does and only return the b2b frame count.
150             # This may change later once its decided the common results stats
151             # to be returned should be.
152             results[ResultsConstants.B2B_FRAMES] = root[0][1][0][0].get(
153                 'TotalTxBurstFrames')
154         else:
155             raise NotImplementedError('Unknown test type in report file.')
156
157         return results
158
159     def _build_packet_header(self, reverse=False):
160         """
161         Build a packet header based on traffic profile using scapy external
162         libraries.
163         :param reverse: Swap source and destination info when building header
164         :return: packet header in hex
165         """
166         srcmac = self._params['traffic']['l2'][
167             'srcmac'] if not reverse else self._params['traffic']['l2'][
168                 'dstmac']
169         dstmac = self._params['traffic']['l2'][
170             'dstmac'] if not reverse else self._params['traffic']['l2'][
171                 'srcmac']
172         srcip = self._params['traffic']['l3'][
173             'srcip'] if not reverse else self._params['traffic']['l3']['dstip']
174         dstip = self._params['traffic']['l3'][
175             'dstip'] if not reverse else self._params['traffic']['l3']['srcip']
176         layer2 = inet.Ether(src=srcmac, dst=dstmac)
177         layer3 = inet.IP(src=srcip, dst=dstip,
178                          proto=self._params['traffic']['l3']['proto'])
179         layer4 = inet.UDP(sport=self._params['traffic']['l4']['srcport'],
180                           dport=self._params['traffic']['l4']['dstport'])
181         if self._params['traffic']['vlan']['enabled']:
182             vlan = inet.Dot1Q(vlan=self._params['traffic']['vlan']['id'],
183                               prio=self._params['traffic']['vlan']['priority'],
184                               id=self._params['traffic']['vlan']['cfi'])
185         else:
186             vlan = None
187         packet = layer2/vlan/layer3/layer4 if vlan else layer2/layer3/layer4
188         packet_bytes = bytes(packet)
189         packet_hex = '0x' + binascii.hexlify(packet_bytes).decode('utf-8')
190         return packet_hex
191
192     def _create_api_result(self):
193         """
194         Create result dictionary per trafficgen specifications from socket API
195         stats. If stats are not available return values of 0.
196         :return: ResultsConstants as dictionary
197         """
198         # Handle each case of statistics based on if the data is available.
199         # This prevents uncaught exceptions when the stats aren't available.
200         result_dict = OrderedDict()
201         if self.tx_stats.data.get(self.tx_stats.pt_stream_keys[0]):
202             result_dict[ResultsConstants.TX_FRAMES] = self.tx_stats.data[
203                 self.tx_stats.pt_stream_keys[0]]['packets']
204             result_dict[ResultsConstants.TX_RATE_FPS] = self.tx_stats.data[
205                 self.tx_stats.pt_stream_keys[0]]['pps']
206             result_dict[ResultsConstants.TX_RATE_MBPS] = self.tx_stats.data[
207                 self.tx_stats.pt_stream_keys[0]]['bps'] / 1000000
208             result_dict[ResultsConstants.TX_BYTES] = self.tx_stats.data[
209                 self.tx_stats.pt_stream_keys[0]]['bytes']
210             # tx rate percent may need to be halved if bi directional
211             result_dict[ResultsConstants.TX_RATE_PERCENT] = line_percentage(
212                 self.xmanager.ports[0], self.tx_stats, self._duration,
213                 self._params['traffic']['l2']['framesize']) if \
214                 self._params['traffic']['bidir'] == 'False' else\
215                 line_percentage(
216                     self.xmanager.ports[0], self.tx_stats, self._duration,
217                     self._params['traffic']['l2']['framesize']) / 2
218         else:
219             self._logger.error('Transmit stats not available.')
220             result_dict[ResultsConstants.TX_FRAMES] = 0
221             result_dict[ResultsConstants.TX_RATE_FPS] = 0
222             result_dict[ResultsConstants.TX_RATE_MBPS] = 0
223             result_dict[ResultsConstants.TX_BYTES] = 0
224             result_dict[ResultsConstants.TX_RATE_PERCENT] = 0
225
226         if self.rx_stats.data.get('pr_tpldstraffic'):
227             result_dict[ResultsConstants.RX_FRAMES] = self.rx_stats.data[
228                 'pr_tpldstraffic']['0']['packets']
229             result_dict[
230                 ResultsConstants.THROUGHPUT_RX_FPS] = self.rx_stats.data[
231                     'pr_tpldstraffic']['0']['pps']
232             result_dict[
233                 ResultsConstants.THROUGHPUT_RX_MBPS] = self.rx_stats.data[
234                     'pr_tpldstraffic']['0']['bps'] / 1000000
235             result_dict[ResultsConstants.RX_BYTES] = self.rx_stats.data[
236                 'pr_tpldstraffic']['0']['bytes']
237             # throughput percent may need to be halved if bi directional
238             result_dict[
239                 ResultsConstants.THROUGHPUT_RX_PERCENT] = line_percentage(
240                     self.xmanager.ports[1], self.rx_stats, self._duration,
241                     self._params['traffic']['l2']['framesize']) if \
242                 self._params['traffic']['bidir'] == 'False' else \
243                 line_percentage(
244                     self.xmanager.ports[1], self.rx_stats, self._duration,
245                     self._params['traffic']['l2']['framesize']) / 2
246
247         else:
248             self._logger.error('Receive stats not available.')
249             result_dict[ResultsConstants.RX_FRAMES] = 0
250             result_dict[ResultsConstants.THROUGHPUT_RX_FPS] = 0
251             result_dict[ResultsConstants.THROUGHPUT_RX_MBPS] = 0
252             result_dict[ResultsConstants.RX_BYTES] = 0
253             result_dict[ResultsConstants.THROUGHPUT_RX_PERCENT] = 0
254
255         if self.rx_stats.data.get('pr_tplderrors'):
256             result_dict[ResultsConstants.PAYLOAD_ERR] = self.rx_stats.data[
257                 'pr_tplderrors']['0']['pld']
258             result_dict[ResultsConstants.SEQ_ERR] = self.rx_stats.data[
259                 'pr_tplderrors']['0']['seq']
260         else:
261             result_dict[ResultsConstants.PAYLOAD_ERR] = 0
262             result_dict[ResultsConstants.SEQ_ERR] = 0
263
264         if self.rx_stats.data.get('pr_tpldlatency'):
265             result_dict[ResultsConstants.MIN_LATENCY_NS] = self.rx_stats.data[
266                 'pr_tpldlatency']['0']['min']
267             result_dict[ResultsConstants.MAX_LATENCY_NS] = self.rx_stats.data[
268                 'pr_tpldlatency']['0']['max']
269             result_dict[ResultsConstants.AVG_LATENCY_NS] = self.rx_stats.data[
270                 'pr_tpldlatency']['0']['avg']
271         else:
272             result_dict[ResultsConstants.MIN_LATENCY_NS] = 0
273             result_dict[ResultsConstants.MAX_LATENCY_NS] = 0
274             result_dict[ResultsConstants.AVG_LATENCY_NS] = 0
275
276         return result_dict
277
278     def _setup_json_config(self, tests, loss_rate, testtype=None):
279         """
280         Create a 2bUsed json file that will be used for xena2544.exe execution.
281         :param tests: Number of tests
282         :param loss_rate: The acceptable loss rate as float
283         :param testtype: Either '2544_b2b' or '2544_throughput' as string
284         :return: None
285         """
286         try:
287             j_file = XenaJSON('./tools/pkt_gen/xena/profiles/baseconfig.x2544')
288             j_file.set_chassis_info(
289                 settings.getValue('TRAFFICGEN_XENA_IP'),
290                 settings.getValue('TRAFFICGEN_XENA_PASSWORD')
291             )
292             j_file.set_port(0, settings.getValue('TRAFFICGEN_XENA_MODULE1'),
293                             settings.getValue('TRAFFICGEN_XENA_PORT1'))
294             j_file.set_port(1, settings.getValue('TRAFFICGEN_XENA_MODULE2'),
295                             settings.getValue('TRAFFICGEN_XENA_PORT2'))
296             j_file.set_port_ip_v4(
297                 0, settings.getValue("TRAFFICGEN_XENA_PORT0_IP"),
298                 settings.getValue("TRAFFICGEN_XENA_PORT0_CIDR"),
299                 settings.getValue("TRAFFICGEN_XENA_PORT0_GATEWAY"))
300             j_file.set_port_ip_v4(
301                 1, settings.getValue("TRAFFICGEN_XENA_PORT1_IP"),
302                 settings.getValue("TRAFFICGEN_XENA_PORT1_CIDR"),
303                 settings.getValue("TRAFFICGEN_XENA_PORT1_GATEWAY"))
304
305             if testtype == '2544_throughput':
306                 j_file.set_test_options_tput(
307                     packet_sizes=self._params['traffic']['l2']['framesize'],
308                     iterations=tests, loss_rate=loss_rate,
309                     duration=self._duration, micro_tpld=True if self._params[
310                         'traffic']['l2']['framesize'] == 64 else False)
311                 j_file.enable_throughput_test()
312                 j_file.modify_2544_tput_options(
313                     settings.getValue('TRAFFICGEN_XENA_2544_TPUT_INIT_VALUE'),
314                     settings.getValue('TRAFFICGEN_XENA_2544_TPUT_MIN_VALUE'),
315                     settings.getValue('TRAFFICGEN_XENA_2544_TPUT_MAX_VALUE'),
316                     settings.getValue(
317                         'TRAFFICGEN_XENA_2544_TPUT_VALUE_RESOLUTION'),
318                     settings.getValue(
319                         'TRAFFICGEN_XENA_2544_TPUT_USEPASS_THRESHHOLD'),
320                     settings.getValue(
321                         'TRAFFICGEN_XENA_2544_TPUT_PASS_THRESHHOLD')
322                 )
323
324             elif testtype == '2544_b2b':
325                 j_file.set_test_options_back2back(
326                     packet_sizes=self._params['traffic']['l2']['framesize'],
327                     iterations=tests, duration=self._duration,
328                     startvalue=self._params['traffic']['frame_rate'],
329                     endvalue=self._params['traffic']['frame_rate'],
330                     micro_tpld=True if self._params[
331                         'traffic']['l2']['framesize'] == 64 else False)
332                 j_file.enable_back2back_test()
333
334             j_file.set_header_layer2(
335                 dst_mac=self._params['traffic']['l2']['dstmac'],
336                 src_mac=self._params['traffic']['l2']['srcmac'])
337             j_file.set_header_layer3(
338                 src_ip=self._params['traffic']['l3']['srcip'],
339                 dst_ip=self._params['traffic']['l3']['dstip'],
340                 protocol=self._params['traffic']['l3']['proto'])
341             j_file.set_header_layer4_udp(
342                 source_port=self._params['traffic']['l4']['srcport'],
343                 destination_port=self._params['traffic']['l4']['dstport'])
344             if self._params['traffic']['vlan']['enabled']:
345                 j_file.set_header_vlan(
346                     vlan_id=self._params['traffic']['vlan']['id'],
347                     id=self._params['traffic']['vlan']['cfi'],
348                     prio=self._params['traffic']['vlan']['priority'])
349             j_file.add_header_segments(
350                 flows=self._params['traffic']['multistream'],
351                 multistream_layer=self._params['traffic']['stream_type'])
352             # set duplex mode
353             if self._params['traffic']['bidir'] == "True":
354                 j_file.set_topology_mesh()
355             else:
356                 j_file.set_topology_blocks()
357
358             j_file.write_config('./tools/pkt_gen/xena/profiles/2bUsed.x2544')
359         except Exception as exc:
360             self._logger.exception("Error during Xena JSON setup: %s", exc)
361             raise
362
363     def _start_traffic_api(self, packet_limit):
364         """
365         Start the Xena traffic using the socket API driver
366         :param packet_limit: packet limit for stream, set to -1 for no limit
367         :return: None
368         """
369         if not self.xmanager:
370             self._xsocket = XenaSocketDriver(
371                 settings.getValue('TRAFFICGEN_XENA_IP'))
372             self.xmanager = XenaManager(
373                 self._xsocket, settings.getValue('TRAFFICGEN_XENA_USER'),
374                 settings.getValue('TRAFFICGEN_XENA_PASSWORD'))
375
376         # for the report file version info ask the chassis directly for its
377         # software versions
378         settings.setValue('XENA_VERSION', 'XENA Socket API - {}'.format(
379             self.xmanager.get_version()))
380
381         if not len(self.xmanager.ports):
382             self.xmanager.ports[0] = self.xmanager.add_module_port(
383                 settings.getValue('TRAFFICGEN_XENA_MODULE1'),
384                 settings.getValue('TRAFFICGEN_XENA_PORT1'))
385             if not self.xmanager.ports[0].reserve_port():
386                 self._logger.error(
387                     'Unable to reserve port 0. Please release Xena Port')
388
389         if len(self.xmanager.ports) < 2:
390             self.xmanager.ports[1] = self.xmanager.add_module_port(
391                 settings.getValue('TRAFFICGEN_XENA_MODULE2'),
392                 settings.getValue('TRAFFICGEN_XENA_PORT2'))
393             if not self.xmanager.ports[1].reserve_port():
394                 self._logger.error(
395                     'Unable to reserve port 1. Please release Xena Port')
396
397         # Clear port configuration for a clean start
398         self.xmanager.ports[0].reset_port()
399         self.xmanager.ports[1].reset_port()
400         self.xmanager.ports[0].clear_stats()
401         self.xmanager.ports[1].clear_stats()
402
403         # set the port IP from the conf file
404         self.xmanager.ports[0].set_port_ip(
405             settings.getValue('TRAFFICGEN_XENA_PORT0_IP'),
406             settings.getValue('TRAFFICGEN_XENA_PORT0_CIDR'),
407             settings.getValue('TRAFFICGEN_XENA_PORT0_GATEWAY'))
408         self.xmanager.ports[1].set_port_ip(
409             settings.getValue('TRAFFICGEN_XENA_PORT1_IP'),
410             settings.getValue('TRAFFICGEN_XENA_PORT1_CIDR'),
411             settings.getValue('TRAFFICGEN_XENA_PORT1_GATEWAY'))
412
413         def setup_stream(stream, port, payload_id, flip_addr=False):
414             """
415             Helper function to configure streams.
416             :param stream: Stream object from XenaDriver module
417             :param port: Port object from XenaDriver module
418             :param payload_id: payload ID as int
419             :param flip_addr: Boolean if the source and destination addresses
420             should be flipped.
421             :return: None
422             """
423             stream.set_on()
424             if packet_limit != -1:
425                 stream.set_packet_limit(packet_limit)
426             else:
427                 speed = port.get_port_speed() / 8  # convert to bytes
428                 gap = port.get_inter_frame_gap()
429                 pkt_size = self._params['traffic']['l2']['framesize']
430                 packets = int(((speed / (pkt_size + gap)) * self._duration) *
431                               (self._params['traffic']['frame_rate'] / 100))
432                 stream.set_packet_limit(packets)
433
434             port.set_port_arp_reply(on=True)
435             port.set_port_arp_reply(on=True, v6=True)
436             port.set_port_ping_reply(on=True)
437             port.set_port_ping_reply(on=True, v6=True)
438
439             stream.set_rate_fraction(
440                 10000 * self._params['traffic']['frame_rate'])
441             stream.set_packet_header(self._build_packet_header(
442                 reverse=flip_addr))
443             stream.set_header_protocol(
444                 'ETHERNET VLAN IP UDP' if self._params['traffic']['vlan'][
445                     'enabled'] else 'ETHERNET IP UDP')
446             stream.set_packet_length(
447                 'fixed', self._params['traffic']['l2']['framesize'],
448                 self._params['traffic']['l2']['framesize'])
449             stream.set_packet_payload('incrementing', '0x00')
450             stream.set_payload_id(payload_id)
451             port.set_port_time_limit(0)
452
453             if self._params['traffic']['l2']['framesize'] == 64:
454                 # set micro tpld
455                 port.micro_tpld_enable()
456
457             if self._params['traffic']['multistream']:
458                 stream.enable_multistream(
459                     flows=self._params['traffic']['multistream'],
460                     layer=self._params['traffic']['stream_type'])
461
462         s1_p0 = self.xmanager.ports[0].add_stream()
463         setup_stream(s1_p0, self.xmanager.ports[0], 0)
464
465         if self._params['traffic']['bidir'] == 'True':
466             s1_p1 = self.xmanager.ports[1].add_stream()
467             setup_stream(s1_p1, self.xmanager.ports[1], 1, flip_addr=True)
468
469         if not self.xmanager.ports[0].traffic_on():
470             self._logger.error(
471                 "Failure to start port 0. Check settings and retry.")
472         if self._params['traffic']['bidir'] == 'True':
473             if not self.xmanager.ports[1].traffic_on():
474                 self._logger.error(
475                     "Failure to start port 1. Check settings and retry.")
476         sleep(self._duration + 1)
477         # getting results
478         if self._params['traffic']['bidir'] == 'True':
479             # need to aggregate out both ports stats and assign that data
480             self.rx_stats = self.xmanager.ports[1].get_rx_stats()
481             self.tx_stats = self.xmanager.ports[0].get_tx_stats()
482             self.tx_stats.data = aggregate_stats(
483                 self.tx_stats.data,
484                 self.xmanager.ports[1].get_tx_stats().data)
485             self.rx_stats.data = aggregate_stats(
486                 self.rx_stats.data,
487                 self.xmanager.ports[0].get_rx_stats().data)
488         else:
489             # no need to aggregate, just grab the appropriate port stats
490             self.tx_stats = self.xmanager.ports[0].get_tx_stats()
491             self.rx_stats = self.xmanager.ports[1].get_rx_stats()
492         sleep(1)
493
494     def _start_xena_2544(self):
495         """
496         Start the xena2544 exe.
497         :return: None
498         """
499         args = ["mono", "./tools/pkt_gen/xena/Xena2544.exe", "-c",
500                 "./tools/pkt_gen/xena/profiles/2bUsed.x2544", "-e", "-r",
501                 "./tools/pkt_gen/xena", "-u",
502                 settings.getValue('TRAFFICGEN_XENA_USER')]
503         # Sometimes Xena2544.exe completes, but mono holds the process without
504         # releasing it, this can cause a deadlock of the main thread. Use the
505         # xena log file as a way to detect this.
506         self._log_handle = open(self._log_path, 'r')
507         # read the contents of the log before we start so the next read in the
508         # wait method are only looking at the text from this test instance
509         self._log_handle.read()
510         self.mono_pipe = subprocess.Popen(args, stdout=sys.stdout)
511
512     def _wait_xena_2544_complete(self):
513         """
514         Wait for Xena2544.exe completion.
515         :return: None
516         """
517         data = ''
518         while True:
519             try:
520                 self.mono_pipe.wait(60)
521                 self._log_handle.close()
522                 break
523             except subprocess.TimeoutExpired:
524                 # check the log to see if Xena2544 has completed and mono is
525                 # deadlocked.
526                 data += self._log_handle.read()
527                 if 'TestCompletedSuccessfully' in data:
528                     self._log_handle.close()
529                     self.mono_pipe.terminate()
530                     break
531
532     def _stop_api_traffic(self):
533         """
534         Stop traffic through the socket API
535         :return: Return results from _create_api_result method
536         """
537         self.xmanager.ports[0].traffic_off()
538         if self._params['traffic']['bidir'] == 'True':
539             self.xmanager.ports[1].traffic_off()
540         sleep(5)
541
542         stat = self._create_api_result()
543         self.disconnect()
544         return stat
545
546     def connect(self):
547         self._logger.debug('Connect')
548         return self
549
550     def disconnect(self):
551         """Disconnect from the traffic generator.
552
553         As with :func:`connect`, this function is optional.
554
555
556         Where implemented, this function should raise an exception on
557         failure.
558
559         :returns: None
560         """
561         self._logger.debug('disconnect')
562         if self.xmanager:
563             self.xmanager.disconnect()
564             self.xmanager = None
565
566         if self._xsocket:
567             self._xsocket.disconnect()
568             self._xsocket = None
569
570     def send_burst_traffic(self, traffic=None, numpkts=100, duration=20):
571         """Send a burst of traffic.
572
573         See ITrafficGenerator for description
574         """
575         self._duration = duration
576         self._params.clear()
577         self._params['traffic'] = self.traffic_defaults.copy()
578         if traffic:
579             self._params['traffic'] = merge_spec(self._params['traffic'],
580                                                  traffic)
581         self._start_traffic_api(numpkts)
582         return self._stop_api_traffic()
583
584     def send_cont_traffic(self, traffic=None, duration=20):
585         """Send a continuous flow of traffic.
586
587         See ITrafficGenerator for description
588         """
589         self._duration = duration
590
591         self._params.clear()
592         self._params['traffic'] = self.traffic_defaults.copy()
593         if traffic:
594             self._params['traffic'] = merge_spec(self._params['traffic'],
595                                                  traffic)
596         self._start_traffic_api(-1)
597         return self._stop_api_traffic()
598
599     def start_cont_traffic(self, traffic=None, duration=20):
600         """Non-blocking version of 'send_cont_traffic'.
601
602         See ITrafficGenerator for description
603         """
604         self._duration = duration
605
606         self._params.clear()
607         self._params['traffic'] = self.traffic_defaults.copy()
608         if traffic:
609             self._params['traffic'] = merge_spec(self._params['traffic'],
610                                                  traffic)
611         self._start_traffic_api(-1)
612
613     def stop_cont_traffic(self):
614         """Stop continuous transmission and return results.
615         """
616         return self._stop_api_traffic()
617
618     def send_rfc2544_throughput(self, traffic=None, tests=1, duration=20,
619                                 lossrate=0.0):
620         """Send traffic per RFC2544 throughput test specifications.
621
622         See ITrafficGenerator for description
623         """
624         self._duration = duration
625
626         self._params.clear()
627         self._params['traffic'] = self.traffic_defaults.copy()
628         if traffic:
629             self._params['traffic'] = merge_spec(self._params['traffic'],
630                                                  traffic)
631         self._setup_json_config(tests, lossrate, '2544_throughput')
632         self._start_xena_2544()
633         self._wait_xena_2544_complete()
634
635         root = ET.parse(r'./tools/pkt_gen/xena/xena2544-report.xml').getroot()
636         return Xena._create_throughput_result(root)
637
638     def start_rfc2544_throughput(self, traffic=None, tests=1, duration=20,
639                                  lossrate=0.0):
640         """Non-blocking version of 'send_rfc2544_throughput'.
641
642         See ITrafficGenerator for description
643         """
644         self._duration = duration
645         self._params.clear()
646         self._params['traffic'] = self.traffic_defaults.copy()
647         if traffic:
648             self._params['traffic'] = merge_spec(self._params['traffic'],
649                                                  traffic)
650         self._setup_json_config(tests, lossrate, '2544_throughput')
651         self._start_xena_2544()
652
653     def wait_rfc2544_throughput(self):
654         """Wait for and return results of RFC2544 test.
655
656         See ITrafficGenerator for description
657         """
658         self._wait_xena_2544_complete()
659         root = ET.parse(r'./tools/pkt_gen/xena/xena2544-report.xml').getroot()
660         return Xena._create_throughput_result(root)
661
662     def send_rfc2544_back2back(self, traffic=None, tests=1, duration=20,
663                                lossrate=0.0):
664         """Send traffic per RFC2544 back2back test specifications.
665
666         See ITrafficGenerator for description
667         """
668         self._duration = duration
669
670         self._params.clear()
671         self._params['traffic'] = self.traffic_defaults.copy()
672         if traffic:
673             self._params['traffic'] = merge_spec(self._params['traffic'],
674                                                  traffic)
675         self._setup_json_config(tests, lossrate, '2544_b2b')
676         self._start_xena_2544()
677         self._wait_xena_2544_complete()
678         root = ET.parse(r'./tools/pkt_gen/xena/xena2544-report.xml').getroot()
679         return Xena._create_throughput_result(root)
680
681     def start_rfc2544_back2back(self, traffic=None, tests=1, duration=20,
682                                 lossrate=0.0):
683         """Non-blocking version of 'send_rfc2544_back2back'.
684
685         See ITrafficGenerator for description
686         """
687         self._duration = duration
688         self._params.clear()
689         self._params['traffic'] = self.traffic_defaults.copy()
690         if traffic:
691             self._params['traffic'] = merge_spec(self._params['traffic'],
692                                                  traffic)
693         self._setup_json_config(tests, lossrate, '2544_b2b')
694         self._start_xena_2544()
695
696     def wait_rfc2544_back2back(self):
697         """Wait and set results of RFC2544 test.
698         """
699         self._wait_xena_2544_complete()
700         root = ET.parse(r'./tools/pkt_gen/xena/xena2544-report.xml').getroot()
701         return Xena._create_throughput_result(root)
702
703
704 if __name__ == "__main__":
705     pass
706