Update of VPP_STABLE_VER files and DPDK_STABLE_VER file
[csit.git] / resources / tools / t-rex / t-rex-stateless.py
1 #!/usr/bin/python
2
3 # Copyright (c) 2016 Cisco and/or its affiliates.
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at:
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 """This script uses T-REX stateless API to drive t-rex instance.
17
18 Requirements:
19 - T-REX: https://github.com/cisco-system-traffic-generator/trex-core
20  - compiled and running T-REX process (eg. ./t-rex-64 -i -c 4)
21  - trex_stl_lib.api library
22 - Script must be executed on a node with T-REX instance
23 - 2 interfaces must be configured in configuretion file /etc/trex_cfg.yaml
24
25 ##################### Example of /etc/trex_cfg.yaml ##########################
26 - port_limit      : 2 # numbers of ports to use
27   version         : 2
28   interfaces      : ["84:00.0","84:00.1"] # PCI address of interfaces
29   port_info       :  # set eth mac addr
30           - dest_mac        :   [0x90,0xe2,0xba,0x1f,0x97,0xd5]  # port 0
31             src_mac         :   [0x90,0xe2,0xba,0x1f,0x97,0xd4]
32           - dest_mac        :   [0x90,0xe2,0xba,0x1f,0x97,0xd4]  # port 1
33             src_mac         :   [0x90,0xe2,0xba,0x1f,0x97,0xd5]
34 ##############################################################################
35
36 Functionality:
37 1. Configure traffic on running T-REX instance
38 2. Clear statistics on all ports
39 3. Ctart traffic with specified duration
40 4. Print statistics to stdout
41
42 """
43
44 import argparse
45 import json
46 import socket
47 import string
48 import struct
49 import sys
50
51 sys.path.insert(0, "/opt/trex-core-2.22/scripts/automation/"+\
52                    "trex_control_plane/stl/")
53 from trex_stl_lib.api import *
54
55 stream_table = {'IMIX_v4_1': [{'size': 64, 'pps': 28, 'isg':0},
56                               {'size': 570, 'pps': 16, 'isg':0.1},
57                               {'size': 1518, 'pps': 4, 'isg':0.2}]
58                }
59
60 def generate_payload(length):
61     """Generate payload.
62
63     :param length: Length of payload.
64     :type length: int
65     :return: Payload filled with chars.
66     :rtype string
67     """
68
69     word = ''
70     alphabet_size = len(string.letters)
71     for i in range(length):
72         word += string.letters[(i % alphabet_size)]
73
74     return word
75
76
77 def get_start_end_ipv6(start_ip, end_ip):
78     """Get start and end host from IPv6 as integer.
79
80     :param start_ip: Start IPv6.
81     :param end_ip: End IPv6.
82     :type start_ip: string
83     :type end_ip: string
84     :return: Start host, end host.
85     :rtype int
86     """
87
88     try:
89         ip1 = socket.inet_pton(socket.AF_INET6, start_ip)
90         ip2 = socket.inet_pton(socket.AF_INET6, end_ip)
91
92         hi1, lo1 = struct.unpack('!QQ', ip1)
93         hi2, lo2 = struct.unpack('!QQ', ip2)
94
95         if ((hi1 << 64) | lo1) > ((hi2 << 64) | lo2):
96             print "IPv6: start_ip is greater then end_ip"
97             sys.exit(2)
98
99         max_p1 = abs(int(lo1) - int(lo2))
100         base_p1 = lo1
101     except AddressValueError as ex_error:
102         print ex_error
103         sys.exit(2)
104
105     return base_p1, max_p1
106
107 def create_streams_v46(base_pkt_a, base_pkt_b, vm1, vm2, frame_size):
108     """Create STLStream streams
109
110     :param base_pkt_a: Base packet a for stream_a
111     :param base_pkt_b: Base packet b for stream_b
112     :param vm1: vm for stream_a
113     :param vm2: vm for stream_b
114     :param frame_size: frame size or name of traffic profile
115     :type base_pkt_a: Eth (scapy)
116     :type base_pkt_b: Eth (scapy)
117     :type vm1: STLScVmRaw
118     :type vm2: STLScVmRaw
119     :frame_size: int or string
120     :return: stream_a, stream_b, stream_a_latency, stream_b_latency
121     :rtype: STLStream, STLStream, STLStream, STLStream
122     """
123
124     if type(frame_size) is int:
125
126         fsize_no_fcs = frame_size - 4 # no FCS
127         pkt_a = STLPktBuilder(pkt=base_pkt_a/generate_payload(
128             max(0, fsize_no_fcs-len(base_pkt_a))), vm=vm1)
129         pkt_b = STLPktBuilder(pkt=base_pkt_b/generate_payload(
130             max(0, fsize_no_fcs-len(base_pkt_b))), vm=vm2)
131         pkt_lat_a = STLPktBuilder(pkt=base_pkt_a/generate_payload(
132             max(0, fsize_no_fcs-len(base_pkt_a))))
133         pkt_lat_b = STLPktBuilder(pkt=base_pkt_b/generate_payload(
134             max(0, fsize_no_fcs-len(base_pkt_b))))
135         lat_stream1 = STLStream(packet=pkt_lat_a,
136                                 flow_stats=STLFlowLatencyStats(pg_id=0),
137                                 mode=STLTXCont(pps=9000))
138         # second traffic stream with a phase of 10ns (inter stream gap)
139         lat_stream2 = STLStream(packet=pkt_lat_b,
140                                 isg=10.0,
141                                 flow_stats=STLFlowLatencyStats(pg_id=1),
142                                 mode=STLTXCont(pps=9000))
143
144         stream1 = STLStream(packet=pkt_a,
145                             mode=STLTXCont(pps=9000))
146         # second traffic stream with a phase of 10ns (inter stream gap)
147         stream2 = STLStream(packet=pkt_b,
148                             isg=10.0,
149                             mode=STLTXCont(pps=9000))
150     elif type(frame_size) is str:
151         lat_stream1 = []
152         lat_stream2 = []
153         stream1 = []
154         stream2 = []
155
156         for x in stream_table[frame_size]:
157             fsize_no_fcs = x['size'] - 4 # no FCS
158             pkt_a = STLPktBuilder(pkt=base_pkt_a/generate_payload(
159                 max(0, fsize_no_fcs-len(base_pkt_a))), vm=vm1)
160             pkt_b = STLPktBuilder(pkt=base_pkt_b/generate_payload(
161                 max(0, fsize_no_fcs-len(base_pkt_b))), vm=vm2)
162
163             stream1.append(STLStream(packet=pkt_a,
164                                isg=x['isg'],
165                                mode=STLTXCont(pps=x['pps'])))
166             stream2.append(STLStream(packet=pkt_b,
167                                isg=x['isg'],
168                                mode=STLTXCont(pps=x['pps'])))
169
170     else:
171         raise ValueError("Unknown frame_size type")
172
173     return (stream1, stream2, lat_stream1, lat_stream2)
174
175
176 def create_streams(traffic_options, frame_size=64):
177     """Create two IP packets to be used in stream.
178
179     :param traffic_options: Parameters for packets.
180     :param frame_size: Size of L2 frame.
181     :type traffic_options: dict
182     :type frame_size: int
183     :return: Packet instances.
184     :rtype: Tuple of STLPktBuilder
185     """
186
187     if type(frame_size) is int and frame_size < 64:
188         print_error("Frame min. size is 64B")
189         sys.exit(1)
190
191     p1_src_start_ip = traffic_options['p1_src_start_ip']
192     p1_src_end_ip = traffic_options['p1_src_end_ip']
193     p1_dst_start_ip = traffic_options['p1_dst_start_ip']
194     p2_src_start_ip = traffic_options['p2_src_start_ip']
195     p2_src_end_ip = traffic_options['p2_src_end_ip']
196     p2_dst_start_ip = traffic_options['p2_dst_start_ip']
197
198     p1_dst_end_ip = traffic_options['p1_dst_end_ip']
199     p2_dst_end_ip = traffic_options['p2_dst_end_ip']
200
201     try:
202         p1_src_start_udp_port = traffic_options['p1_src_start_udp_port']
203         p1_src_end_udp_port = traffic_options['p1_src_end_udp_port']
204         p1_dst_start_udp_port = traffic_options['p1_dst_start_udp_port']
205         p2_src_start_udp_port = traffic_options['p2_src_start_udp_port']
206         p2_dst_start_udp_port = traffic_options['p2_dst_start_udp_port']
207         p2_dst_end_udp_port = traffic_options['p2_dst_end_udp_port']
208         ports_defined = True
209     except KeyError:
210         ports_defined = False
211
212     if ports_defined:
213         base_pkt_a = (Ether() /
214                       IP(src=p1_src_start_ip, dst=p1_dst_start_ip, proto=17) /
215                       UDP(sport=int(p1_src_start_udp_port),
216                           dport=int(p1_dst_start_udp_port)))
217         base_pkt_b = (Ether() /
218                       IP(src=p2_src_start_ip, dst=p2_dst_start_ip, proto=17) /
219                       UDP(sport=int(p2_src_start_udp_port),
220                           dport=int(p2_dst_start_udp_port)))
221     else:
222         base_pkt_a = Ether() / IP(src=p1_src_start_ip, dst=p1_dst_start_ip,
223                                   proto=61)
224         base_pkt_b = Ether() / IP(src=p2_src_start_ip, dst=p2_dst_start_ip,
225                                   proto=61)
226
227     # The following code applies raw instructions to packet (IP src/dst
228     # increment). It splits the generated traffic by "ip_src"/"ip_dst" variable
229     # to cores and fix IPv4 header checksum.
230     if ports_defined:
231         if p1_src_start_udp_port != p1_src_end_udp_port and \
232                         p1_src_start_ip != p1_src_end_ip:
233             vm1 = STLScVmRaw([
234                 STLVmTupleGen(ip_min=p1_src_start_ip,
235                               ip_max=p1_src_end_ip,
236                               port_min=int(p1_src_start_udp_port),
237                               port_max=int(p1_src_end_udp_port),
238                               name="tuple"),
239                 STLVmWrFlowVar(fv_name="tuple.ip", pkt_offset="IP.src"),
240                 STLVmFixIpv4(offset="IP"),
241                 STLVmWrFlowVar(fv_name="tuple.port", pkt_offset="UDP.sport")
242             ])
243             vm2 = STLScVmRaw([
244                 STLVmTupleGen(ip_min=p2_dst_start_ip,
245                               ip_max=p2_dst_start_ip,
246                               port_min=int(p2_dst_start_udp_port),
247                               port_max=int(p2_dst_end_udp_port),
248                               name="tuple"),
249                 STLVmWrFlowVar(fv_name="tuple.ip", pkt_offset="IP.dst"),
250                 STLVmFixIpv4(offset="IP"),
251                 STLVmWrFlowVar(fv_name="tuple.port", pkt_offset="UDP.dport")
252             ])
253         elif p1_src_start_udp_port != p1_src_end_udp_port:
254             vm1 = STLScVmRaw([
255                 STLVmFlowVar(name="sport",
256                              min_value=int(p1_src_start_udp_port),
257                              max_value=int(p1_src_end_udp_port),
258                              size=2, op="inc"),
259                 STLVmWrFlowVar(fv_name="sport", pkt_offset="UDP.sport")
260                 ])
261             vm2 = STLScVmRaw([
262                 STLVmFlowVar(name="dport",
263                              min_value=int(p2_dst_start_udp_port),
264                              max_value=int(p2_dst_end_udp_port),
265                              size=2, op="inc"),
266                 STLVmWrFlowVar(fv_name="dport", pkt_offset="UDP.dport")
267             ])
268         elif p1_src_start_udp_port == p1_src_end_udp_port:
269             vm1 = STLScVmRaw([STLVmFlowVar(name="src",
270                                            min_value=p1_src_start_ip,
271                                            max_value=p1_src_end_ip,
272                                            size=4, op="inc"),
273                               STLVmWrFlowVar(fv_name="src",
274                                              pkt_offset="IP.src"),
275                               STLVmFixIpv4(offset="IP"),
276                               ], split_by_field="src")
277             vm2 = STLScVmRaw([STLVmFlowVar(name="src",
278                                            min_value=p2_src_start_ip,
279                                            max_value=p2_src_end_ip,
280                                            size=4, op="inc"),
281                               STLVmWrFlowVar(fv_name="src",
282                                              pkt_offset="IP.src"),
283                               STLVmFixIpv4(offset="IP"),
284                               ], split_by_field="src")
285     elif p1_dst_end_ip and p2_dst_end_ip:
286         vm1 = STLScVmRaw([STLVmFlowVar(name="dst",
287                                        min_value=p1_dst_start_ip,
288                                        max_value=p1_dst_end_ip,
289                                        size=4, op="inc"),
290                           STLVmWrFlowVar(fv_name="dst", pkt_offset="IP.dst"),
291                           STLVmFixIpv4(offset="IP"),
292                          ], split_by_field="dst")
293         vm2 = STLScVmRaw([STLVmFlowVar(name="dst",
294                                        min_value=p2_dst_start_ip,
295                                        max_value=p2_dst_end_ip,
296                                        size=4, op="inc"),
297                           STLVmWrFlowVar(fv_name="dst", pkt_offset="IP.dst"),
298                           STLVmFixIpv4(offset="IP"),
299                          ], split_by_field="dst")
300     else:
301         vm1 = STLScVmRaw([STLVmFlowVar(name="src",
302                                        min_value=p1_src_start_ip,
303                                        max_value=p1_src_end_ip,
304                                        size=4, op="inc"),
305                           STLVmWrFlowVar(fv_name="src", pkt_offset="IP.src"),
306                           STLVmFixIpv4(offset="IP"),
307                          ], split_by_field="src")
308         vm2 = STLScVmRaw([STLVmFlowVar(name="src",
309                                        min_value=p2_src_start_ip,
310                                        max_value=p2_src_end_ip,
311                                        size=4, op="inc"),
312                           STLVmWrFlowVar(fv_name="src", pkt_offset="IP.src"),
313                           STLVmFixIpv4(offset="IP"),
314                          ], split_by_field="src")
315
316     return create_streams_v46(base_pkt_a, base_pkt_b, vm1, vm2, frame_size)
317
318
319 def create_streams_v6(traffic_options, frame_size=78):
320     """Create two IPv6 packets to be used in stream.
321
322     :param traffic_options: Parameters for packets.
323     :param frame_size: Size of L2 frame.
324     :type traffic_options: List
325     :type frame_size: int
326     :return: Packet instances.
327     :rtype: Tuple of STLPktBuilder
328     """
329
330     if type(frame_size) is int and frame_size < 78:
331         print_error("Frame min. size is 78B")
332         sys.exit(2)
333
334     p1_src_start_ip = traffic_options['p1_src_start_ip']
335     p1_src_end_ip = traffic_options['p1_src_end_ip']
336     p1_dst_start_ip = traffic_options['p1_dst_start_ip']
337     p2_src_start_ip = traffic_options['p2_src_start_ip']
338     p2_src_end_ip = traffic_options['p2_src_end_ip']
339     p2_dst_start_ip = traffic_options['p2_dst_start_ip']
340
341     p1_dst_end_ip = traffic_options['p1_dst_end_ip']
342     p2_dst_end_ip = traffic_options['p2_dst_end_ip']
343
344     base_pkt_a = Ether()/IPv6(src=p1_src_start_ip, dst=p1_dst_start_ip)
345     base_pkt_b = Ether()/IPv6(src=p2_src_start_ip, dst=p2_dst_start_ip)
346
347     # The following code applies raw instructions to packet (IP src/dst
348     # increment). It splits the generated traffic by "ip_src"/"ip_dst" variable
349     # to cores.
350     if p1_dst_end_ip and p2_dst_end_ip:
351         base_p1, max_p1 = get_start_end_ipv6(p1_dst_start_ip, p1_dst_end_ip)
352         base_p2, max_p2 = get_start_end_ipv6(p2_dst_start_ip, p2_dst_end_ip)
353
354         vm1 = STLScVmRaw([STLVmFlowVar(name="ipv6_dst",
355                                        min_value=base_p1,
356                                        max_value=max_p1+base_p1,
357                                        size=8, op="inc"),
358                           STLVmWrFlowVar(fv_name="ipv6_dst",
359                                          pkt_offset="IPv6.dst",
360                                          offset_fixup=8)
361                          ]
362                          , split_by_field="ipv6_dst")
363         vm2 = STLScVmRaw([STLVmFlowVar(name="ipv6_dst",
364                                        min_value=base_p2,
365                                        max_value=max_p2+base_p2,
366                                        size=8, op="inc"),
367                           STLVmWrFlowVar(fv_name="ipv6_dst",
368                                          pkt_offset="IPv6.dst",
369                                          offset_fixup=8)
370                          ]
371                          , split_by_field="ipv6_dst")
372     else:
373         base_p1, max_p1 = get_start_end_ipv6(p1_src_start_ip, p1_src_end_ip)
374         base_p2, max_p2 = get_start_end_ipv6(p2_src_start_ip, p2_src_end_ip)
375
376         vm1 = STLScVmRaw([STLVmFlowVar(name="ipv6_src",
377                                        min_value=base_p1,
378                                        max_value=max_p1+base_p1,
379                                        size=8, op="inc"),
380                           STLVmWrFlowVar(fv_name="ipv6_src",
381                                          pkt_offset="IPv6.src",
382                                          offset_fixup=8)
383                          ]
384                          , split_by_field="ipv6_src")
385         vm2 = STLScVmRaw([STLVmFlowVar(name="ipv6_src",
386                                        min_value=base_p2,
387                                        max_value=max_p2+base_p2,
388                                        size=8, op="inc"),
389                           STLVmWrFlowVar(fv_name="ipv6_src",
390                                          pkt_offset="IPv6.src",
391                                          offset_fixup=8)
392                          ]
393                          , split_by_field="ipv6_src")
394
395     return create_streams_v46(base_pkt_a, base_pkt_b, vm1, vm2, frame_size)
396
397 def fmt_latency(lat_min, lat_avg, lat_max):
398     """ Return formatted, rounded latency
399
400     :param lat_min: Min latency
401     :param lat_avg: Average latency
402     :param lat_max: Max latency
403     :type lat_min: string
404     :type lat_avg: string
405     :type lat_max: string
406     :return: Formatted and rounded output "min/avg/max"
407     :rtype: string
408     """
409
410     try:
411         t_min = int(round(float(lat_min)))
412     except ValueError:
413         t_min = int(-1)
414     try:
415         t_avg = int(round(float(lat_avg)))
416     except ValueError:
417         t_avg = int(-1)
418     try:
419         t_max = int(round(float(lat_max)))
420     except ValueError:
421         t_max = int(-1)
422
423     return "/".join(str(tmp) for tmp in (t_min, t_avg, t_max))
424
425 def simple_burst(stream_a, stream_b, stream_lat_a, stream_lat_b, duration, rate,
426                  warmup_time, async_start, latency):
427     """Run the traffic with specific parameters.
428
429     :param pkt_a: Base packet for stream 1.
430     :param pkt_b: Base packet for stream 2.
431     :param pkt_lat_a: Base packet for latency stream 1.
432     :param pkt_lat_b: Base packet for latency stream 2.
433     :param duration: Duration of traffic run in seconds (-1=infinite).
434     :param rate: Rate of traffic run [percentage, pps, bps].
435     :param warmup_time: Warm up duration.
436     :param async_start: Start the traffic and exit.
437     :param latency: With latency stats.
438     :type pkt_a: STLPktBuilder
439     :type pkt_b: STLPktBuilder
440     :type pkt_lat_a: STLPktBuilder
441     :type pkt_lat_b: STLPktBuilder
442     :type duration: int
443     :type rate: string
444     :type warmup_time: int
445     :type async_start: bool
446     :type latency: bool
447     :return: nothing
448     """
449
450     # create client
451     client = STLClient()
452
453     total_rcvd = 0
454     total_sent = 0
455     lost_a = 0
456     lost_b = 0
457     lat_a = "-1/-1/-1"
458     lat_b = "-1/-1/-1"
459
460     try:
461         # turn this off if too many logs
462         #client.set_verbose("high")
463
464         # connect to server
465         client.connect()
466
467         # prepare our ports (my machine has 0 <--> 1 with static route)
468         client.reset(ports=[0, 1])
469
470         client.add_streams(stream_a, ports=[0])
471         client.add_streams(stream_b, ports=[1])
472
473         if latency:
474             try:
475                 client.add_streams(stream_lat_a, ports=[0])
476                 client.add_streams(stream_lat_b, ports=[1])
477             except:
478                 #Disable latency if NIC does not support requested stream type
479                 print "##### FAILED to add latency streams #####"
480                 latency = False
481
482         #warmup phase
483         if warmup_time > 0:
484             # clear the stats before injecting
485             client.clear_stats()
486
487             # choose rate and start traffic
488             client.start(ports=[0, 1], mult=rate, duration=warmup_time)
489
490             # block until done
491             client.wait_on_traffic(ports=[0, 1], timeout=(warmup_time+30))
492
493             if client.get_warnings():
494                 for warning in client.get_warnings():
495                     print(warning)
496
497             # read the stats after the test
498             stats = client.get_stats()
499
500             print "#####warmup statistics#####"
501             print json.dumps(stats, indent=4,
502                              separators=(',', ': '), sort_keys=True)
503             lost_a = stats[0]["opackets"] - stats[1]["ipackets"]
504             lost_b = stats[1]["opackets"] - stats[0]["ipackets"]
505
506             print "\npackets lost from 0 --> 1:   {0} pkts".format(lost_a)
507             print "packets lost from 1 --> 0:   {0} pkts".format(lost_b)
508
509         # clear the stats before injecting
510         client.clear_stats()
511         lost_a = 0
512         lost_b = 0
513
514         # choose rate and start traffic
515         client.start(ports=[0, 1], mult=rate, duration=duration)
516
517         if not async_start:
518             # block until done
519             client.wait_on_traffic(ports=[0, 1], timeout=(duration+30))
520
521             if client.get_warnings():
522                 for warning in client.get_warnings():
523                     print(warning)
524
525             # read the stats after the test
526             stats = client.get_stats()
527
528             print "#####statistics#####"
529             print json.dumps(stats, indent=4,
530                              separators=(',', ': '), sort_keys=True)
531             lost_a = stats[0]["opackets"] - stats[1]["ipackets"]
532             lost_b = stats[1]["opackets"] - stats[0]["ipackets"]
533
534             if latency:
535                 lat_a = fmt_latency(\
536                     str(stats["latency"][0]["latency"]["total_min"]),\
537                     str(stats["latency"][0]["latency"]["average"]),\
538                     str(stats["latency"][0]["latency"]["total_max"]))
539                 lat_b = fmt_latency(\
540                     str(stats["latency"][1]["latency"]["total_min"]),\
541                     str(stats["latency"][1]["latency"]["average"]),\
542                     str(stats["latency"][1]["latency"]["total_max"]))
543
544             total_sent = stats[0]["opackets"] + stats[1]["opackets"]
545             total_rcvd = stats[0]["ipackets"] + stats[1]["ipackets"]
546
547             print "\npackets lost from 0 --> 1:   {0} pkts".format(lost_a)
548             print "packets lost from 1 --> 0:   {0} pkts".format(lost_b)
549
550     except STLError as ex_error:
551         print_error(str(ex_error))
552         sys.exit(1)
553
554     finally:
555         if async_start:
556             client.disconnect(stop_traffic=False, release_ports=True)
557         else:
558             client.disconnect()
559             print "rate={0}, totalReceived={1}, totalSent={2}, "\
560                 "frameLoss={3}, latencyStream0(usec)={4}, "\
561                 "latencyStream1(usec)={5}".format(rate, total_rcvd,\
562                 total_sent, lost_a+lost_b, lat_a, lat_b)
563
564
565 def print_error(msg):
566     """Print error message on stderr.
567
568     :param msg: Error message to print.
569     :type msg: string
570     :return: nothing
571     """
572
573     sys.stderr.write(msg+'\n')
574
575
576 def parse_args():
577     """Parse arguments from cmd line.
578
579     :return: Parsed arguments.
580     :rtype ArgumentParser
581     """
582
583     parser = argparse.ArgumentParser()
584     parser.add_argument("-d", "--duration", required=True, type=int,
585                         help="Duration of traffic run")
586     parser.add_argument("-s", "--frame_size", required=True,
587                         help="Size of a Frame without padding and IPG")
588     parser.add_argument("-r", "--rate", required=True,
589                         help="Traffic rate with included units (%, pps)")
590     parser.add_argument("-6", "--use_IPv6", action="store_true",
591                         default=False,
592                         help="Use IPv6 traffic profile instead of IPv4")
593     parser.add_argument("--async", action="store_true",
594                         default=False,
595                         help="Non-blocking call of the script")
596     parser.add_argument("--latency", action="store_true",
597                         default=False,
598                         help="Add latency stream")
599     parser.add_argument("-w", "--warmup_time", type=int,
600                         default=5,
601                         help="Traffic warmup time in seconds, 0 = disable")
602 #    parser.add_argument("--p1_src_mac",
603 #                        help="Port 1 source MAC address")
604 #    parser.add_argument("--p1_dst_mac",
605 #                        help="Port 1 destination MAC address")
606
607     parser.add_argument("--p1_src_start_ip", required=True,
608                         help="Port 1 source start IP address")
609     parser.add_argument("--p1_src_end_ip",
610                         default=False,
611                         help="Port 1 source end IP address")
612     parser.add_argument("--p1_dst_start_ip", required=True,
613                         help="Port 1 destination start IP address")
614     parser.add_argument("--p1_dst_end_ip",
615                         default=False,
616                         help="Port 1 destination end IP address")
617
618     parser.add_argument("--p1_src_start_udp_port",
619                         default=None,
620                         help="Port 1 source start UDP port.")
621     parser.add_argument("--p1_src_end_udp_port",
622                         default=None,
623                         help="Port 1 source end UDP port.")
624
625     parser.add_argument("--p1_dst_start_udp_port",
626                         default=None,
627                         help="Port 1 destination start UDP port.")
628     parser.add_argument("--p1_dst_end_udp_port",
629                         default=None,
630                         help="Port 1 destination end UDP port.")
631
632 #    parser.add_argument("--p2_src_mac",
633 #                        help="Port 2 source MAC address")
634 #    parser.add_argument("--p2_dst_mac",
635 #                        help="Port 2 destination MAC address")
636
637     parser.add_argument("--p2_src_start_ip", required=True,
638                         help="Port 2 source start IP address")
639     parser.add_argument("--p2_src_end_ip",
640                         default=False,
641                         help="Port 2 source end IP address")
642     parser.add_argument("--p2_dst_start_ip", required=True,
643                         help="Port 2 destination start IP address")
644     parser.add_argument("--p2_dst_end_ip",
645                         default=False,
646                         help="Port 2 destination end IP address")
647
648     parser.add_argument("--p2_src_start_udp_port",
649                         default=None,
650                         help="Port 2 source start UDP port.")
651     parser.add_argument("--p2_src_end_udp_port",
652                         default=None,
653                         help="Port 2 source end UDP port.")
654
655     parser.add_argument("--p2_dst_start_udp_port",
656                         default=None,
657                         help="Port 2 destination start UDP port.")
658     parser.add_argument("--p2_dst_end_udp_port",
659                         default=None,
660                         help="Port 2 destination end UDP port.")
661
662     return parser.parse_args()
663
664
665 def main():
666     """Main function."""
667
668     args = parse_args()
669
670     _duration = args.duration
671     _latency = args.latency
672     if args.frame_size.isdigit():
673         _frame_size = int(args.frame_size)
674     else:
675         _frame_size = args.frame_size
676         _latency = False
677     _rate = args.rate
678     _use_ipv6 = args.use_IPv6
679     _async_call = args.async
680     _warmup_time = args.warmup_time
681
682     _traffic_options = {}
683     for attr in [a for a in dir(args) if a.startswith('p')]:
684         if getattr(args, attr) is not None:
685             _traffic_options[attr] = getattr(args, attr)
686
687     if _use_ipv6:
688         stream_a, stream_b, stream_lat_a, stream_lat_b = create_streams_v6(
689             _traffic_options, frame_size=_frame_size)
690     else:
691         stream_a, stream_b, stream_lat_a, stream_lat_b = create_streams(
692             _traffic_options, frame_size=_frame_size)
693
694     simple_burst(stream_a, stream_b, stream_lat_a, stream_lat_b,
695                  _duration, _rate, _warmup_time, _async_call, _latency)
696
697 if __name__ == "__main__":
698     sys.exit(main())