Update T-rex version to v2.00
[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 json
45 import string
46 import sys, getopt
47
48 sys.path.insert(0, "/opt/trex-core-2.00/scripts/automation/"+\
49                    "trex_control_plane/stl/")
50 from trex_stl_lib.api import *
51
52
53 def generate_payload(length):
54     """Generate random payload.
55
56     :param length: Length of payload.
57     :type length: int
58     :return: Payload filled with random chars.
59     :rtype string
60     """
61
62     word = ''
63     alphabet_size = len(string.letters)
64     for i in range(length):
65         word += string.letters[(i % alphabet_size)]
66
67     return word
68
69 def create_packets(traffic_options, frame_size=64):
70     """Create two IP packets to be used in stream.
71
72     :param traffic_options: Parameters for packets.
73     :param frame_size: Size of L2 frame.
74     :type traffic_options: list
75     :type frame_size: int
76     :return: Packet instances.
77     :rtype STLPktBuilder
78     """
79
80     if frame_size < 64:
81         print_error("Packet min. size is 64B")
82         sys.exit(1)
83
84     fsize_no_fcs = frame_size - 4 # no FCS
85
86     p1_src_start_ip = traffic_options['p1_src_start_ip']
87     p1_src_end_ip = traffic_options['p1_src_end_ip']
88     p1_dst_start_ip = traffic_options['p1_dst_start_ip']
89     p2_src_start_ip = traffic_options['p2_src_start_ip']
90     p2_src_end_ip = traffic_options['p2_src_end_ip']
91     p2_dst_start_ip = traffic_options['p2_dst_start_ip']
92
93     base_pkt_a = Ether()/IP(src=p1_src_start_ip, dst=p1_dst_start_ip, proto=61)
94     base_pkt_b = Ether()/IP(src=p2_src_start_ip, dst=p2_dst_start_ip, proto=61)
95
96     # The following code applies raw instructions to packet (IP src increment).
97     # It splits the generated traffic by "ip_src" variable to cores and fix
98     # IPv4 header checksum.
99     vm1 = STLScVmRaw([STLVmFlowVar(name="src",
100                                    min_value=p1_src_start_ip,
101                                    max_value=p1_src_end_ip,
102                                    size=4, op="inc"),
103                       STLVmWrFlowVar(fv_name="src", pkt_offset="IP.src"),
104                       STLVmFixIpv4(offset="IP"),
105                      ], split_by_field="src")
106
107     # The following code applies raw instructions to packet (IP src increment).
108     # It splits the generated traffic by "ip_src" variable to cores and fix
109     # IPv4 header checksum.
110     vm2 = STLScVmRaw([STLVmFlowVar(name="src",
111                                    min_value=p2_src_start_ip,
112                                    max_value=p2_src_end_ip,
113                                    size=4, op="inc"),
114                       STLVmWrFlowVar(fv_name="src", pkt_offset="IP.src"),
115                       STLVmFixIpv4(offset="IP"),
116                      ], split_by_field="src")
117
118     pkt_a = STLPktBuilder(pkt=base_pkt_a/generate_payload(
119         max(0, fsize_no_fcs-len(base_pkt_a))), vm=vm1)
120     pkt_b = STLPktBuilder(pkt=base_pkt_b/generate_payload(
121         max(0, fsize_no_fcs-len(base_pkt_b))), vm=vm2)
122
123     return(pkt_a, pkt_b)
124
125 def simple_burst(pkt_a, pkt_b, duration=10, rate="1mpps", warmup_time=5):
126     """Run the traffic with specific parameters.
127
128     :param pkt_a: Base packet for stream 1.
129     :param pkt_b: Base packet for stream 2.
130     :param duration: Duration of traffic run in seconds.
131     :param rate: Rate of traffic run [percentage, pps, bps].
132     :param warmup_time: Warm up duration.
133     :type pkt_a: STLPktBuilder
134     :type pkt_b: STLPktBuilder
135     :type duration: int
136     :type rate: string
137     :type warmup_time: int
138     :return: nothing
139     """
140
141     # create client
142     client = STLClient()
143
144     total_rcvd = 0
145     total_sent = 0
146     lost_a = 0
147     lost_b = 0
148
149     try:
150         # turn this off if too many logs
151         #client.set_verbose("high")
152
153         # create two streams
154         stream1 = STLStream(packet=pkt_a,
155                             mode=STLTXCont(pps=100))
156
157         # second stream with a phase of 10ns (inter stream gap)
158         stream2 = STLStream(packet=pkt_b,
159                             isg=10.0,
160                             mode=STLTXCont(pps=100))
161
162
163         # connect to server
164         client.connect()
165
166         # prepare our ports (my machine has 0 <--> 1 with static route)
167         client.reset(ports=[0, 1])
168
169         # add both streams to ports
170         client.add_streams(stream1, ports=[0])
171         client.add_streams(stream2, ports=[1])
172
173         #warmup phase
174         if warmup_time is not None:
175             client.clear_stats()
176             client.start(ports=[0, 1], mult=rate, duration=warmup_time)
177             client.wait_on_traffic(ports=[0, 1], timeout=(duration+30))
178             stats = client.get_stats()
179             print stats
180             print "#####warmup statistics#####"
181             print json.dumps(stats, indent=4,
182                              separators=(',', ': '), sort_keys=True)
183             lost_a = stats[0]["opackets"] - stats[1]["ipackets"]
184             lost_b = stats[1]["opackets"] - stats[0]["ipackets"]
185
186             print "\npackets lost from 0 --> 1:   {0} pkts".format(lost_a)
187             print "packets lost from 1 --> 0:   {0} pkts".format(lost_b)
188
189
190         # clear the stats before injecting
191         client.clear_stats()
192
193         # choose rate and start traffic
194         client.start(ports=[0, 1], mult=rate, duration=duration)
195
196         # block until done
197         client.wait_on_traffic(ports=[0, 1], timeout=(duration+30))
198
199         # read the stats after the test
200         stats = client.get_stats()
201
202         print "#####statistics#####"
203         print json.dumps(stats, indent=4,
204                          separators=(',', ': '), sort_keys=True)
205
206         lost_a = stats[0]["opackets"] - stats[1]["ipackets"]
207         lost_b = stats[1]["opackets"] - stats[0]["ipackets"]
208
209         total_sent = stats[0]["opackets"] + stats[1]["opackets"]
210         total_rcvd = stats[0]["ipackets"] + stats[1]["ipackets"]
211
212         print "\npackets lost from 0 --> 1:   {0} pkts".format(lost_a)
213         print "packets lost from 1 --> 0:   {0} pkts".format(lost_b)
214
215     except STLError as ex_error:
216         print_error(str(ex_error))
217         sys.exit(1)
218
219     finally:
220         client.disconnect()
221         print "rate={0}, totalReceived={1}, totalSent={2}, frameLoss={3}"\
222               .format(rate, total_rcvd, total_sent, lost_a+lost_b)
223
224
225 def print_help():
226     """Print help on stdout."""
227
228     print "args: [-h] -d <duration> -s <size of frame in bytes>"+\
229     " [-r] <traffic rate with unit: %, mpps> "+\
230     "--p1_src_mac <port1_src_mac> "+\
231     "--p1_dst_mac <port1_dst_mac> "+\
232     "--p1_src_start_ip <port1_src_start_ip> "+\
233     "--p1_src_end_ip <port1_src_end_ip> "+\
234     "--p1_dst_start_ip <port1_dst_start_ip> "+\
235     "--p1_dst_end_ip <port1_dst_end_ip> "+\
236     "--p2_src_mac <port2_src_mac> "+\
237     "--p2_dst_mac <port2_dst_mac> "+\
238     "--p2_src_start_ip <port2_src_start_ip> "+\
239     "--p2_src_end_ip <port2_src_end_ip> "+\
240     "--p2_dst_start_ip <port2_dst_start_ip> "+\
241     "--p2_dst_end_ip <port2_dst_end_ip>"
242
243 def print_error(msg):
244     """Print error message on stderr.
245
246     :param msg: Error message to print.
247     :type msg: string
248     :return: nothing
249     """
250
251     sys.stderr.write(msg+'\n')
252
253
254 def main(argv):
255     """Main function."""
256
257     _duration = 10
258     _frame_size = 64
259     _rate = '1mpps'
260     _traffic_options = {}
261
262     try:
263         opts, _ = getopt.getopt(argv, "hd:s:r:o:",
264                                 ["help",
265                                  "p1_src_mac=",
266                                  "p1_dst_mac=",
267                                  "p1_src_start_ip=",
268                                  "p1_src_end_ip=",
269                                  "p1_dst_start_ip=",
270                                  "p1_dst_end_ip=",
271                                  "p2_src_mac=",
272                                  "p2_dst_mac=",
273                                  "p2_src_start_ip=",
274                                  "p2_src_end_ip=",
275                                  "p2_dst_start_ip=",
276                                  "p2_dst_end_ip="])
277     except getopt.GetoptError:
278         print_help()
279         sys.exit(1)
280     for opt, arg in opts:
281         if opt in ('-h', "--help"):
282             print_help()
283             sys.exit()
284         elif opt == '-d':
285             _duration = int(arg)
286         elif opt == '-s':
287             _frame_size = int(arg)
288         elif opt == '-r':
289             _rate = arg
290         elif opt.startswith("--p"):
291             _traffic_options[opt[2:]] = arg
292
293     print _traffic_options
294     if len(_traffic_options) != 6:
295         print_error("Supported only: src_start_ip, src_end_ip, dst_start_ip")
296         print_help()
297         sys.exit(1)
298
299     pkt_a, pkt_b = create_packets(_traffic_options,
300                                   frame_size=_frame_size)
301
302     simple_burst(pkt_a, pkt_b, duration=_duration, rate=_rate)
303
304 if __name__ == "__main__":
305     main(sys.argv[1:])
306