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:
8 # http://www.apache.org/licenses/LICENSE-2.0
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.
16 """This script uses T-REX stateless API to drive t-rex instance.
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
25 ##################### Example of /etc/trex_cfg.yaml ##########################
26 - port_limit : 2 # numbers of ports to use
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 ##############################################################################
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
51 sys.path.insert(0, "/opt/trex-core-2.00/scripts/automation/"+\
52 "trex_control_plane/stl/")
53 from trex_stl_lib.api import *
56 def generate_payload(length):
59 :param length: Length of payload.
61 :return: Payload filled with chars.
66 alphabet_size = len(string.letters)
67 for i in range(length):
68 word += string.letters[(i % alphabet_size)]
73 def get_start_end_ipv6(start_ip, end_ip):
74 """Get start and end host from IPv6 as integer.
76 :param start_ip: Start IPv6.
77 :param end_ip: End IPv6.
78 :type start_ip: string
80 :return: Start host, end host.
85 ip1 = socket.inet_pton(socket.AF_INET6, start_ip)
86 ip2 = socket.inet_pton(socket.AF_INET6, end_ip)
88 hi1, lo1 = struct.unpack('!QQ', ip1)
89 hi2, lo2 = struct.unpack('!QQ', ip2)
91 if ((hi1 << 64) | lo1) > ((hi2 << 64) | lo2):
92 print "IPv6: start_ip is greater then end_ip"
95 max_p1 = abs(int(lo1) - int(lo2)) + 1
97 except AddressValueError as ex_error:
101 return base_p1, max_p1
104 def create_packets(traffic_options, frame_size=64):
105 """Create two IP packets to be used in stream.
107 :param traffic_options: Parameters for packets.
108 :param frame_size: Size of L2 frame.
109 :type traffic_options: list
110 :type frame_size: int
111 :return: Packet instances.
116 print_error("Packet min. size is 64B")
119 fsize_no_fcs = frame_size - 4 # no FCS
121 p1_src_start_ip = traffic_options['p1_src_start_ip']
122 p1_src_end_ip = traffic_options['p1_src_end_ip']
123 p1_dst_start_ip = traffic_options['p1_dst_start_ip']
124 p2_src_start_ip = traffic_options['p2_src_start_ip']
125 p2_src_end_ip = traffic_options['p2_src_end_ip']
126 p2_dst_start_ip = traffic_options['p2_dst_start_ip']
128 base_pkt_a = Ether()/IP(src=p1_src_start_ip, dst=p1_dst_start_ip, proto=61)
129 base_pkt_b = Ether()/IP(src=p2_src_start_ip, dst=p2_dst_start_ip, proto=61)
131 # The following code applies raw instructions to packet (IP src increment).
132 # It splits the generated traffic by "ip_src" variable to cores and fix
133 # IPv4 header checksum.
134 vm1 = STLScVmRaw([STLVmFlowVar(name="src",
135 min_value=p1_src_start_ip,
136 max_value=p1_src_end_ip,
138 STLVmWrFlowVar(fv_name="src", pkt_offset="IP.src"),
139 STLVmFixIpv4(offset="IP"),
140 ], split_by_field="src")
141 # The following code applies raw instructions to packet (IP src increment).
142 # It splits the generated traffic by "ip_src" variable to cores and fix
143 # IPv4 header checksum.
144 vm2 = STLScVmRaw([STLVmFlowVar(name="src",
145 min_value=p2_src_start_ip,
146 max_value=p2_src_end_ip,
148 STLVmWrFlowVar(fv_name="src", pkt_offset="IP.src"),
149 STLVmFixIpv4(offset="IP"),
150 ], split_by_field="src")
152 pkt_a = STLPktBuilder(pkt=base_pkt_a/generate_payload(
153 fsize_no_fcs-len(base_pkt_a)), vm=vm1)
154 pkt_b = STLPktBuilder(pkt=base_pkt_b/generate_payload(
155 fsize_no_fcs-len(base_pkt_b)), vm=vm2)
160 def create_packets_v6(traffic_options, frame_size=78):
161 """Create two IPv6 packets to be used in stream.
163 :param traffic_options: Parameters for packets.
164 :param frame_size: Size of L2 frame.
165 :type traffic_options: List
166 :type frame_size: int
167 :return: Packet instances.
172 print "Packet min. size is 78B"
175 fsize_no_fcs = frame_size - 4 # no FCS
177 p1_src_start_ip = traffic_options['p1_src_start_ip']
178 p1_src_end_ip = traffic_options['p1_src_end_ip']
179 p1_dst_start_ip = traffic_options['p1_dst_start_ip']
180 p2_src_start_ip = traffic_options['p2_src_start_ip']
181 p2_src_end_ip = traffic_options['p2_src_end_ip']
182 p2_dst_start_ip = traffic_options['p2_dst_start_ip']
184 base_p1, max_p1 = get_start_end_ipv6(p1_src_start_ip, p1_src_end_ip)
185 base_p2, max_p2 = get_start_end_ipv6(p2_src_start_ip, p2_src_end_ip)
187 base_pkt_a = Ether()/IPv6(src=p1_src_start_ip, dst=p1_dst_start_ip)
188 base_pkt_b = Ether()/IPv6(src=p2_src_start_ip, dst=p2_dst_start_ip)
190 # The following code applies raw instructions to packet (IP src increment).
191 # It splits the generated traffic by "ip_src" variable to cores
192 vm1 = STLScVmRaw([STLVmFlowVar(name="ipv6_src",
194 max_value=max_p1+base_p1,
196 STLVmWrFlowVar(fv_name="ipv6_src", pkt_offset="IPv6.src",
199 , split_by_field="ipv6_src")
201 # The following code applies raw instructions to packet (IP src increment).
202 # It splits the generated traffic by "ip_src" variable to cores
203 vm2 = STLScVmRaw([STLVmFlowVar(name="ipv6_src",
205 max_value=max_p2+base_p2,
207 STLVmWrFlowVar(fv_name="ipv6_src", pkt_offset="IPv6.src",
210 , split_by_field="ipv6_src")
212 pkt_a = STLPktBuilder(pkt=base_pkt_a/generate_payload(
213 max(0, fsize_no_fcs-len(base_pkt_a))), vm=vm1)
214 pkt_b = STLPktBuilder(pkt=base_pkt_b/generate_payload(
215 max(0, fsize_no_fcs-len(base_pkt_b))), vm=vm2)
220 def simple_burst(pkt_a, pkt_b, duration, rate, warmup_time, async_start):
221 """Run the traffic with specific parameters.
223 :param pkt_a: Base packet for stream 1.
224 :param pkt_b: Base packet for stream 2.
225 :param duration: Duration of traffic run in seconds (-1=infinite).
226 :param rate: Rate of traffic run [percentage, pps, bps].
227 :param warmup_time: Warm up duration.
228 :async_start: Start the traffic and exit
229 :type pkt_a: STLPktBuilder
230 :type pkt_b: STLPktBuilder
233 :type warmup_time: int
234 :type async_start: bool
247 # turn this off if too many logs
248 #client.set_verbose("high")
251 stream1 = STLStream(packet=pkt_a,
252 mode=STLTXCont(pps=100))
254 # second stream with a phase of 10ns (inter stream gap)
255 stream2 = STLStream(packet=pkt_b,
257 mode=STLTXCont(pps=100))
262 # prepare our ports (my machine has 0 <--> 1 with static route)
263 client.reset(ports=[0, 1])
265 # add both streams to ports
266 client.add_streams(stream1, ports=[0])
267 client.add_streams(stream2, ports=[1])
272 client.start(ports=[0, 1], mult=rate, duration=warmup_time)
273 client.wait_on_traffic(ports=[0, 1], timeout=(warmup_time+30))
274 stats = client.get_stats()
276 print "#####warmup statistics#####"
277 print json.dumps(stats, indent=4,
278 separators=(',', ': '), sort_keys=True)
279 lost_a = stats[0]["opackets"] - stats[1]["ipackets"]
280 lost_b = stats[1]["opackets"] - stats[0]["ipackets"]
282 print "\npackets lost from 0 --> 1: {0} pkts".format(lost_a)
283 print "packets lost from 1 --> 0: {0} pkts".format(lost_b)
286 # clear the stats before injecting
293 # choose rate and start traffic
294 client.start(ports=[0, 1], mult=rate, duration=duration)
298 client.wait_on_traffic(ports=[0, 1], timeout=(duration+30))
300 # read the stats after the test
301 stats = client.get_stats()
303 print "#####statistics#####"
304 print json.dumps(stats, indent=4,
305 separators=(',', ': '), sort_keys=True)
307 lost_a = stats[0]["opackets"] - stats[1]["ipackets"]
308 lost_b = stats[1]["opackets"] - stats[0]["ipackets"]
310 total_sent = stats[0]["opackets"] + stats[1]["opackets"]
311 total_rcvd = stats[0]["ipackets"] + stats[1]["ipackets"]
313 print "\npackets lost from 0 --> 1: {0} pkts".format(lost_a)
314 print "packets lost from 1 --> 0: {0} pkts".format(lost_b)
316 except STLError as ex_error:
317 print_error(str(ex_error))
322 client.disconnect(stop_traffic=False, release_ports=True)
325 print "rate={0}, totalReceived={1}, totalSent={2}, frameLoss={3}"\
326 .format(rate, total_rcvd, total_sent, lost_a+lost_b)
328 def print_error(msg):
329 """Print error message on stderr.
331 :param msg: Error message to print.
336 sys.stderr.write(msg+'\n')
342 _traffic_options = {}
343 #default L3 profile is IPv4
345 #default warmup time is 5 seconds
347 #default behaviour of this script is sychronous
350 parser = argparse.ArgumentParser()
351 parser.add_argument("-d", "--duration", required=True, type=int,
352 help="Duration of traffic run")
353 parser.add_argument("-s", "--frame_size", required=True, type=int,
354 help="Size of a Frame without padding and IPG")
355 parser.add_argument("-r", "--rate", required=True,
356 help="Traffic rate with included units (%, pps)")
357 parser.add_argument("-6", "--use_IPv6", action="store_true",
358 help="Use IPv6 traffic profile instead of IPv4")
359 parser.add_argument("--async", action="store_true",
360 help="Non-blocking call of the script")
361 parser.add_argument("-w", "--warmup_time", type=int,
362 help="Traffic warmup time in seconds, 0 = disable")
363 # parser.add_argument("--p1_src_mac",
364 # help="Port 1 source MAC address")
365 # parser.add_argument("--p1_dst_mac",
366 # help="Port 1 destination MAC address")
367 parser.add_argument("--p1_src_start_ip", required=True,
368 help="Port 1 source start IP address")
369 parser.add_argument("--p1_src_end_ip", required=True,
370 help="Port 1 source end IP address")
371 parser.add_argument("--p1_dst_start_ip", required=True,
372 help="Port 1 destination start IP address")
373 # parser.add_argument("--p1_dst_end_ip",
374 # help="Port 1 destination end IP address")
375 # parser.add_argument("--p2_src_mac",
376 # help="Port 2 source MAC address")
377 # parser.add_argument("--p2_dst_mac",
378 # help="Port 2 destination MAC address")
379 parser.add_argument("--p2_src_start_ip", required=True,
380 help="Port 2 source start IP address")
381 parser.add_argument("--p2_src_end_ip", required=True,
382 help="Port 2 source end IP address")
383 parser.add_argument("--p2_dst_start_ip", required=True,
384 help="Port 2 destination start IP address")
385 # parser.add_argument("--p2_dst_end_ip",
386 # help="Port 2 destination end IP address")
388 args = parser.parse_args()
390 _duration = args.duration
391 _frame_size = args.frame_size
393 _use_ipv6 = args.use_IPv6
394 _async_call = args.async
396 if args.warmup_time is not None:
397 _warmup_time = args.warmup_time
399 for attr in [a for a in dir(args) if a.startswith('p')]:
400 if getattr(args, attr) is not None:
401 _traffic_options[attr] = getattr(args, attr)
404 pkt_a, pkt_b = create_packets_v6(_traffic_options,
405 frame_size=_frame_size)
407 pkt_a, pkt_b = create_packets(_traffic_options,
408 frame_size=_frame_size)
410 simple_burst(pkt_a, pkt_b, _duration, _rate, _warmup_time, _async_call)
412 if __name__ == "__main__":