6c53794739afd44636eed5d91aa274285ff1153e
[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
45 import sys, getopt
46 sys.path.insert(0, "/opt/trex-core-1.91/scripts/automation/trex_control_plane/stl/")
47
48 from trex_stl_lib.api import *
49
50 import dpkt
51 import json
52 import string
53
54 def generate_payload(length):
55     word = ''
56     alphabet_size = len(string.letters)
57     for i in range(length):
58         word += string.letters[(i % alphabet_size)]
59     return word
60
61 def create_packets(traffic_options, frame_size=64):
62
63     if frame_size < 64:
64         print "Packet min. size is 64B"
65         sys.exit(2)
66
67     fsize_no_fcs = frame_size - 4 # no FCS
68
69     #p1_src_mac = traffic_options['p1_src_mac']
70     #p1_dst_mac = traffic_options['p1_dst_mac']
71     p1_src_start_ip = traffic_options['p1_src_start_ip']
72     p1_src_end_ip = traffic_options['p1_src_end_ip']
73     p1_dst_start_ip = traffic_options['p1_dst_start_ip']
74     #p1_dst_end_ip = traffic_options['p1_dst_end_ip']
75     #p2_src_mac = traffic_options['p2_src_mac']
76     #p2_dst_mac = traffic_options['p2_dst_mac']
77     p2_src_start_ip = traffic_options['p2_src_start_ip']
78     p2_src_end_ip = traffic_options['p2_src_end_ip']
79     p2_dst_start_ip = traffic_options['p2_dst_start_ip']
80     #p2_dst_end_ip = traffic_options['p2_dst_end_ip']
81
82     base_pkt_a = Ether()/IP(src=p1_src_start_ip, dst=p1_dst_start_ip, proto=61)
83     base_pkt_b = Ether()/IP(src=p2_src_start_ip, dst=p2_dst_start_ip, proto=61)
84
85     vm1 = CTRexScRaw([STLVmTupleGen(ip_min=p1_src_start_ip, ip_max=p1_src_end_ip,
86                                     name="tuple"), # define tuple gen
87
88                       STLVmWrFlowVar(fv_name="tuple.ip", pkt_offset="IP.src"), # write ip to packet IP.src
89                       STLVmFixIpv4(offset="IP"),                               # fix checksum
90                      ]
91                      , split_by_field="tuple") # split to cores base on the tuple generator
92
93     vm2 = CTRexScRaw([STLVmTupleGen(ip_min=p2_src_start_ip, ip_max=p2_src_end_ip,
94                                     name="tuple"), # define tuple gen
95
96                       STLVmWrFlowVar(fv_name="tuple.ip", pkt_offset="IP.src"), # write ip to packet IP.src
97                       STLVmFixIpv4(offset="IP"),                               # fix checksum
98                      ]
99                      , split_by_field="tuple") # split to cores base on the tuple generator
100
101     pkt_a = STLPktBuilder(pkt=base_pkt_a/generate_payload(fsize_no_fcs-len(base_pkt_a)), vm=vm1)
102     pkt_b = STLPktBuilder(pkt=base_pkt_b/generate_payload(fsize_no_fcs-len(base_pkt_b)), vm=vm2)
103
104     return(pkt_a, pkt_b)
105
106 def simple_burst(pkt_a, pkt_b, duration=10, rate="1mpps",
107                  warmup=True, warmup_time=5):
108
109     # create client
110     c = STLClient()
111     passed = True
112
113     try:
114         # turn this on for some information
115         #c.set_verbose("high")
116
117         # create two streams
118         s1 = STLStream(packet=pkt_a,
119                        mode=STLTXCont(pps=100))
120
121         # second stream with a phase of 10ns (inter stream gap)
122         s2 = STLStream(packet=pkt_b,
123                        isg=10.0,
124                        mode=STLTXCont(pps=100))
125
126
127         # connect to server
128         c.connect()
129
130         # prepare our ports (my machine has 0 <--> 1 with static route)
131         c.reset(ports=[0, 1])
132
133         # add both streams to ports
134         c.add_streams(s1, ports=[0])
135         c.add_streams(s2, ports=[1])
136
137         #warmup phase
138         if warmup == True:
139             c.clear_stats()
140             c.start(ports=[0, 1], mult=rate, duration=warmup_time)
141             c.wait_on_traffic(ports=[0, 1])
142             stats = c.get_stats()
143             print stats
144             print "#####warmup statistics#####"
145             print json.dumps(stats, indent=4,
146                              separators=(',', ': '), sort_keys=True)
147             lost_a = stats[0]["opackets"] - stats[1]["ipackets"]
148             lost_b = stats[1]["opackets"] - stats[0]["ipackets"]
149
150             print "\npackets lost from 0 --> 1:   {0} pkts".format(lost_a)
151             print "packets lost from 1 --> 0:   {0} pkts".format(lost_b)
152
153
154         # clear the stats before injecting
155         c.clear_stats()
156
157         # choose rate and start traffic
158         c.start(ports=[0, 1], mult=rate, duration=duration)
159
160         # block until done
161         c.wait_on_traffic(ports=[0, 1])
162
163         # read the stats after the test
164         stats = c.get_stats()
165
166         print "#####statistics#####"
167         print json.dumps(stats, indent=4,
168                          separators=(',', ': '), sort_keys=True)
169
170         lost_a = stats[0]["opackets"] - stats[1]["ipackets"]
171         lost_b = stats[1]["opackets"] - stats[0]["ipackets"]
172
173         total_sent = stats[0]["opackets"] + stats[1]["opackets"]
174         total_rcvd = stats[0]["ipackets"] + stats[1]["ipackets"]
175
176         print "\npackets lost from 0 --> 1:   {0} pkts".format(lost_a)
177         print "packets lost from 1 --> 0:   {0} pkts".format(lost_b)
178         print "rate={0}, totalReceived={1}, totalSent={2}, frameLoss={3}"\
179               .format(rate, total_rcvd, total_sent, lost_a+lost_b)
180
181         if (lost_a == 0) and (lost_b == 0):
182             passed = True
183         else:
184             passed = False
185
186     except STLError as e:
187         passed = False
188         print e
189
190     finally:
191         c.disconnect()
192
193 def print_help():
194
195     print "args: [-h] -d <duration> -s <size of frame in bytes>"+\
196     " [-r] <traffic rate with unit: %, mpps> "+\
197     "--p1_src_mac <port1_src_mac> "+\
198     "--p1_dst_mac <port1_dst_mac> "+\
199     "--p1_src_start_ip <port1_src_start_ip> "+\
200     "--p1_src_end_ip <port1_src_end_ip> "+\
201     "--p1_dst_start_ip <port1_dst_start_ip> "+\
202     "--p1_dst_end_ip <port1_dst_end_ip> "+\
203     "--p2_src_mac <port2_src_mac> "+\
204     "--p2_dst_mac <port2_dst_mac> "+\
205     "--p2_src_start_ip <port2_src_start_ip> "+\
206     "--p2_src_end_ip <port2_src_end_ip> "+\
207     "--p2_dst_start_ip <port2_dst_start_ip> "+\
208     "--p2_dst_end_ip <port2_dst_end_ip>"
209
210
211 def main(argv):
212
213     _duration = 10
214     _frame_size = 64
215     _rate = '1mpps'
216     _traffic_options = {}
217
218     try:
219         opts, args = getopt.getopt(argv, "hd:s:r:o:",
220                                    ["help",
221                                     "p1_src_mac=",
222                                     "p1_dst_mac=",
223                                     "p1_src_start_ip=",
224                                     "p1_src_end_ip=",
225                                     "p1_dst_start_ip=",
226                                     "p1_dst_end_ip=",
227                                     "p2_src_mac=",
228                                     "p2_dst_mac=",
229                                     "p2_src_start_ip=",
230                                     "p2_src_end_ip=",
231                                     "p2_dst_start_ip=",
232                                     "p2_dst_end_ip="])
233     except getopt.GetoptError:
234         print_help()
235         sys.exit(2)
236     for opt, arg in opts:
237         if opt in ('-h', "--help"):
238             print_help()
239             sys.exit()
240         elif opt == '-d':
241             _duration = int(arg)
242         elif opt == '-s':
243             _frame_size = int(arg)
244         elif opt == '-r':
245             _rate = arg
246         elif opt.startswith("--p"):
247             _traffic_options[opt[2:]] = arg
248
249     print _traffic_options
250     if len(_traffic_options) != 6:
251         print "Supported only: src_start_ip, src_end_ip, dst_start_ip"
252         print_help()
253         sys.exit(2)
254
255     pkt_a, pkt_b = create_packets(_traffic_options,
256                                   frame_size=_frame_size)
257
258     simple_burst(pkt_a, pkt_b, duration=_duration, rate=_rate)
259
260 if __name__ == "__main__":
261     main(sys.argv[1:])
262