Small fix to client config doc
[trex.git] / doc / trex_stateless.asciidoc
1 TRex Stateless support
2 ======================
3 :author: TRex team
4 :email: trex.tgen@gmail.com 
5 :revnumber: 2.01
6 :quotes.++:
7 :numbered:
8 :web_server_url: https://trex-tgn.cisco.com/trex
9 :local_web_server_url: csi-wiki-01:8181/trex
10 :github_stl_path: https://github.com/cisco-system-traffic-generator/trex-core/tree/master/scripts/stl
11 :github_stl_examples_path: https://github.com/cisco-system-traffic-generator/trex-core/tree/master/scripts/automation/trex_control_plane/stl/examples
12 :toclevels: 6
13
14 include::trex_ga.asciidoc[]
15
16 // PDF version - image width variable
17 ifdef::backend-docbook[]
18 :p_width: 450
19 :p_width_1: 200
20 :p_width_1a: 100
21 :p_width_1c: 150
22 :p_width_lge: 500
23 endif::backend-docbook[]
24
25 // HTML version - image width variable
26 ifdef::backend-xhtml11[]
27 :p_width: 800
28 :p_width_1: 400
29 :p_width_1a: 650
30 :p_width_1a: 400
31 :p_width_lge: 900
32 endif::backend-xhtml11[]
33
34
35
36 == Audience 
37
38 This document assumes basic knowledge of TRex, and assumes that TRex is installed and configured.
39 For information, see the link:trex_manual.html[manual], especially the material up to the link:trex_manual.html#_basic_usage[Basic Usage] section.
40
41 == Stateless support 
42
43 === High level functionality
44 // maybe Feature overview
45
46 * Large scale - Supports about 10-22 million packets per second (mpps) per core, scalable with the number of cores 
47 * Support for 1, 10, 25, 40, and 100 Gb/sec interfaces
48 * Support for multiple traffic profiles per interface
49 * Profile can support multiple streams, scalable to 10K parallel streams 
50 * Supported for each stream:
51 ** Packet template - ability to build any packet (including malformed) using link:https://en.wikipedia.org/wiki/Scapy[Scapy] (example: MPLS/IPv4/Ipv6/GRE/VXLAN/NSH) 
52 ** Field engine program
53 *** Ability to change any field inside the packet (example: src_ip = 10.0.0.1-10.0.0.255)
54 *** Ability to change the packet size (example: random packet size 64-9K)
55 ** Mode - Continuous/Burst/Multi-burst support
56 ** Rate can be specified as:
57 *** Packets per second (example: 14MPPS)
58 *** L1 bandwidth (example: 500Mb/sec)
59 *** L2 bandwidth (example: 500Mb/sec)
60 *** Interface link percentage (example: 10%)
61 ** Support for HLTAPI-like profile definition  
62 ** Action - stream can trigger a stream 
63 * Interactive support - Fast Console,  GUI 
64 * Statistics per interface
65 * Statistics per stream done in hardware
66 * Latency and Jitter per stream
67 * Blazingly fast automation support 
68 ** Python 2.7/3.0 Client API 
69 ** Python HLTAPI Client API
70 * Multi-user support - multiple users can interact with the same TRex instance simultaneously
71
72
73 ==== Traffic profile example
74
75 The following example shows three streams configured for Continuous, Burst, and Multi-burst traffic.
76
77 image::images/stl_streams_example_02.png[title="Example of multiple streams",align="left",width={p_width}, link="images/stl_streams_example_02.png"]
78
79
80 ==== High level functionality - Roadmap for future development
81
82 * Add emulation support 
83 ** RIP/BGP/ISIS/SPF
84
85
86 === IXIA IXExplorer vs TRex 
87
88 TRex has limited functionality compared to IXIA, but has some advantages. The following table summarizes the differences:
89
90 .TRex vs IXExplorer
91 [cols="1^,3^,3^,5^", options="header"]
92 |=================
93 | Feature       |  IXExplorer  |TRex | Description 
94 | Line rate       | Yes | 10-24MPPS/core, depends on the use case |
95 | Multi stream    | 255 | [green]*Unlimited* |
96 | Packet build flexibility | Limited | [green]*Scapy - Unlimited* | Example: GRE/VXLAN/NSH is supported. Can be extended to future protocols
97 | Packet Field engine      | limited | [green]*Unlimited* |
98 | Tx Mode | Continuous/Burst/Multi-burst | Continuous/Burst/Multi-burst|
99 | ARP Emulation | Yes | Not yet - workaround |
100 | Automation  | TCL/Python wrapper to TCL | [green]*native Python/Scapy*  |
101 | Automation speed sec| 30 sec | [green]*1 msec* | Test of load/start/stop/get counters 
102 | HLTAPI | Full support. 2000 pages of documentation |  Limited. 20 pages of documentation|
103 | Per Stream statistics | 255  streams with 4 global masks | 128 rules for XL710/X710 hardware and software impl for 82599/I350/X550| Some packet type restrictions apply to XL710/X710.
104 | Latency Jitter |  Yes,Resolution of nsec (hardware) | Yes,Resolution of usec (software)  |
105 | Multi-user support | Yes | Yes |
106 | GUI  | very good | WIP, packet build is scapy-based. Not the same as IXIA. Done by Exalt |
107 | Cisco pyATS support | Yes | Yes - Python 2.7/Python 3.4 |    
108 | Emulation | Yes | Not yet |
109 | Port IDs  | Based on IXIA numebrs  | Depends on PCI enumeration  
110 |=================
111
112
113 === RPC Architecture 
114
115 A JSON-RPC2 thread in the TRex control plane core provides support for interactive mode. 
116
117 // RPC = Remote Procedure Call, alternative to REST? --YES, no change
118
119 image::images/trex_architecture_01.png[title="RPC Server Components",align="left",width={p_width}, link="images/trex_architecture_01.png"]
120
121 // OBSOLETE: image::images/trex_2_stateless.png[title="RPC Server Components",align="left",width={p_width}, link="images/trex_2_stateless.png"]
122
123 // Is there a big picture that would help to make the next 11 bullet points flow with clear logic? --explanation of the figure
124
125 *Layers*::
126 * Control transport protocol: ZMQ working in REQ/RES mode. 
127 // change all ZMQ to "link:http://rfc.zeromq.org/spec:37[ZeroMQ] Message Transport Protocol (ZMTP)"? not sure what REQ/RES mode is
128 * RPC protocol on top of the control transport protocol: JSON-RPC2. 
129 * Asynchronous transport: ZMQ working in SUB/PUB mode (used for asynchronous events such as interface change mode, counters, and so on).
130
131 // TBD: rendering problem with bullet indentation
132 // Maybe Layers, Interfaces, and Control of Interfaces should each be level 4 headings instead of complex bulleted lists.
133
134
135
136 *Interfaces*::
137 * Automation API: Python is the first client to implement the Python automation API.
138 * User interface: The console uses the Python API to implement a user interface for TRex.
139 * GUI : The GUI works on top of the JSON-RPC2 layer.
140
141 *Control of TRex interfaces*::
142 * Numerous users can control a single TRex server together, from different interfaces. 
143 * Users acquire individual TRex interfaces exclusively. *Example*: Two users control a 4-port TRex server. User A acquires interfaces 0 and 1; User B acquires interfaces 3 and 4.
144 * Only one user interface (console or GUI) can have read/write control of a specific interface. This enables caching the TRex server interface information in the client core. *Example*: User A, with two acquired interfaces, can have only one read/write control session at a time. 
145 * A user can set up numerous read-only clients on a single interface - for example, for monitoring traffic statistics on the interface.
146 * A client in read-write mode can acquire a statistic in real time (with ASYNC ZMQ). This enables viewing statistics through numerous user interfaces (console and GUI) simultaneously.
147
148 *Synchronization*::
149 * A client syncs with the TRex server to get the state in connection time, and caches the server information locally after the state has changed. 
150 * If a client crashes or exits, it syncs again after reconnecting. 
151
152 image::images/trex_stateless_multi_user_02.png[title="Multiple users, per interface",align="left",width={p_width}, link="images/trex_stateless_multi_user_02.png"]
153
154 For details about the TRex RPC server, see the link:trex_rpc_server_spec.html[RPC specification].  
155
156 ==== RPC architecture highlights
157
158 This Architecture provides the following advantages:
159
160 * Fast interaction with TRex server. Loading, starting, and stopping a profile for an interface is very fast - about 2000 cycles/sec.
161 * Leverages Python/Scapy for building a packet/field engine.
162 * HLTAPI compiler complexity is handled in Python.
163
164 === TRex Objects 
165
166 // maybe call it "Objects" in title and figure caption
167
168 image::images/stateless_objects_02.png[title="TRex Objects",align="left",width={p_width_1}, link="images/stateless_objects_02.png"]
169
170 * *TRex*: Each TRex instance supports numerous interfaces. 
171 // "one or more"?
172 * *Interface*: Each interface supports one or more traffic profiles.
173 * *Traffic profile*: Each traffic profile supports one or more streams. 
174 * *Stream*: Each stream includes:
175 ** *Packet*: Packet template up to 9 KB 
176 // ok to standardize to KB? 
177 ** *Field Engine*: Which field to change, do we want to change packet size 
178 // unclear
179 ** *Mode*: Specifies how to send packets: Continuous/Burst/Multi-burst 
180 ** *Rx Stats*: Statistics to collect for each stream
181 ** *Rate*: Rate (packets per second or bandwidth) 
182 ** *Action*:  Specifies stream to follow when the current stream is complete (valid for Continuous or Burst modes).
183
184
185 === Stateful vs Stateless 
186
187 TRex Stateless support enables basic L2/L3 testing, relevant mostly for a switch or router. Using Statelss mode, it is possible to define a stream with a *one* packet template, define a program to change any fields in the packet, and run the stream in continuous, burst, or multi-burst mode.
188 With Stateless, you *cannot* learn NAT translation; there is no context of flow/client/server. 
189
190 * In Stateful mode, the basic building block is a flow/application (composed of many packets). 
191 * Stateless mode is much more flexible, enabling you to define any type of packet, and build a simple program. 
192
193 .Stateful vs Stateless features 
194 [cols="1^,3^,3^", options="header"]
195 |=================
196 | Feature       |  Stateless  |Stateful 
197 | Flow base       | No | Yes
198 | NAT             | No | Yes
199 | Tunnel          | Yes | Some are supported 
200 | L7 App emulation | No | Yes
201 | Any type of packet | Yes | No 
202 | Latency Jitter | Per Stream | Global/Per flow
203 |=================
204
205 ==== Using Stateless mode to mimic Stateful mode
206
207 Stateless mode can mimic some, but not all functionality of Stateful mode. 
208 For example, you can load a pcap with the number of packets as a link of streams:
209 a->b->c->d-> back to a
210 You can then create a program for each stream to change src_ip=10. 0.0.1-10.0.0.254. This creates traffic similar to that of Stateful mode, but with a completely different basis.
211
212 If you are confused you probably need Stateless. :-)
213
214 === TRex package folders 
215
216 [cols="5,5", options="header",width="100%"]
217 |=============================
218 | Location        | Description   
219 | /               | t-rex-64/dpdk_set_ports/stl-sim 
220 | /stl            | Stateless native (py) profiles 
221 | /stl/yaml       | Stateless YAML profiles 
222 | /stl/hlt        | Stateless HLT profiles 
223 | /ko             | Kernel modules for DPDK
224 | /external_libs  | Python external libs used by server/clients
225 | /exp            | Golden pcap file for unit-tests
226 | /cfg            | Examples of config files
227 | /cap2           | Stateful profiles 
228 | /avl            | Stateful profiles - SFR profile
229 | /automation     | Python client/server code for both Stateful and Stateless
230 | /automation/regression     | Regression for Stateless and Stateful
231 | /automation/config     | Regression setups config files
232 | /automation/trex_control_plane/stl     | Stateless lib and Console 
233 | /automation/trex_control_plane/stl/trex_stl_lib     | Stateless lib
234 | /automation/trex_control_plane/stl/examples     | Stateless Examples
235 |=============================
236
237 === Port Layer Mode Configuration
238
239 TRex ports can operate in two different mutual exclusive modes:
240
241 * *Layer 2 mode* - MAC level configuration
242 * *Layer 3 mode* - IPv4/IPv6 configuration
243
244 When configuring a port for L2 mode, it is only required to provide
245 the destination MAC address for the port (Legacy mode previous to v2.12 version).
246
247 When configuring a port for L3, it is required to provide both
248 source IPv4/IPv6 address and a IPv4/IPv6 destination address.
249
250 As an intergral part of configuring L3, the client will try to ARP resolve the
251 destination address and automatically configure the correct destination MAC.
252 (instead of sending ARP request when starting traffic)
253
254 [NOTE]
255 While in L3 mode, TRex server will generate *gratuitous ARP* packets to make sure
256 that no ARP timeout on the DUT/router will result in a faliure of the test.
257
258 .*Example of configuring L2 mode*
259 [source,bash]
260 ----
261
262 trex>service 
263
264 trex>l2 --help
265 usage: port [-h] --port PORT --dst DST_MAC
266
267 Configures a port in L2 mode
268
269 optional arguments:
270   -h, --help            show this help message and exit
271   --port PORT, -p PORT  source port for the action
272   --dst DST_MAC         Configure destination MAC address
273
274
275 trex(service)>l2 -p 0 --dst 6A:A7:B5:3A:4E:FF
276
277 Setting port 0 in L2 mode:                                   [SUCCESS]
278
279 trex>service --off
280
281 ----
282
283
284 .*Example of configuring L2 mode- Python API*
285 [source,Python]
286 ----
287   client.set_service_mode(port = 0, enabled = True)
288
289   client.set_l2_mode(port = 0, dst_mac = "6A:A7:B5:3A:4E:FF")
290
291   client.set_service_mode(port = 0, enabled = False)
292
293 ----
294
295
296 .*Example of configuring L3 mode- Console*
297 [source,bash]
298 ----
299
300 trex>service 
301
302
303 trex(service)>l3 --help
304 usage: port [-h] --port PORT --src SRC_IPV4 --dst DST_IPV4
305
306 Configures a port in L3 mode
307
308 optional arguments:
309   -h, --help            show this help message and exit
310   --port PORT, -p PORT  source port for the action
311   --src SRC_IPV4        Configure source IPv4 address
312   --dst DST_IPV4        Configure destination IPv4 address
313
314 trex(service)>l3 -p 0 --src 1.1.1.2 --dst 1.1.1.1
315
316 Setting port 0 in L3 mode:                                   [SUCCESS]
317
318
319 ARP resolving address '1.1.1.1':                             [SUCCESS]
320
321 trex>service --off
322
323 ----
324
325
326 .*Example of configuring L3 mode - Python API*
327 [source,python]
328 ----
329
330 client.set_service_mode(port = 0, enabled = True)
331
332 client.set_l3_mode(port = 0, src_ipv4 = '1.1.1.2', dst_ipv4 = '1.1.1.1')
333
334 client.set_service_mode(port = 0, enabled = False)
335
336 ----
337
338 === Port Service Mode
339
340 In 'normal operation mode', to preserve high speed processing of packets,
341 TRex ignores most of the RX traffic, with the exception of counting/statistic and handling
342 latency flows.
343
344
345 In the following diagram it is illustrated how RX packets are handled.
346 Only a portion is forwarded to the RX handling module and none of forward back
347 to the Python client.
348
349 image::images/port_normal_mode.png[title="Port Under Normal Mode",align="left",width={p_width}, link="images/port_normal_mode.png"]
350
351
352
353 We provide another mode called 'service mode' in which a port will respond to ping, ARP requests
354 and also provide a capabality in this mode to forward packets to the Python control plane for
355 applying full duplex protocols (DCHP, IPv6 neighboring and etc.)
356
357 The following diagram illustrates of packets can be forwarded back to the Python client
358
359 image::images/port_service_mode.png[title="Port Under Service Mode",align="left",width={p_width}, link="images/port_service_mode.png"]
360
361 In this mode, it is possible to write python plugins for emulation (e.g. IPV6 ND/DHCP) to prepare the setup and then move to normal mode for high speed testing 
362
363
364 *Example Of Switcing Between 'Service' And 'Normal' Mode*
365 [source,bash]
366 ----
367
368 trex(service)>service --help
369 usage: service [-h] [--port PORTS [PORTS ...] | -a] [--off]
370
371 Configures port for service mode. In service mode ports will reply to ARP,
372 PING and etc.
373
374 optional arguments:
375   -h, --help            show this help message and exit
376   --port PORTS [PORTS ...], -p PORTS [PORTS ...]
377                         A list of ports on which to apply the command
378   -a                    Set this flag to apply the command on all available
379                         ports
380   --off                 Deactivates services on port(s)
381
382
383 trex>service
384
385 Enabling service mode on port(s) [0, 1]:                     [SUCCESS]
386
387 trex(service)>service --off
388
389 Disabling service mode on port(s) [0, 1]:                    [SUCCESS]
390
391 ----
392
393 .*Example Of Switcing Between 'Service' And 'Normal' Mode-API*
394 [source,Python]
395 ----
396
397   client.set_service_mode(ports = [0, 1], enabled = True)
398   
399   client.set_service_mode(ports = [0, 1], enabled = False)
400
401 ----
402
403 ==== ARP / ICMP response
404 [IMPORTANT]
405 Only while in service mode, ports will reply to ICMP echo requests and ARP requests.
406
407
408 === Neighboring Protocols
409 As mentioned, in order to preserve high speed traffic generation,
410 TRex handles neighboring protocols in pre test phase.
411
412 A test that requires running a neighboring protocol should first move
413 to 'service mode', execute the required steps in Python, switch back to 'normal mode'
414 and start the actual test.
415
416 ==== ARP
417 A basic neighboring protocol that is provided as part of TRex is ARP.
418
419 For example, let's take a look at the following setup:
420
421 image::images/router_arp.png[title="Router ARP",align="left",width={p_width}, link="images/router_arp.png"]
422
423 [source,bash]
424 ----
425
426 trex>service                                                                   #<1> 
427
428 Enabling service mode on port(s) [0, 1]:                     [SUCCESS]   
429
430 trex(service)>portattr  --port 0
431
432              port       |          0           |  
433         ------------------------------------------
434         driver          |    rte_ixgbe_pmd     |  
435         description     |  82599EB 10-Gigabit  |  
436         link status     |          UP          |  
437         link speed      |       10 Gb/s        |  
438         port status     |         IDLE         |  
439         promiscuous     |         off          |  
440         flow ctrl       |         none         |  
441         --              |                      |  
442         src IPv4        |          -           |  
443         src MAC         |  00:00:00:01:00:00   |  
444         ---             |                      |  
445         Destination     |  00:00:00:01:00:00   |  
446         ARP Resolution  |          -           |  
447         ----            |                      |  
448         PCI Address     |     0000:03:00.0     |  
449         NUMA Node       |          0           |  
450         -----           |                      |  
451         RX Filter Mode  |    hardware match    |  
452         RX Queueing     |         off          |  
453         RX sniffer      |         off          |  
454         Grat ARP        |         off          |  
455
456
457 trex(service)>l3 -p -s 1.1.1.1 -d 1.1.1.2                         #<2> 
458
459 trex(service)>arp -p 0 1                                          #<3>
460
461 Resolving destination on port(s) [0, 1]:                     [SUCCESS]
462
463
464 Port 0 - Recieved ARP reply from: 1.1.1.1, hw: d0:d0:fd:a8:a1:01
465 Port 1 - Recieved ARP reply from: 1.1.2.1, hw: d0:d0:fd:a8:a1:02
466
467 trex(service)>service --off                                       #<4>
468
469 ----
470 <1> Enable service mode 
471 <2> Set IPv4/default gateway. it will resolve the arp
472 <3> repeat ARP resolution
473 <4> exist from service mode 
474  
475
476
477 to revert  back to MAC address mode (without ARP resolution) you do the following 
478
479 .Disable L3 mode
480 [source,bash]
481 ----
482
483 trex>l2 -p 0 --dst 00:00:00:01:00:00       #<1>
484
485 trex>portattr  --port 0
486
487              port       |          0           |  
488         ------------------------------------------
489         driver          |    rte_ixgbe_pmd     |  
490         description     |  82599EB 10-Gigabit  |  
491         link status     |          UP          |  
492         link speed      |       10 Gb/s        |  
493         port status     |         IDLE         |  
494         promiscuous     |         off          |  
495         flow ctrl       |         none         |  
496         --              |                      |  
497         src IPv4        |          -           |  
498         src MAC         |  00:00:00:01:00:00   |  
499         ---             |                      |  
500         Destination     |  00:00:00:01:00:00   |  
501         ARP Resolution  |          -           |  
502         ----            |                      |  
503         PCI Address     |     0000:03:00.0     |  
504         NUMA Node       |          0           |  
505         -----           |                      |  
506         RX Filter Mode  |    hardware match    |  
507         RX Queueing     |         off          |  
508         RX sniffer      |         off          |  
509         Grat ARP        |         off          |  
510         
511 ----
512 <1> disable service mode 
513
514
515
516 .Python API:
517 [source,python]
518 ----
519
520 client.set_service_mode(ports = [0, 1], enabled = True)                  <1>
521
522 # configure port 0, 1 to Layer 3 mode
523 client.set_l3_mode(port = 0, src_ipv4 = '1.1.1.2', dst_ipv4 = '1.1.1.2') <2>
524 client.set_l3_mode(port = 1, src_ipv4 = '1.1.2.2', dst_ipv4 = '1.1.2.1') 
525     
526 # ARP resolve ports 0, 1
527 c.resolve(ports = [0, 1])
528
529 client.set_service_mode(ports = [0, 1], enabled = False)                 <3>
530
531 ----
532 <1> Enable service mode
533 <2> configure IPv4 and Default Gateway 
534 <3> Disable service mode
535
536 ==== ICMP
537
538 Another basic protocol provided with TRex is ICMP.
539 It is possible, under service mode to ping the DUT or even a TRex port
540 from the console / API.
541
542 .TRex Console
543 [source,bash]
544 ----
545
546 trex(service)>ping --help
547 usage: ping [-h] --port PORT -d PING_IPV4 [-s PKT_SIZE] [-n COUNT]
548
549 pings the server / specific IP
550
551 optional arguments:
552   -h, --help            show this help message and exit
553   --port PORT, -p PORT  source port for the action
554   -d PING_IPV4          which IPv4 to ping
555   -s PKT_SIZE           packet size to use
556   -n COUNT, --count COUNT
557                         How many times to ping [default is 5]
558
559 trex(service)>ping -p 0 -d 1.1.2.2
560
561 Pinging 1.1.2.2 from port 0 with 64 bytes of data:
562 Reply from 1.1.2.2: bytes=64, time=27.72ms, TTL=127
563 Reply from 1.1.2.2: bytes=64, time=1.40ms, TTL=127
564 Reply from 1.1.2.2: bytes=64, time=1.31ms, TTL=127
565 Reply from 1.1.2.2: bytes=64, time=1.78ms, TTL=127
566 Reply from 1.1.2.2: bytes=64, time=1.95ms, TTL=127
567
568 ----
569
570
571
572 .Python API
573 [source,python]
574 ----
575
576 # move to service mode
577 client.set_service_mode(ports = ports, enabled = True)
578     
579 # configure port 0, 1 to Layer 3 mode
580 client.set_l3_mode(port = 0, src_ipv4 = '1.1.1.2', dst_ipv4 = '1.1.1.1')
581 client.set_l3_mode(port = 1, src_ipv4 = '1.1.2.2', dst_ipv4 = '1.1.2.1')
582
583 # ping port 1 from port 0 through the router
584 client.ping_ip(src_port = 0, dst_ipv4 = '1.1.2.2', pkt_size = 64)        <1>
585     
586 # disable service mode
587 client.set_service_mode(enabled = False)
588
589 ----
590 <1> Check connectivity
591
592
593 ==== IPv6 ND/DHCP client
594
595 in progress 
596
597
598 === Tutorials
599
600 The tutorials in this section demonstrate basic TRex *stateless* use cases. Examples include common and moderately advanced TRex concepts.
601
602 ==== Tutorial: Simple IPv4/UDP packet - TRex 
603
604 *Goal*:: 
605
606 Send a simple UDP packet from all ports of a TRex server.
607
608 *Traffic profile*::  
609
610 The following profile defines one stream, with an IP/UDP packet template with 10 bytes of 'x'(0x78) of payload. For more examples of defining packets using Scapy see the  link:http://www.secdev.org/projects/scapy/doc/[Scapy documentation].
611
612 *File*:: 
613
614 link:{github_stl_path}/udp_1pkt_simple.py[stl/udp_1pkt_simple.py]
615
616 [source,python]
617 ----
618 from trex_stl_lib.api import *                                  
619
620 class STLS1(object):
621
622     def create_stream (self):
623
624         return STLStream( 
625             packet = 
626                     STLPktBuilder(
627                         pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/
628                                 UDP(dport=12,sport=1025)/(10*'x')                       <1>                
629                     ),
630              mode = STLTXCont())                                                        <2>
631
632
633     def get_streams (self, direction = 0, **kwargs):                                              <3>
634         # create 1 stream 
635         return [ self.create_stream() ]
636
637
638 # dynamic load - used for TRex console or simulator
639 def register():                                                                         <4>        
640     return STLS1()
641 ----
642 <1> Defines the packet. In this case, the packet is IP/UDP with 10 bytes of 'x'. For more information, see the link:http://www.secdev.org/projects/scapy/doc/[Scapy documentation].
643 <2> Mode: Continuous. Rate: 1 PPS (default rate is 1 PPS)
644 <3> The `get_streams` function is mandatory 
645 <4> Each traffic profile module requires a `register` function. 
646
647 [NOTE] 
648 =====================================================================
649 The SRC/DST MAC addresses are taken from /etc/trex_cfg.yaml. To change them, add Ether(dst="00:00:dd:dd:00:01") with the desired destination.
650 =====================================================================
651
652
653 *Start TRex as a server*::   
654
655 [NOTE] 
656 =====================================================================
657 The TRex package includes all required packages. It is unnecessary to install any python packages (including Scapy). 
658 =====================================================================
659
660 [source,bash]
661 ----
662 $sudo ./t-rex-64 -i
663 ----
664
665 * Wait until the server is up and running. 
666 * (Optional) Use `-c` to add more cores.
667 * (Optional) Use `--cfg` to specify a different configuration file. The default is link:trex_manual.html#_create_minimum_configuration_file[/etc/trex_cfg.yaml].
668
669 // IGNORE: this line helps rendering of next line
670
671 *Connect with console*::
672
673 On the same machine, in a new terminal window (open a new window using `xterm`, or `ssh` again), connect to TRex using `trex-console`. 
674
675 [source,bash]
676 ----
677 $trex-console                                                           #<1>
678
679 Connecting to RPC server on localhost:4501                   [SUCCESS]
680 connecting to publisher server on localhost:4500             [SUCCESS]
681 Acquiring ports [0, 1, 2, 3]:                                [SUCCESS]
682
683 125.69 [ms]
684
685 trex>start -f stl/udp_1pkt_simple.py -m 10mbps -a                      #<2>
686
687 Removing all streams from port(s) [0, 1, 2, 3]:              [SUCCESS]
688 Attaching 1 streams to port(s) [0, 1, 2, 3]:                 [SUCCESS]
689 Starting traffic on port(s) [0, 1, 2, 3]:                    [SUCCESS]
690
691 # pause  the traffic on all port
692 >pause -a                                                               #<3>
693
694 # resume  the traffic on all port
695 >resume -a                                                              #<4>
696
697 # stop traffic on all port      
698 >stop -a                                                                #<5>
699
700 # show dynamic statistic 
701 >tui
702 ----
703 <1> Connects to the TRex server from the local machine.
704 <2> Start the traffic on all ports at 10 mbps. Can also specify as MPPS. Example: 14 MPPS (`-m 14mpps`).
705 <3> Pauses the traffic.
706 <4> Resumes.
707 <5> Stops traffic on all the ports.
708
709
710 [NOTE] 
711 =====================================================================
712 If you have a connection *error*, open the /etc/trex_cfg.yaml file and remove keywords such as `enable_zmq_pub : true` and `zmq_pub_port   : 4501`  from the file. 
713 =====================================================================
714
715 *Viewing streams*::
716
717 To display stream data for all ports, use `streams -a`. 
718
719 .Streams
720 [source,bash]
721 ----
722 trex>streams -a
723 Port 0:
724
725     ID |     packet type     |  length  |       mode       |  rate     | next stream 
726   -----------------------------------------------------------------------------------
727     1  | Ethernet:IP:UDP:Raw |       56 |    Continuous    |  1.00 pps |      -1     
728
729 Port 1:
730
731     ID |     packet type     |  length  |       mode       |  rate     | next stream 
732   -----------------------------------------------------------------------------------
733     1  | Ethernet:IP:UDP:Raw |       56 |    Continuous    |  1.00 pps |      -1     
734
735 Port 2:
736
737     ID |     packet type     |  length  |       mode       |  rate     | next stream 
738   -----------------------------------------------------------------------------------
739     1  | Ethernet:IP:UDP:Raw |       56 |    Continuous    |  1.00 pps |      -1     
740
741 Port 3:
742
743     ID |     packet type     |  length  |       mode       |  rate     | next stream 
744   -----------------------------------------------------------------------------------
745     1  | Ethernet:IP:UDP:Raw |       56 |    Continuous    |  1.00 pps |      -1     
746 ----
747
748
749 *Viewing command help*::
750
751
752 To view help for a command, use `<command> --help`.
753
754 *Viewing general statistics*::
755
756 To view general statistics, open a "textual user interface" with `tui`.
757
758 [source,bash]
759 ----
760 TRex >tui
761 Global Statistics
762
763 Connection  : localhost, Port 4501 
764 Version     : v1.93, UUID: N/A     
765 Cpu Util    : 0.2%                 
766             :                      
767 Total Tx L2 : 40.01 Mb/sec         
768 Total Tx L1 : 52.51 Mb/sec         
769 Total Rx    : 40.01 Mb/sec         
770 Total Pps   : 78.14 Kpkt/sec       
771             :                      
772 Drop Rate   : 0.00 b/sec           
773 Queue Full  : 0 pkts               
774
775 Port Statistics
776
777    port    |         0          |         1          |     
778  --------------------------------------------------------
779  owner      |             hhaim |             hhaim |    
780  state      |            ACTIVE |            ACTIVE |    
781  --         |                   |                   |    
782  Tx bps L2  |        10.00 Mbps |        10.00 Mbps |    
783  Tx bps L1  |        13.13 Mbps |        13.13 Mbps |    
784  Tx pps     |        19.54 Kpps |        19.54 Kpps |    
785  Line Util. |            0.13 % |            0.13 % |    
786  ---        |                   |                   |    
787  Rx bps     |        10.00 Mbps |        10.00 Mbps |    
788  Rx pps     |        19.54 Kpps |        19.54 Kpps |    
789  ----       |                   |                   |    
790  opackets   |           1725794 |           1725794 |    
791  ipackets   |           1725794 |           1725794 |    
792  obytes     |         110450816 |         110450816 |    
793  ibytes     |         110450816 |         110450816 |    
794  tx-bytes   |         110.45 MB |         110.45 MB |    
795  rx-bytes   |         110.45 MB |         110.45 MB |    
796  tx-pkts    |        1.73 Mpkts |        1.73 Mpkts |    
797  rx-pkts    |        1.73 Mpkts |        1.73 Mpkts |    
798  -----      |                   |                   |    
799  oerrors    |                 0 |                 0 |    
800  ierrors    |                 0 |                 0 |    
801
802  status:  /
803
804  browse:     'q' - quit, 'g' - dashboard, '0-3' - port display
805  dashboard:  'p' - pause, 'c' - clear, '-' - low 5%, '+' - up 5%, 
806 ----
807
808
809 *Discussion*::
810
811 In this example TRex sends the *same* packet from all ports. If your setup is connected with loopback, you will see Tx packets from port 0 in Rx port 1 and vice versa.  If you have DUT with static route, you might see all the packets going to specific port.
812
813 .Static route
814 [source,bash]
815 ----
816 interface TenGigabitEthernet0/0/0       
817  mtu 9000 
818  ip address 1.1.9.1 255.255.255.0
819 !         
820 interface TenGigabitEthernet0/1/0       
821  mtu 9000 
822  ip address 1.1.10.1 255.255.255.0
823 !         
824
825 ip route 16.0.0.0 255.0.0.0 1.1.9.2     
826 ip route 48.0.0.0 255.0.0.0 1.1.10.2    
827 ----
828
829 // this is good info, but it isn't organized into specific tasks or explanations of specific goals. so comes across as useful but somewhat random. for example in the Static route example above, we should explain at the beginning that this will route all packets to one port, and that the next example will demonstrate how to route the packets to different ports.
830
831 In this example all the packets will be routed to `TenGigabitEthernet0/1/0` port. The following example uses the `direction` flag to change this.
832
833 *File*:: link:{github_stl_path}/udp_1pkt_simple_bdir.py[stl/udp_1pkt_simple_bdir.py]
834
835 [source,python]
836 ----
837
838  class STLS1(object):
839
840     def create_stream (self):
841         return STLStream( 
842             packet = 
843                     STLPktBuilder(
844                         pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/
845                                 UDP(dport=12,sport=1025)/(10*'x')
846                     ),
847              mode = STLTXCont())
848
849     def get_streams (self, direction = 0, **kwargs):
850         # create 1 stream 
851         if direction==0:                                                        <1>
852             src_ip="16.0.0.1"
853             dst_ip="48.0.0.1"
854         else:
855             src_ip="48.0.0.1"
856             dst_ip="16.0.0.1"
857
858         pkt   = STLPktBuilder(
859                               pkt = Ether()/IP(src=src_ip,dst=dst_ip)/
860                               UDP(dport=12,sport=1025)/(10*'x') )
861
862         return [ STLStream( packet = pkt,mode = STLTXCont()) ]
863 ----
864 <1> This use of the `direction` flag causes a different packet to be sent for each direction.
865
866
867 ==== Tutorial: Connect from a remote server 
868
869 *Goal*:: Connect by console from remote machine to a TRex server
870
871 *Check that TRex server is operational*::
872
873 Ensure that the TRex server is running. If not, run TRex in interactive mode.
874 // again, this is a bit vague. the tutorial should provide simple steps for using interactive mode or not. too many conditions.
875
876 [source,bash]
877 ----
878 $sudo ./t-rex-64 -i
879 ----
880
881 *Connect with Console*::
882
883 From a remote machine, use `trex-console` to connect. Include the `-s` flag, as shown below, to specify the server.
884
885 [source,bash]
886 ----
887 $trex-console -s csi-kiwi-02  #<1>
888 ----
889 <1> TRex server is csi-kiwi-02.
890
891 The TRex client requires Python versions 2.7.x or 3.4.x. To change the Python version, set the *PYTHON* environment variable as follows:
892
893 .tcsh shell
894 [source,bash]
895 ----
896 setenv PYTHON /bin/python     #tcsh
897 ----
898
899 .bash shell
900 [source,bash]
901 ----
902 extern PYTHON=/bin/mypython    #bash
903 ----
904
905 [NOTE]
906 =====================================================================
907 The client machine should run Python 2.7.x or 3.4.x. Cisco CEL/ADS is supported. The TRex package includes the required link:cp_stl_docs/[client archive].
908 =====================================================================
909
910 ==== Tutorial: Source and Destination MAC addresses
911
912 *Goal*:: Change the source/destination MAC address
913
914 Each TRex port has a source and destination MAC (DUT) configured in the /etc/trex_cfg.yaml configuration file. The source MAC is not necessarily the hardware MAC address configured in EEPROM. By default, the hardware-specified MAC addresses (source and destination) are used. If a source or destination MAC address is configured explicitly, that address takes precedence over the hardware-specified default.
915
916 .MAC address
917 [format="csv",cols="2^,2^,2^", options="header",width="100%"]
918 |=================
919 Scapy , Source MAC,Destination MAC
920 Ether() , trex_cfg (src),trex_cfg(dst)
921 Ether(src="00:bb:12:34:56:01"),"00:bb:12:34:56:01",trex_cfg(dst)
922 Ether(dst="00:bb:12:34:56:01"),trex_cfg(src),"00:bb:12:34:56:01"
923 |=================
924
925
926 *File*:: link:{github_stl_path}/udp_1pkt_1mac_override.py[stl/udp_1pkt_1mac_override.py]
927
928 [source,python]
929 ----
930     def create_stream (self):
931
932         base_pkt =  Ether(src="00:bb:12:34:56:01")/      <1>
933                     IP(src="16.0.0.1",dst="48.0.0.1")/
934                     UDP(dport=12,sport=1025)  
935 ----
936 <1> Specifying the source interface MAC replaces the default specified in the configuration YAML file.
937
938
939 [IMPORTANT]
940 =====================================
941 TRex port will receive a packet only if the packet's destination MAC matches the HW Src MAC defined for that port in the `/etc/trex_cfg.yaml` configuration file. Alternatively, a port can be put into link:https://en.wikipedia.org/wiki/Promiscuous_mode[promiscuous mode], allowing the port to receive all packets on the line. The port can be configured to promiscuous mode by API or by the following command at the console: `portattr -a --prom`.
942 =====================================
943
944 To set ports to link:https://en.wikipedia.org/wiki/Promiscuous_mode[promiscuous mode] and show the port status:
945
946 [source,bash]
947 ----
948 trex>portattr -a --prom on                                          #<1> 
949 trex>stats --ps
950 Port Status
951
952      port       |          0           |          1           |     
953   ---------------------------------------------------------------
954 driver          |    rte_ixgbe_pmd     |    rte_ixgbe_pmd     |     
955 maximum         |       10 Gb/s        |       10 Gb/s        |     
956 status          |         IDLE         |         IDLE         |     
957 promiscuous     |         on           |         on           |     #<2>
958   --            |                      |                      | 
959 HW src mac      |  90:e2:ba:36:33:c0   |  90:e2:ba:36:33:c1   | 
960 SW src mac      |  00:00:00:01:00:00   |  00:00:00:01:00:00   | 
961 SW dst mac      |  00:00:00:01:00:00   |  00:00:00:01:00:00   | 
962   ---           |                      |                      |     
963 PCI Address     |     0000:03:00.0     |     0000:03:00.1     |     
964 NUMA Node       |          0           |          0           |   
965 ----
966 <1> Configures all ports to promiscuous mode.
967 <2> Indicates port promiscuous mode status.
968
969 To change ports to promiscuous mode by Python API:
970
971 .Python API to change ports to promiscuous mode
972 [source,python]
973 ----
974         c = STLClient(verbose_level = LoggerApi.VERBOSE_REGULAR)
975
976         c.connect()
977
978         my_ports=[0,1]
979
980         # prepare our ports
981         c.reset(ports = my_ports)
982
983         # port info, mac-addr info, speed
984         print c.get_port_info(my_ports)                         <1>
985         
986         c.set_port_attr(my_ports, promiscuous = True)           <2>
987 ----
988 <1> Get port info for all ports.
989 <2> Change the port attribute to `promiscuous = True`.
990
991 For more information see the link:cp_stl_docs/api/client_code.html[Python Client API].
992
993
994 [NOTE] 
995 =====================================================================
996 An interface is not set to promiscuous mode by default. Typically, after changing the port to promiscuous mode for a specific test, it is advisable to change it back to non-promiscuous mode.
997 =====================================================================
998
999 ==== Tutorial: Python automation 
1000
1001 *Goal*:: Simple automation test using Python from a local or remote machine 
1002
1003 *Directories*::
1004
1005 Python API examples: `automation/trex_control_plane/stl/examples`.
1006
1007 Python API library: `automation/trex_control_plane/stl/trex_stl_lib`.
1008
1009 The TRex console uses the Python API library to interact with the TRex server using the JSON-RPC2 protocol over ZMQ.
1010
1011 image::images/trex_architecture_01.png[title="RPC Server Components",align="left",width={p_width}, link="images/trex_architecture_01.png"]
1012
1013 // OBSOLETE: image::images/trex_2_stateless.png[title="RPC Server Components",align="left",width={p_width}, link="images/trex_2_stateless.png"]
1014
1015 *File*:: link:{github_stl_examples_path}/stl_bi_dir_flows.py[stl_bi_dir_flows.py]
1016
1017
1018 [source,python]
1019 ----
1020 import stl_path                                                            <1>
1021 from trex_stl_lib.api import *                                             <2>               
1022
1023 import time
1024 import json
1025
1026 # simple packet creation                                                   <3>
1027 def create_pkt (size, direction):
1028
1029     ip_range = {'src': {'start': "10.0.0.1", 'end': "10.0.0.254"},
1030                 'dst': {'start': "8.0.0.1",  'end': "8.0.0.254"}}
1031
1032     if (direction == 0):
1033         src = ip_range['src']
1034         dst = ip_range['dst']
1035     else:
1036         src = ip_range['dst']
1037         dst = ip_range['src']
1038
1039     vm = [
1040         # src                                                               <4>
1041         STLVmFlowVar(name="src",
1042                      min_value=src['start'],
1043                      max_value=src['end'],
1044                      size=4,op="inc"),
1045         STLVmWrFlowVar(fv_name="src",pkt_offset= "IP.src"),
1046
1047         # dst
1048         STLVmFlowVar(name="dst",
1049                      min_value=dst['start'],
1050                      max_value=dst['end'],
1051                      size=4,op="inc"),
1052         STLVmWrFlowVar(fv_name="dst",pkt_offset= "IP.dst"),
1053
1054         # checksum
1055         STLVmFixIpv4(offset = "IP")
1056         ]
1057
1058
1059     base = Ether()/IP()/UDP()
1060     pad = max(0, len(base)) * 'x'
1061
1062     return STLPktBuilder(pkt = base/pad,
1063                          vm  = vm)
1064
1065                                                                             
1066 def simple_burst ():
1067  
1068     # create client
1069     c = STLClient() 
1070                     # username/server can be changed those are the default
1071                     # username = common.get_current_user(),
1072                     # server = "localhost"
1073                     # STLClient(server = "my_server",username ="trex_client") for example 
1074     passed = True
1075
1076     try:
1077         # turn this on for some information
1078         #c.set_verbose("high")
1079
1080         # create two streams
1081         s1 = STLStream(packet = create_pkt(200, 0),
1082                        mode = STLTXCont(pps = 100))
1083
1084         # second stream with a phase of 1ms (inter stream gap)
1085         s2 = STLStream(packet = create_pkt(200, 1),
1086                        isg = 1000,
1087                        mode = STLTXCont(pps = 100))
1088
1089
1090         # connect to server
1091         c.connect()                                                                <5>
1092                                                                                         
1093         # prepare our ports (my machine has 0 <--> 1 with static route)
1094         c.reset(ports = [0, 1]) #  Acquire port 0,1 for $USER                      <6>
1095
1096         # add both streams to ports
1097         c.add_streams(s1, ports = [0])
1098         c.add_streams(s2, ports = [1])
1099
1100         # clear the stats before injecting
1101         c.clear_stats()
1102
1103         # choose rate and start traffic for 10 seconds on 5 mpps
1104         print "Running 5 Mpps on ports 0, 1 for 10 seconds..."
1105         c.start(ports = [0, 1], mult = "5mpps", duration = 10)                     <7>
1106
1107         # block until done
1108         c.wait_on_traffic(ports = [0, 1])                                          <8>
1109
1110         # read the stats after the test
1111         stats = c.get_stats()                                                      <9>
1112
1113         print json.dumps(stats[0], indent = 4, separators=(',', ': '), sort_keys = True)
1114         print json.dumps(stats[1], indent = 4, separators=(',', ': '), sort_keys = True)
1115
1116         lost_a = stats[0]["opackets"] - stats[1]["ipackets"]
1117         lost_b = stats[1]["opackets"] - stats[0]["ipackets"]                       
1118
1119         print "\npackets lost from 0 --> 1:   {0} pkts".format(lost_a)
1120         print "packets lost from 1 --> 0:   {0} pkts".format(lost_b)
1121
1122         if (lost_a == 0) and (lost_b == 0):
1123             passed = True
1124         else:
1125             passed = False
1126
1127     except STLError as e:
1128         passed = False
1129         print e
1130
1131     finally:
1132         c.disconnect()                                                             <10>    
1133
1134     if passed:
1135         print "\nTest has passed :-)\n"
1136     else:
1137         print "\nTest has failed :-(\n"
1138
1139
1140 # run the tests
1141 simple_burst()
1142 ----
1143 <1> Imports the stl_path. The path here is specific to this example. When configuring, provide the path to your stl_trex library.
1144 <2> Imports TRex Stateless library. When configuring, provide the path to your TRex Stateless library.
1145 <3> Creates packet per direction using Scapy.
1146 <4> See the Field Engine section for information.
1147 <5> Connects to the local TRex. Username and server can be added. 
1148 <6> Acquires the ports. 
1149 <7> Loads the traffic profile and start generating traffic.
1150 <8> Waits for the traffic to be finished. There is a polling function so you can test do something while waiting.
1151 <9> Get port statistics.
1152 <10> Disconnects.
1153
1154 See link:cp_stl_docs/index.html[TRex Stateless Python API] for details about using the Python APIs. 
1155
1156
1157 ==== Tutorial: HLT Python API 
1158
1159 HLT Python API is a layer on top of the native layer. It supports the standard Cisco traffic generator API. For more information, see Cisco/IXIA/Spirent documentation.
1160 TRex supports limited number of HLTAPI arguments and the recommendation is to use the native API due to the flexibility and simplicity.
1161
1162 Supported HLT Python API classes:
1163
1164 * Device Control
1165 ** connect
1166 ** cleanup_session
1167 ** device_info
1168 ** info
1169 * Interface
1170 ** interface_config
1171 ** interface_stats
1172 * Traffic
1173 ** traffic_config - not all arguments are supported  
1174 ** traffic_control
1175 ** traffic_stats
1176
1177 // IGNORE: This line simply ends the bulletted section so that the next line will be formatted correctly.
1178
1179 For details, see link:#_hlt_supported_arguments_a_id_altapi_support_a[Appendix]
1180 // confirm link above
1181
1182 *File*:: link:{github_stl_examples_path}/hlt_udp_simple.py[hlt_udp_simple.py]
1183
1184
1185 [source,python]
1186 ----
1187
1188 import sys
1189 import argparse
1190 import stl_path
1191 from trex_stl_lib.api import *                                          <1>
1192 from trex_stl_lib.trex_stl_hltapi import *                              <2>
1193
1194
1195 if __name__ == "__main__":
1196     parser = argparse.ArgumentParser(usage=""" 
1197     Connect to TRex and send burst of packets
1198
1199     examples
1200
1201      hlt_udp_simple.py -s 9000 -d 30
1202
1203      hlt_udp_simple.py -s 9000 -d 30 -rate_percent 10
1204
1205      hlt_udp_simple.py -s 300 -d 30 -rate_pps 5000000
1206
1207      hlt_udp_simple.py -s 800 -d 30 -rate_bps 500000000 --debug
1208
1209      then run the simulator on the output 
1210        ./stl-sim -f example.yaml -o a.pcap  ==> a.pcap include the packet
1211
1212     """,
1213     description="Example for TRex HLTAPI",
1214     epilog=" based on hhaim's stl_run_udp_simple example")
1215
1216     parser.add_argument("--ip", 
1217                         dest="ip",
1218                         help='Remote trex ip',
1219                         default="127.0.0.1",
1220                         type = str)
1221
1222     parser.add_argument("-s", "--frame-size", 
1223                         dest="frame_size",
1224                         help='L2 frame size in bytes without FCS',
1225                         default=60,
1226                         type = int,)
1227
1228     parser.add_argument('-d','--duration', 
1229                         dest='duration',
1230                         help='duration in second ',
1231                         default=10,
1232                         type = int,)
1233
1234     parser.add_argument('--rate-pps', 
1235                         dest='rate_pps',
1236                         help='speed in pps',
1237                         default="100")
1238
1239     parser.add_argument('--src', 
1240                         dest='src_mac',
1241                         help='src MAC',
1242                         default='00:50:56:b9:de:75')
1243
1244     parser.add_argument('--dst', 
1245                         dest='dst_mac',
1246                         help='dst MAC',
1247                         default='00:50:56:b9:34:f3')
1248
1249     args = parser.parse_args()
1250
1251     hltapi = CTRexHltApi()
1252     print 'Connecting to TRex'
1253     res = hltapi.connect(device = args.ip, port_list = [0, 1], reset = True, break_locks = True)
1254     check_res(res)
1255     ports = res['port_handle']
1256     if len(ports) < 2:
1257         error('Should have at least 2 ports for this test')
1258     print 'Connected, acquired ports: %s' % ports
1259
1260     print 'Creating traffic'
1261
1262     res = hltapi.traffic_config(mode = 'create', bidirectional = True,
1263                                 port_handle = ports[0], port_handle2 = ports[1],
1264                                 frame_size = args.frame_size,
1265                                 mac_src = args.src_mac, mac_dst = args.dst_mac,
1266                                 mac_src2 = args.dst_mac, mac_dst2 = args.src_mac,
1267                                 l3_protocol = 'ipv4',
1268                                 ip_src_addr = '10.0.0.1', ip_src_mode = 'increment', ip_src_count = 254,
1269                                 ip_dst_addr = '8.0.0.1', ip_dst_mode = 'increment', ip_dst_count = 254,
1270                                 l4_protocol = 'udp',
1271                                 udp_dst_port = 12, udp_src_port = 1025,
1272                                 stream_id = 1, # temporary workaround, add_stream does not return stream_id
1273                                 rate_pps = args.rate_pps,
1274                                 )
1275     check_res(res)
1276
1277     print 'Starting traffic'
1278     res = hltapi.traffic_control(action = 'run', port_handle = ports[:2])
1279     check_res(res)
1280     wait_with_progress(args.duration)
1281
1282     print 'Stopping traffic'
1283     res = hltapi.traffic_control(action = 'stop', port_handle = ports[:2])
1284     check_res(res)
1285
1286     res = hltapi.traffic_stats(mode = 'aggregate', port_handle = ports[:2])
1287     check_res(res)
1288     print_brief_stats(res)
1289     
1290     res = hltapi.cleanup_session(port_handle = 'all')
1291     check_res(res)
1292
1293     print 'Done' 
1294 ----
1295 <1> Imports the native TRex API.
1296 <2> Imports the HLT API.
1297
1298                 
1299 ==== Tutorial: Simple IPv4/UDP packet - Simulator 
1300
1301 *Goal*:: Use the TRex Stateless simulator.
1302
1303 Demonstrates the most basic use case using TRex simulator.
1304
1305 The TRex package includes a simulator tool, `stl-sim`. The simulator operates as a Python script that calls an executable. The platform requirements for the simulator tool are the same as for TRex.
1306
1307 The TRex simulator can:
1308
1309 * Test your traffic profiles before running them on TRex. 
1310 * Generate an output pcap file.
1311 * Simulate a number of threads.
1312 * Convert from one type of profile to another.
1313 * Convert any profile to JSON (API). For information, see: link:trex_rpc_server_spec.html#_add_stream[TRex stream specification]
1314
1315 Example traffic profile: 
1316
1317 *File*:: link:{github_stl_path}/udp_1pkt_simple.py[stl/udp_1pkt_simple.py]
1318
1319 [source,python]
1320 ----
1321 from trex_stl_lib.api import *                                  
1322
1323 class STLS1(object):
1324
1325     def create_stream (self):
1326
1327         return STLStream( 
1328             packet = 
1329                     STLPktBuilder(
1330                         pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/
1331                                 UDP(dport=12,sport=1025)/(10*'x')                       <1>                
1332                     ),
1333              mode = STLTXCont())                                                        <2>
1334
1335
1336     def get_streams (self, direction = 0, **kwargs):
1337         # create 1 stream 
1338         return [ self.create_stream() ]
1339
1340
1341 # dynamic load - used for TRex console or simulator
1342 def register():                                                                         <3>        
1343     return STLS1()
1344 ----
1345 <1> Defines the packet - in this case, IP/UDP with 10 bytes of 'x'.
1346 <2> Mode is Continuous, with a rate of 1 PPS. (Default rate: 1 PPS)
1347 <3> Each traffic profile module requires a `register` function.
1348
1349 The following runs the traffic profile through the TRex simulator, limiting the number of packets to 10, and storing the output in a pcap file.
1350
1351 [source,bash]
1352 ----
1353 $ ./stl-sim -f stl/udp_1pkt_simple.py -o b.pcap -l 10 
1354   executing command: 'bp-sim-64-debug --pcap --sl --cores 1 --limit 5000 -f /tmp/tmpq94Tfx -o b.pcap'
1355
1356   General info:
1357   ------------
1358
1359   image type:               debug
1360   I/O output:               b.pcap
1361   packet limit:             10
1362   core recording:           merge all
1363  
1364   Configuration info:
1365   -------------------
1366
1367   ports:                    2
1368   cores:                    1
1369   
1370   Port Config:
1371   ------------
1372   
1373   stream count:             1
1374   max PPS    :              1.00  pps
1375   max BPS L1 :              672.00  bps
1376   max BPS L2 :              512.00  bps
1377   line util. :              0.00  %
1378
1379
1380   Starting simulation...
1381
1382
1383   Simulation summary:
1384   -------------------
1385
1386   simulated 10 packets
1387   written 10 packets to 'b.pcap'
1388 ----
1389
1390 Contents of the output pcap file produced by the simulator in the previous step:
1391
1392 image::images/stl_tut_1.png[title="TRex simulator output stored in pcap file",align="left",width={p_width}, link="images/stl_tut_1.png"]
1393
1394 Adding `--json` displays the details of the JSON command for adding a stream:
1395
1396 [source,bash]
1397 ----
1398 $./stl-sim -f stl/udp_1pkt_simple.py --json
1399 [
1400     {
1401         "id": 1,
1402         "jsonrpc": "2.0",
1403         "method": "add_stream",
1404         "params": {
1405             "handler": 0,
1406             "port_id": 0,
1407             "stream": {
1408                 "action_count": 0,
1409                 "enabled": true,
1410                 "flags": 0,
1411                 "isg": 0.0,
1412                 "mode": {
1413                     "rate": {
1414                         "type": "pps",
1415                         "value": 1.0
1416                     },
1417                     "type": "continuous"
1418                 },
1419                 "next_stream_id": -1,
1420                 "packet": {
1421                     "binary": "AAAAAQAAAAAAAgAACABFAAAmAA",
1422                     "meta": ""
1423                 },
1424                 "rx_stats": {
1425                     "enabled": false
1426                 },
1427                 "self_start": true,
1428                 "vm": {
1429                     "instructions": [],
1430                     "split_by_var": ""
1431                 }
1432             },
1433             "stream_id": 1
1434         }
1435     },
1436     {
1437         "id": 1,
1438         "jsonrpc": "2.0",
1439         "method": "start_traffic",
1440         "params": {
1441             "duration": -1,
1442             "force": true,
1443             "handler": 0,
1444             "mul": {
1445                 "op": "abs",
1446                 "type": "raw",
1447                 "value": 1.0
1448             },
1449             "port_id": 0
1450         }
1451     }
1452 ]
1453 ----
1454
1455 For more information about stream definition, see the link:trex_rpc_server_spec.html#_add_stream[RPC specification].
1456
1457 To convert the profile to YAML format:
1458 [source,bash]
1459 ----
1460 $./stl-sim -f stl/udp_1pkt_simple.py --yaml
1461 - stream:
1462     action_count: 0
1463     enabled: true
1464     flags: 0
1465     isg: 0.0
1466     mode:
1467       pps: 1.0
1468       type: continuous
1469     packet:
1470       binary: AAAAAQAAAAAAAgAACABFAAAmAAEAAEARO
1471       meta: ''
1472     rx_stats:
1473       enabled: false
1474     self_start: true
1475     vm:
1476       instructions: []
1477       split_by_var: ''
1478 ----
1479
1480 To display packet details, use the `--pkt` option (using Scapy).
1481
1482 [source,bash]
1483 ----
1484 $./stl-sim -f stl/udp_1pkt_simple.py --pkt
1485  =======================
1486  Stream 0
1487  =======================
1488 ###[ Ethernet ]###
1489   dst       = 00:00:00:01:00:00
1490   src       = 00:00:00:02:00:00
1491   type      = IPv4
1492 ###[ IP ]###
1493      version   = 4L
1494      ihl       = 5L
1495      tos       = 0x0
1496      len       = 38
1497      id        = 1
1498      flags     = 
1499      frag      = 0L
1500      ttl       = 64
1501      proto     = udp
1502      chksum    = 0x3ac5
1503      src       = 16.0.0.1
1504      dst       = 48.0.0.1
1505      \options   \
1506 ###[ UDP ]###
1507         sport     = blackjack
1508         dport     = 12
1509         len       = 18
1510         chksum    = 0x6161
1511 ###[ Raw ]###
1512            load      = 'xxxxxxxxxx'
1513 0000   00 00 00 01 00 00 00 00  00 02 00 00 08 00 45 00   ..............E.
1514 0010   00 26 00 01 00 00 40 11  3A C5 10 00 00 01 30 00   .&....@.:.....0.
1515 0020   00 01 04 01 00 0C 00 12  61 61 78 78 78 78 78 78   ........aaxxxxxx
1516 0030   78 78 78 78                                        xxxx
1517 ----
1518
1519 To convert any profile type to native again, use the `--native` option:
1520
1521 .Input YAML format
1522 [source,python]
1523 ----
1524 $more stl/yaml/imix_1pkt.yaml
1525 - name: udp_64B
1526   stream:
1527     self_start: True
1528     packet:
1529       pcap: udp_64B_no_crc.pcap  # pcap should not include CRC
1530     mode:
1531       type: continuous
1532       pps: 100
1533 ----
1534
1535 To convert to native:
1536
1537 [source,bash]
1538 ----
1539 $./stl-sim -f stl/yaml/imix_1pkt.yaml --native
1540 ----
1541
1542
1543 .Output Native
1544 [source,python]
1545 ----
1546 # !!! Auto-generated code !!!
1547 from trex_stl_lib.api import *
1548
1549 class STLS1(object):
1550     def get_streams(self):
1551         streams = []
1552         
1553         packet = (Ether(src='00:de:01:0a:01:00', dst='00:50:56:80:0d:28', type=2048) / 
1554                   IP(src='101.0.0.1', proto=17, dst='102.0.0.1', chksum=28605, len=46, flags=2L, ihl=5L, id=0) / 
1555                   UDP(dport=2001, sport=2001, len=26, chksum=1176) / 
1556                   Raw(load='\xde\xad\xbe\xef\x00\x01\x06\x07\x08\x09\x0a\x0b\x00\x9b\xe7\xdb\x82M'))
1557         vm = STLScVmRaw([], split_by_field = '')
1558         stream = STLStream(packet = CScapyTRexPktBuilder(pkt = packet, vm = vm),
1559                            name = 'udp_64B',
1560                            mac_src_override_by_pkt = 0,
1561                            mac_dst_override_mode = 0,
1562                            mode = STLTXCont(pps = 100))
1563         streams.append(stream)
1564
1565         return streams
1566
1567 def register():
1568     return STLS1()
1569 ----
1570
1571 *Discussion*::
1572
1573 The following are the main traffic profile formats. Native is the preferred format. There is a separation between how the traffic is defined and how to control/activate it. The API/Console/GUI can load a traffic profile and start/stop/get a statistic. Due to this separation it is possible to share traffic profiles.
1574
1575 .Traffic profile formats
1576 [cols="1^,1^,10<", options="header",width="80%"]
1577 |=================
1578 | Profile Type       | Format | Description  
1579 | Native             | Python | Most flexibile. Any format can be converted to native using the `stl-sim` command with the `--native` option.
1580 | HLT                | Python | Uses HLT arguments.
1581 | YAML               | YAML   | The common denominator traffic profile. Information is shared between console, GUI, and simulator in YAML format. This format is difficult to use for defining packets; primarily for machine use. YAML can be converted to native using the `stl-sim` command with the `--native` option. 
1582 |=================
1583
1584
1585 === Traffic profile Tutorials
1586
1587 ==== Tutorial: Simple Interleaving streams
1588
1589 *Goal*:: Demonstrate interleaving of multiple streams.
1590
1591 The following example demonstrates 3 streams with different rates (10, 20, 40 PPS) and different start times, based on an inter-stream gap (ISG) of 0, 25 msec, or 50 msec.
1592
1593 *File*:: link:{github_stl_path}/simple_3pkt.py[stl/simple_3pkt.py]
1594
1595 // inserted this comment to fix rendering problem - otherwise the next several lines are not rendered
1596 // there's still a problem with the rendering. the image is not displayed.
1597
1598
1599 .Interleaving multiple streams
1600 [source,python]
1601 ----
1602     def create_stream (self):
1603
1604         # create a base packet and pad it to size
1605         size = self.fsize - 4 # no FCS
1606         base_pkt =  Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)       <1>
1607         base_pkt1 =  Ether()/IP(src="16.0.0.2",dst="48.0.0.1")/UDP(dport=12,sport=1025)
1608         base_pkt2 =  Ether()/IP(src="16.0.0.3",dst="48.0.0.1")/UDP(dport=12,sport=1025)
1609         pad = max(0, size - len(base_pkt)) * 'x'
1610
1611
1612         return STLProfile( [ STLStream( isg = 0.0, 
1613                                         packet = STLPktBuilder(pkt = base_pkt/pad),
1614                                         mode = STLTXCont( pps = 10),                         <2>
1615                                         ), 
1616
1617                              STLStream( isg = 25000.0, #defined in usec, 25 msec
1618                                         packet  = STLPktBuilder(pkt = base_pkt1/pad),
1619                                         mode    = STLTXCont( pps = 20),                      <3>
1620                                         ),
1621
1622                              STLStream(  isg = 50000.0,#defined in usec, 50 msec
1623                                          packet = STLPktBuilder(pkt = base_pkt2/pad),
1624                                          mode    = STLTXCont( pps = 40)                      <4>
1625                                          
1626                                         )
1627                             ]).get_streams()
1628 ----
1629 <1> Defines template packets using Scapy.
1630 <2> Defines streams with rate of 10 PPS.
1631 <3> Defines streams with rate of 20 PPS.
1632 <4> Defines streams with rate of 40 PPS.
1633
1634 *Output*::
1635
1636 The folowing figure presents the output.
1637
1638 image::images/stl_interleaving_01.png[title="Interleaving of streams",align="left",width={p_width}, link="images/stl_interleaving_01.png"]
1639
1640 *Discussion*:: 
1641 * Stream #1
1642 ** Schedules a packet each 100 msec 
1643 * Stream #2 
1644 ** Schedules a packet each 50 msec
1645 ** Starts 25 msec after stream #1
1646 * Stream #3 
1647 ** Schedules a packet each 25 msec
1648 ** Starts 50 msec after stream #1
1649
1650 You can run the traffic profile in the TRex simulator and view the details in the pcap file containing the simulation output.
1651
1652 [source,bash]
1653 ----
1654 $./stl-sim -f stl/simple_3pkt.py -o b.pcap -l 200
1655 ----
1656
1657 To run the traffic profile from console in TRex, use the following command.
1658
1659 [source,bash]
1660 ----
1661 trex>start -f stl/simple_3pkt.py -m 10mbps -a 
1662 ----
1663
1664 ==== Tutorial:  Multi burst streams - action next stream   
1665
1666 *Goal*:: Create a profile with a stream that trigger another stream 
1667
1668 The following example demonstrates: 
1669
1670 1. More than one stream 
1671 2. Burst of 10 packets
1672 3. One stream activating another stream (see `self_start=False` in the traffic profile)
1673
1674 *File*:: link:{github_stl_path}/burst_3pkt_60pkt.py[stl/burst_3pkt_60pkt.py]
1675
1676
1677 [source,python]
1678 ----
1679     def create_stream (self):
1680
1681         # create a base packet and pad it to size
1682         size = self.fsize - 4 # no FCS
1683         base_pkt =  Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)
1684         base_pkt1 =  Ether()/IP(src="16.0.0.2",dst="48.0.0.1")/UDP(dport=12,sport=1025)
1685         base_pkt2 =  Ether()/IP(src="16.0.0.3",dst="48.0.0.1")/UDP(dport=12,sport=1025)
1686         pad = max(0, size - len(base_pkt)) * 'x'
1687
1688
1689         return STLProfile( [ STLStream( isg = 10.0, # star in delay 
1690                                         name    ='S0',
1691                                         packet = STLPktBuilder(pkt = base_pkt/pad),
1692                                         mode = STLTXSingleBurst( pps = 10, total_pkts = 10),  <1>
1693                                         next = 'S1'), # point to next stream 
1694
1695                              STLStream( self_start = False, # stream is  disabled enable trow S0  <2>
1696                                         name    ='S1',
1697                                         packet  = STLPktBuilder(pkt = base_pkt1/pad),
1698                                         mode    = STLTXSingleBurst( pps = 10, total_pkts = 20),
1699                                         next    = 'S2' ),                                         
1700
1701                              STLStream(  self_start = False, # stream is  disabled enable trow S0 <3>
1702                                          name   ='S2',
1703                                          packet = STLPktBuilder(pkt = base_pkt2/pad),
1704                                          mode = STLTXSingleBurst( pps = 10, total_pkts = 30 )
1705                                         )
1706                             ]).get_streams()
1707
1708 ----
1709 <1> Stream S0 is configured to `self_start=True`, starts after 10 sec. 
1710 <2> S1 is configured to `self_start=False`, activated by stream S0.
1711 <3> S2 is activated by S1.
1712
1713 To run the simulation, use this command.
1714
1715 [source,bash]
1716 ----
1717 $ ./stl-sim -f stl/stl/burst_3pkt_60pkt.py -o b.pcap 
1718 ----
1719
1720 The generated pcap file has 60 packets. The first 10 packets have src_ip=16.0.0.1. The next 20 packets has src_ip=16.0.0.2. The next 30 packets has src_ip=16.0.0.3.
1721
1722 This run the profile from console use this command.
1723
1724 [source,bash]
1725 ----
1726 TRex>start -f stl/stl/burst_3pkt_60pkt.py --port 0
1727 ----
1728
1729 ==== Tutorial: Multi-burst mode
1730
1731 *Goal* : Use Multi-burst transmit mode  
1732
1733 *File*:: link:{github_stl_path}/multi_burst_2st_1000pkt.py[stl/multi_burst_2st_1000pkt.py]
1734
1735 [source,python]
1736 ----
1737
1738     def create_stream (self):
1739
1740         # create a base packet and pad it to size
1741         size = self.fsize - 4 # no FCS
1742         base_pkt =  Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)
1743         base_pkt1 =  Ether()/IP(src="16.0.0.2",dst="48.0.0.1")/UDP(dport=12,sport=1025)
1744         pad = max(0, size - len(base_pkt)) * 'x'
1745
1746
1747         return STLProfile( [ STLStream( isg = 10.0, # start in delay                                  <1>
1748                                         name    ='S0',
1749                                         packet = STLPktBuilder(pkt = base_pkt/pad),
1750                                         mode = STLTXSingleBurst( pps = 10, total_pkts = 10),
1751                                         next = 'S1'), # point to next stream 
1752
1753                              STLStream( self_start = False, # stream is disabled. Enabled by S0       <2>
1754                                         name    ='S1',
1755                                         packet  = STLPktBuilder(pkt = base_pkt1/pad),
1756                                         mode    = STLTXMultiBurst( pps = 1000,
1757                                                                    pkts_per_burst = 4,
1758                                                                    ibg = 1000000.0,                         
1759                                                                    count = 5)
1760                                         )
1761
1762                             ]).get_streams()
1763
1764 ----
1765 <1> Stream S0 waits 10 usec (inter-stream gap, ISG) and then sends a burst of 10 packets at 10 PPS.
1766 <2> Multi-burst of 5 bursts of 4 packets with an inter-burst gap of 1 second.
1767  
1768
1769 The following illustration does not fully match the Python example cited above. It has been simplified, such as using a 0.5 second ISG, for illustration purposes.
1770
1771 image::images/stl_multiple_streams_01.png[title="Example of multiple streams",align="left",width={p_width_lge}, link="images/stl_multiple_streams_01.png"]
1772
1773
1774
1775 ==== Tutorial: Loops of streams
1776
1777 *Goal* : Demonstrate a limited loop of streams
1778
1779 *File*:: link:{github_stl_path}/burst_3st_loop_x_times.py[stl/burst_3st_loop_x_times.py]
1780
1781 [source,python]
1782 ----
1783     def create_stream (self):
1784
1785         # create a base packet and pad it to size
1786         size = self.fsize - 4 # no FCS
1787         base_pkt =  Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)
1788         base_pkt1 =  Ether()/IP(src="16.0.0.2",dst="48.0.0.1")/UDP(dport=12,sport=1025)
1789         base_pkt2 =  Ether()/IP(src="16.0.0.3",dst="48.0.0.1")/UDP(dport=12,sport=1025)
1790         pad = max(0, size - len(base_pkt)) * 'x'
1791
1792
1793         return STLProfile( [ STLStream( isg = 10.0, # start in delay 
1794                                         name    ='S0',
1795                                         packet = STLPktBuilder(pkt = base_pkt/pad),
1796                                         mode = STLTXSingleBurst( pps = 10, total_pkts = 1),
1797                                         next = 'S1'), # point to next stream 
1798
1799                              STLStream( self_start = False, # stream is disabled. Enabled by S0
1800                                         name    ='S1',
1801                                         packet  = STLPktBuilder(pkt = base_pkt1/pad),
1802                                         mode    = STLTXSingleBurst( pps = 10, total_pkts = 2),
1803                                         next    = 'S2' ),
1804
1805                              STLStream(  self_start = False, # stream is disabled. Enabled by S1
1806                                          name   ='S2',
1807                                          packet = STLPktBuilder(pkt = base_pkt2/pad),
1808                                          mode = STLTXSingleBurst( pps = 10, total_pkts = 3 ),
1809                                          action_count = 2, # loop 2 times                       <1>
1810                                          next    = 'S0' # loop back to S0
1811                                         )
1812                             ]).get_streams()
1813
1814 ----
1815 <1> go back to S0 but limit it to 2 loops
1816
1817
1818 ==== Tutorial: IMIX with UDP packets, bi-directional 
1819
1820 *Goal* : Demonstrate how to create an IMIX traffic profile.
1821
1822 This profile defines 3 streams, with packets of different sizes. The rate is different for each stream/size. See the link:https://en.wikipedia.org/wiki/Internet_Mix[Wikipedia article on Internet Mix].
1823
1824 *File*:: link:{github_stl_path}/imix.py[stl/imix.py]
1825
1826 [source,python]
1827 ----
1828     def __init__ (self):
1829         # default IP range
1830         self.ip_range = {'src': {'start': "10.0.0.1", 'end': "10.0.0.254"},
1831                          'dst': {'start': "8.0.0.1",  'end': "8.0.0.254"}}
1832
1833         # default IMIX properties
1834         self.imix_table = [ {'size': 60,   'pps': 28,  'isg':0 },
1835                             {'size': 590,  'pps': 16,  'isg':0.1 },
1836                             {'size': 1514, 'pps': 4,   'isg':0.2 } ]
1837
1838
1839     def create_stream (self, size, pps, isg, vm ):
1840         # create a base packet and pad it to size
1841         base_pkt = Ether()/IP()/UDP()
1842         pad = max(0, size - len(base_pkt)) * 'x'
1843
1844         pkt = STLPktBuilder(pkt = base_pkt/pad,
1845                             vm = vm)
1846
1847         return STLStream(isg = isg,
1848                          packet = pkt,
1849                          mode = STLTXCont(pps = pps))
1850
1851
1852     def get_streams (self, direction = 0, **kwargs):                            <1>
1853
1854         if direction == 0:                                                      <2>
1855             src = self.ip_range['src']
1856             dst = self.ip_range['dst']
1857         else:
1858             src = self.ip_range['dst']
1859             dst = self.ip_range['src']
1860
1861         # construct the base packet for the profile
1862
1863         vm =[                                                                   <3>
1864             # src
1865             STLVmFlowVar(name="src",
1866                          min_value=src['start'],
1867                          max_value=src['end'],
1868                          size=4,op="inc"),
1869             STLVmWrFlowVar(fv_name="src",pkt_offset= "IP.src"),
1870
1871             # dst
1872             STLVmFlowVar(name="dst",
1873                          min_value=dst['start'],
1874                          max_value=dst['end'],
1875                          size=4,
1876                          op="inc"),
1877             STLVmWrFlowVar(fv_name="dst",pkt_offset= "IP.dst"),
1878
1879             # checksum
1880             STLVmFixIpv4(offset = "IP")
1881
1882             ]
1883
1884         # create imix streams
1885         return [self.create_stream(x['size'], x['pps'],x['isg'] , vm) for x in self.imix_table]
1886 ----
1887 <1> Constructs a diffrent stream for each direction (replaces src and dest).
1888 <2> Even port id has direction==0 and odd has direction==1.
1889 // direction==1 not shown explicitly in the code?
1890 <3> Field Engine program to change fields within the packets.
1891 // we can link "Field Engine" to an appropriate location for for more info.
1892
1893 ==== Tutorial: Field Engine, Syn attack  
1894
1895 The following example demonstrates changing packet fields. The Field Engine (FE) has a limited number of instructions/operation, which support most use cases. 
1896
1897 *The FE can*::
1898 * Allocate stream variables in a stream context
1899 * Write a stream variable to a packet offset
1900 * Change packet size
1901 * and more...
1902 * There is a plan to add LuaJIT to be more flexible at the cost of performance.
1903
1904 *Examples:*::
1905 * Change ipv4.tos value (1 to 10)
1906 * Change packet size to a random value in the range 64 to 9K
1907 * Create a range of flows (change src_ip, dest_ip, src_port, dest_port) 
1908 * Update the IPv4 checksum 
1909
1910 For more information, see link:trex_rpc_server_spec.html#_object_type_em_vm_em_a_id_vm_obj_a[here]
1911 // add link to Python API: http://trex-tgn.cisco.com/trex/doc/cp_stl_docs/api/field_engine.html
1912
1913 The following example demonstrates creating a SYN attack from many src addresses to one server.
1914
1915 *File*:: link:{github_stl_path}/syn_attack.py[stl/syn_attack.py]
1916
1917 [source,python]
1918 ----
1919     def create_stream (self):
1920
1921         # TCP SYN
1922         base_pkt  = Ether()/IP(dst="48.0.0.1")/TCP(dport=80,flags="S")      <1>
1923
1924
1925         # vm
1926         vm = STLScVmRaw( [ STLVmFlowVar(name="ip_src", 
1927                                               min_value="16.0.0.0", 
1928                                               max_value="18.0.0.254", 
1929                                               size=4, op="random"),         <2>
1930
1931                            STLVmFlowVar(name="src_port", 
1932                                               min_value=1025, 
1933                                               max_value=65000, 
1934                                               size=2, op="random"),         <3>
1935
1936                            STLVmWrFlowVar(fv_name="ip_src", pkt_offset= "IP.src" ), <4>
1937
1938                            STLVmFixIpv4(offset = "IP"), # fix checksum              <5>
1939
1940                            STLVmWrFlowVar(fv_name="src_port",                       <6>
1941                                                 pkt_offset= "TCP.sport") # U 
1942
1943                           ]
1944                        )
1945
1946         pkt = STLPktBuilder(pkt = base_pkt,
1947                             vm = vm)
1948
1949         return STLStream(packet = pkt,
1950                          random_seed = 0x1234,# can be removed. will give the same random value any run
1951                          mode = STLTXCont())
1952 ----
1953 <1> Creates SYN packet using Scapy .
1954 <2> Defines a stream variable `name=ip_src`, size 4 bytes, for IPv4. 
1955 <3> Defines a stream variable `name=src_port`, size 2 bytes, for port. 
1956 <4> Writes `ip_src` stream var into `IP.src` packet offset. Scapy calculates the offset. Can specify `IP:1.src` for a second IP header in the packet.
1957 <5> Fixes IPv4 checksum. Provides the header name `IP`. Can specify `IP:1` for a second IP.
1958 <6> Writes `src_port` stream var into `TCP.sport` packet offset. TCP checksum is not updated here.
1959
1960 WARNING: Original Scapy cannot calculate offset for a header/field by name. This offset capability will not work for all cases. In some complex cases, Scapy may rebuild the header. In such cases, specify the offset as a number.
1961
1962 Output pcap file: 
1963
1964 .Output - pcap file 
1965 [format="csv",cols="1^,2<,2<", options="header",width="40%"]
1966 |=================
1967 pkt,Client IPv4,Client Port
1968  1  , 17.152.71.218  , 5814
1969  2  , 17.7.6.30      , 26810
1970  3  , 17.3.32.200    , 1810 
1971  4  , 17.135.236.168 , 55810 
1972  5  , 17.46.240.12   , 1078  
1973  6  , 16.133.91.247  , 2323
1974 |=================
1975
1976
1977 ==== Tutorial: Field Engine, Tuple Generator 
1978
1979 The following example creates multiple flows from the same packet template. The Tuple Generator instructions are used to create two stream variables for IP and port. See link:trex_rpc_server_spec.html#_object_type_em_vm_em_a_id_vm_obj_a[here]
1980 // clarify link
1981
1982 *File*:: link:{github_stl_path}/udp_1pkt_tuple_gen.py[stl/udp_1pkt_tuple_gen.py]
1983
1984 [source,python]
1985 ----
1986         base_pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)        
1987
1988         pad = max(0, size - len(base_pkt)) * 'x'
1989                              
1990         vm = STLScVmRaw( [   STLVmTupleGen ( ip_min="16.0.0.1",                              <1>
1991                                              ip_max="16.0.0.2", 
1992                                              port_min=1025, 
1993                                              port_max=65535,
1994                                              name="tuple"), # define tuple gen 
1995
1996                              STLVmWrFlowVar (fv_name="tuple.ip", pkt_offset= "IP.src" ),     <2>
1997                              STLVmFixIpv4(offset = "IP"),                                
1998                              STLVmWrFlowVar (fv_name="tuple.port", pkt_offset= "UDP.sport" ) <3>
1999                                   ]
2000                               )
2001
2002         pkt = STLPktBuilder(pkt = base_pkt/pad,
2003                             vm = vm)
2004 ----
2005 <1> Defines a struct with two dependent variables: tuple.ip, tuple.port
2006 <2> Writes the tuple.ip variable to `IPv4.src` field offset.
2007 <3> Writes the tuple.port variable to `UDP.sport` field offset. Set `UDP.checksum` to 0.
2008 // Hanoch: add how to set UDP.checksum to 0
2009
2010
2011 .Output - pcap file 
2012 [format="csv",cols="1^,2^,1^", options="header",width="40%"]
2013 |=================
2014 pkt,Client IPv4,Client Port
2015  1  , 16.0.0.1 , 1025
2016  2  , 16.0.0.2 , 1025
2017  3  , 16.0.0.1 , 1026
2018  4  , 16.0.0.2 , 1026
2019  5  , 16.0.0.1 , 1027
2020  6  , 16.0.0.2,  1027
2021 |=================
2022
2023 * Number of clients: 2: 16.0.0.1 and 16.0.0.2
2024 * Number of flows is limited to 129020: (2 * (65535-1025))
2025 * The stream variable size should match the size of the FlowVarWr instruction.
2026
2027 ==== Tutorial: Field Engine, write to a bit-field packet  
2028
2029 The following example writes a stream variable to a bit field packet variable. In this example, an MPLS label field is changed.
2030
2031 .MPLS header 
2032 [cols="32", halign="center",width="50%"] 
2033 |==== 
2034 20+<|Label 3+<|TC 1+<|S 8+<|TTL| 
2035 0|1|2|3|4|5|6|7|8|9|0|1|2|3|4|5|6|7|8|9|0|1|2|3|4|5|6|7|8|9|0|1|
2036 |==== 
2037
2038 *File*:: link:{github_stl_path}/udp_1pkt_mpls_vm.py[stl/udp_1pkt_mpls_vm.py]
2039
2040 [source,python]
2041 ----
2042
2043     def create_stream (self):
2044         # 2 MPLS label the internal with  s=1 (last one)
2045         pkt =  Ether()/
2046                MPLS(label=17,cos=1,s=0,ttl=255)/
2047                MPLS(label=0,cos=1,s=1,ttl=12)/
2048                IP(src="16.0.0.1",dst="48.0.0.1")/
2049                UDP(dport=12,sport=1025)/('x'*20)
2050
2051         vm = STLScVmRaw( [ STLVmFlowVar(name="mlabel",                                 <1>
2052                                         min_value=1, 
2053                                         max_value=2000, 
2054                                         size=2, op="inc"), # 2 bytes var               <2>
2055                            STLVmWrMaskFlowVar(fv_name="mlabel",                      
2056                                               pkt_offset= "MPLS:1.label",              <3>
2057                                               pkt_cast_size=4, 
2058                                               mask=0xFFFFF000,shift=12) # write to 20bit MSB
2059                           ]
2060                        )
2061
2062         # burst of 100 packets
2063         return STLStream(packet = STLPktBuilder(pkt = pkt ,vm = vm),
2064                          mode = STLTXSingleBurst( pps = 1, total_pkts = 100) )
2065
2066 ----
2067 <1> Defines a variable size of 2 bytes.
2068 <2> Writes the stream variable label with a shift of 12 bits, with a 20-bit MSB mask. Cast the stream variables of 2 bytes to 4 bytes.
2069 <3> Change the second MPLS header.
2070
2071
2072 ==== Tutorial: Field Engine, Random packet size 
2073
2074 The following example demonstrates varies the packet size randomly, as follows:
2075
2076 1. Defines the template packet with maximum size.
2077 2. Trims the packet to the size you want.
2078 3. Updates the packet fields according to the new size. 
2079
2080 *File*:: link:{github_stl_path}/udp_rand_len_9k.py[stl/udp_rand_len_9k.py]
2081
2082 [source,python]
2083 ----
2084
2085     def create_stream (self):
2086         # pkt 
2087         p_l2  = Ether()
2088         p_l3  = IP(src="16.0.0.1",dst="48.0.0.1")
2089         p_l4  = UDP(dport=12,sport=1025)
2090         pyld_size = max(0, self.max_pkt_size_l3 - len(p_l3/p_l4))
2091         base_pkt = p_l2/p_l3/p_l4/('\x55'*(pyld_size))
2092
2093         l3_len_fix =-(len(p_l2))
2094         l4_len_fix =-(len(p_l2/p_l3))
2095
2096
2097         # vm
2098         vm = STLScVmRaw( [ STLVmFlowVar(name="fv_rand",                            <1>
2099                                         min_value=64, 
2100                                         max_value=len(base_pkt), 
2101                                         size=2, 
2102                                         op="random"),
2103
2104                            STLVmTrimPktSize("fv_rand"), # total packet size        <2>
2105
2106                            STLVmWrFlowVar(fv_name="fv_rand",                       <3>
2107                                           pkt_offset= "IP.len", 
2108                                           add_val=l3_len_fix), # fix ip len 
2109
2110                            STLVmFixIpv4(offset = "IP"),                               
2111
2112                            STLVmWrFlowVar(fv_name="fv_rand",                       <4>
2113                                           pkt_offset= "UDP.len", 
2114                                           add_val=l4_len_fix) # fix udp len  
2115                           ]
2116                        )
2117 ----
2118 <1> Defines a random stream variable with the maximum size of the packet.
2119 <2> Trims the packet size to the `fv_rand` value.
2120 <3> Fixes ip.len to reflect the packet size.
2121 <4> Fixes udp.len to reflect the packet size.
2122
2123
2124 ==== Tutorial: Field Engine, Significantly improve performance 
2125
2126 anchor:trex_cache_mbuf[]
2127
2128 The following example demonstrates a way to significantly improve Field Engine performance in case it is needed. 
2129
2130 Field Engine has a cost of CPU instructions and CPU memory bandwidth. There is a way to significantly improve performance by caching the packets and run the Field Engine offline(before sending the packets). 
2131 The limitation is that you can have only a limited number of packets that can be cached (order or 10K depends how much memory you have).
2132 For example a program that change the src_ip to a random value can't be utilized this technique and still have random src_ip.  
2133 Usually this is done with small packets (64bytes) where performance is an issue. This method can improve long packets senario with a complex Field Engine program.
2134
2135 *File*:: link:{github_stl_path}/udp_1pkt_src_ip_split.py[stl/udp_1pkt_src_ip_split.py]
2136
2137 [source,python]
2138 ----
2139
2140     def create_stream (self):
2141         # create a base packet and pad it to size
2142         size = self.fsize - 4; # no FCS
2143
2144         base_pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)
2145
2146         pad = max(0, size - len(base_pkt)) * 'x'
2147                              
2148         vm = STLScVmRaw( [   STLVmFlowVar ( "ip_src",  
2149                                             min_value="10.0.0.1",
2150                                             max_value="10.0.0.255", 
2151                                             size=4, step=1,op="inc"),
2152                                             
2153                              STLVmWrFlowVar (fv_name="ip_src", 
2154                                              pkt_offset= "IP.src" ), 
2155                                              
2156                              STLVmFixIpv4(offset = "IP")                               
2157                          ],
2158                          split_by_field = "ip_src",  
2159                          cache_size =255 # the cache size             <1>
2160                         );
2161
2162         pkt = STLPktBuilder(pkt = base_pkt/pad,
2163                             vm = vm)
2164                             
2165         stream = STLStream(packet = pkt,
2166                          mode = STLTXCont())
2167         return stream
2168         
2169 ----
2170 <1> Cache 255 packets. The range is the same as `ip_src` stream variable 
2171
2172 This FE program will run *x2-5 faster* compared to native (without cache). 
2173 In this specific example the output will be *exactly* the same.
2174
2175 Again the limitations of this method are:
2176
2177 1. The total number of cache packets for all the streams all the ports in limited by the memory pool (range of ~10-40K)
2178 2. There could be cases that the cache options won't be exactly the same as the normal program, for example, in case of a program that step in prime numbers or with a random variable
2179
2180
2181 ==== Tutorial: New Scapy header  
2182
2183 The following example uses a header that is not supported by Scapy by default. The example demonstrates VXLAN support.
2184
2185 *File*:: link:{github_stl_path}/udp_1pkt_vxlan.py[stl/udp_1pkt_vxlan.py]
2186
2187 [source,python]
2188 ----
2189
2190 # Adding header that does not exists yet in Scapy
2191 # This was taken from pull request of Scapy 
2192
2193
2194
2195 # RFC 7348 - Virtual eXtensible Local Area Network (VXLAN):                                     <1>
2196 # A Framework for Overlaying Virtualized Layer 2 Networks over Layer 3 Networks
2197 # http://tools.ietf.org/html/rfc7348
2198 _VXLAN_FLAGS = ['R' for i in range(0, 24)] + ['R', 'R', 'R', 'I', 'R', 'R', 'R', 'R', 'R'] 
2199
2200 class VXLAN(Packet):
2201     name = "VXLAN"
2202     fields_desc = [FlagsField("flags", 0x08000000, 32, _VXLAN_FLAGS),
2203                    ThreeBytesField("vni", 0),
2204                    XByteField("reserved", 0x00)]
2205
2206     def mysummary(self):
2207         return self.sprintf("VXLAN (vni=%VXLAN.vni%)")
2208
2209 bind_layers(UDP, VXLAN, dport=4789)
2210 bind_layers(VXLAN, Ether)
2211
2212
2213 class STLS1(object):
2214
2215     def __init__ (self):
2216         pass
2217
2218     def create_stream (self):
2219         pkt =  Ether()/IP()/UDP(sport=1337,dport=4789)/VXLAN(vni=42)/Ether()/IP()/('x'*20)    <2>
2220         #pkt.show2()
2221         #hexdump(pkt)
2222
2223         # burst of 17 packets
2224         return STLStream(packet = STLPktBuilder(pkt = pkt ,vm = []),
2225                          mode = STLTXSingleBurst( pps = 1, total_pkts = 17) )
2226
2227
2228 ----
2229 <1> Downloads and adds a Scapy header from the specified location. Alternatively, write a Scapy header.
2230 <2> Apply the header. 
2231
2232 For more information how to define headers see link:http://www.secdev.org/projects/scapy/doc/build_dissect.html[Adding new protocols] in the Scapy documentation.
2233
2234
2235 ==== Tutorial: Field Engine, Multiple Clients 
2236
2237 The following example generates traffic from many clients with different IP/MAC addresses to one server.
2238
2239 // Please leave this comment - helping rendition of image below.
2240
2241 image::images/stl_multiple_clients_01b.png[title="Multiple clients to single server",align="left",width="80%", link="images/stl_multiple_clients_01b.png"]
2242
2243 // OBSOLETEimage::images/stl_tut_12.png[title="client->server",align="left",width={p_width}, link="images/stl_tut_12.png"]
2244
2245 1. Send a gratuitous ARP from B->D with server IP/MAC (58.55.1.1).
2246 2. DUT learns the ARP of server IP/MAC (58.55.1.1).
2247 3. Send traffic from A->C with many client IP/MAC addresses.
2248
2249 Example:
2250
2251 Base source IPv4 : 55.55.1.1
2252 Destination IPv4:  58.55.1.1
2253
2254 Increment src ipt portion starting at 55.55.1.1 for 'n' number of clients (55.55.1.1, 55.55.1.2)
2255 Src MAC: start with 0000.dddd.0001, increment mac in steps of 1
2256 Dst MAC: Fixed  - 58.55.1.1 
2257
2258 The following sends a link:https://wiki.wireshark.org/Gratuitous_ARP[gratuitous ARP] from the TRex server port for this server (58.0.0.1).
2259
2260 [source,python]
2261 ----
2262     def create_stream (self):
2263         # create a base packet and pad it to size
2264         base_pkt =  Ether(src="00:00:dd:dd:01:01",
2265                           dst="ff:ff:ff:ff:ff:ff")/
2266                     ARP(psrc="58.55.1.1",
2267                         hwsrc="00:00:dd:dd:01:01", 
2268                         hwdst="00:00:dd:dd:01:01", 
2269                         pdst="58.55.1.1")
2270 ----
2271
2272 Then traffic can be sent from client side: A->C 
2273
2274 *File*:: link:{github_stl_path}/udp_1pkt_range_clients_split.py[stl/udp_1pkt_range_clients_split.py]
2275
2276 [source,python]
2277 ----
2278 class STLS1(object):
2279
2280     def __init__ (self):
2281         self.num_clients  =30000 # max is 16bit
2282         self.fsize        =64
2283
2284     def create_stream (self):
2285
2286         # create a base packet and pad it to size
2287         size = self.fsize - 4 # no FCS
2288         base_pkt =  Ether(src="00:00:dd:dd:00:01")/
2289                           IP(src="55.55.1.1",dst="58.55.1.1")/UDP(dport=12,sport=1025)
2290         pad = max(0, size - len(base_pkt)) * 'x'
2291
2292         vm = STLScVmRaw( [ STLVmFlowVar(name="mac_src", 
2293                                         min_value=1, 
2294                                         max_value=self.num_clients, 
2295                                         size=2, op="inc"), # 1 byte varible, range 1-10
2296                                         
2297                            STLVmWrFlowVar(fv_name="mac_src", pkt_offset= 10),        <1>                 
2298                            STLVmWrFlowVar(fv_name="mac_src" ,
2299                                           pkt_offset="IP.src",
2300                                           offset_fixup=2),                           <2>
2301                            STLVmFixIpv4(offset = "IP")
2302                           ]
2303                          ,split_by_field = "mac_src"  # split 
2304                        )
2305
2306         return STLStream(packet = STLPktBuilder(pkt = base_pkt/pad,vm = vm),
2307                          mode = STLTXCont( pps=10 ))
2308 ----
2309 <1> Writes the stream variable `mac_src` with an offset of 10 (last 2 bytes of `src_mac` field). The offset is specified explicitly as 10 bytes from the beginning of the packet.
2310 <2> Writes the stream variable `mac_src` with an offset determined by the offset of `IP.src` plus the `offset_fixup` of 2. 
2311
2312
2313 ==== Tutorial: Field Engine, many clients with ARP
2314
2315 In the following example, there are two Switchs SW1 and SW2. 
2316 TRex port 0 is connected to SW1 and TRex port 1 is connected to SW2.
2317 There are 253 hosts connected to SW1 and SW2 with two network ports. 
2318
2319 .Client side the network of the hosts
2320 [cols="3<,3<", options="header",width="50%"]
2321 |=================
2322 | Name      |  Description   
2323 | TRex port 0 MAC       | 00:00:01:00:00:01     
2324 | TRex port 0 IPv4      | 16.0.0.1
2325 | IPv4 host client side range     | 16.0.0.2-16.0.0.254
2326 | MAC host client side range     | 00:00:01:00:00:02-00:00:01:00:00:FE 
2327 |=================
2328
2329
2330 .Server side the network of the hosts
2331 [cols="3<,3<", options="header",width="50%"]
2332 |=================
2333 | Name      |  Description   
2334 | TRex port 1 MAC       | 00:00:02:00:00:01     
2335 | TRex port 1 IPv4      | 48.0.0.1
2336 | IPv4 host server side range     | 48.0.0.2-48.0.0.254
2337 | MAC host server side range     | 00:00:02:00:00:02-00:00:02:00:00:FE 
2338 |=================
2339
2340 image::images/stl_arp.png[title="arp/nd",align="left",width={p_width}, link="images/stl_arp.png"]
2341
2342 In the following example, there are two Switchs SW1 and SW2. 
2343 TRex port 0 is connected to SW1 and TRex port 1 is connected to SW2
2344 In this example, because there are many hosts connected to the same network using SW1 and not as a next hope, we would like to teach SW1 the MAC addresses of the hosts and not to send the traffic directly to the hosts MAC (as it is unknown)
2345 For that we would send an ARP to all the hosts (16.0.0.2-16.0.0.254) from TRex port 0 and gratuitous ARP from server side (48.0.0.1) TRex port 1 as the first stage of the test
2346
2347 So the step would be like that:
2348
2349 1. Send a gratuitous ARP from TRex port 1 with server IP/MAC (48.0.0.1) after this stage SW2 will know that 48.0.0.1 is located after this port of SW2.
2350 2. Send ARP request for all hosts from port 0 with a range of 16.0.0.2-16.0.0.254 after this stage all switch ports will learn the PORT/MAC locations. Without this stage the first packets from TRex port 0 will be flooded to all Switch ports. 
2351 3. send traffic from TRex0->clients, port 1->servers 
2352
2353
2354 .ARP traffic profile 
2355 [source,python]
2356 ----
2357
2358  base_pkt =  Ether(dst="ff:ff:ff:ff:ff:ff")/
2359             ARP(psrc="16.0.0.1",hwsrc="00:00:01:00:00:01", pdst="16.0.0.2")                      <1>
2360
2361  vm = STLScVmRaw( [ STLVmFlowVar(name="mac_src", min_value=2, max_value=254, size=2, op="inc"),  <2>
2362                     STLVmWrFlowVar(fv_name="mac_src" ,pkt_offset="ARP.pdst",offset_fixup=2),                
2363                   ]
2364                  ,split_by_field = "mac_src"  # split 
2365                 )
2366
2367
2368 ----
2369 <1> ARP packet with TRex port 0 MAC and IP and pdst as variable.
2370 <2> Write it to `ARP.pdst`.
2371
2372
2373 .Gratuitous ARP traffic profile 
2374 [source,python]
2375 ----
2376
2377         base_pkt =  Ether(src="00:00:02:00:00:01",dst="ff:ff:ff:ff:ff:ff")/
2378                     ARP(psrc="48.0.0.1",hwsrc="00:00:02:00:00:01", 
2379                         hwdst="00:00:02:00:00:01", pdst="48.0.0.1") <1>
2380
2381 ----
2382 <1> G ARP packet with TRex port 1 MAC and IP no need a VM.
2383
2384 [NOTE] 
2385 =====================================================================
2386 This principal can be done for IPv6 too. ARP could be replaced with Neighbor Solicitation IPv6 packet.
2387 =====================================================================
2388  
2389 ==== Tutorial: Field Engine, split to core 
2390
2391 Post v2.08 version split to core directive was deprecated and was kept for backward compatibility.
2392 The new implementation is always to split as if the profile was sent from one core. 
2393 The user of TRex is oblivious to the number of cores. 
2394
2395
2396 [source,python]
2397 ----
2398     def create_stream (self):
2399
2400         # TCP SYN
2401         base_pkt  = Ether()/IP(dst="48.0.0.1")/TCP(dport=80,flags="S")     
2402
2403
2404         # vm
2405         vm = STLScVmRaw( [ STLVmFlowVar(name="ip_src", 
2406                                               min_value="16.0.0.0", 
2407                                               max_value="16.0.0.254", 
2408                                               size=4, op="inc"),                     
2409
2410
2411                            STLVmWrFlowVar(fv_name="ip_src", pkt_offset= "IP.src" ),  
2412
2413                            STLVmFixIpv4(offset = "IP"), # fix checksum              
2414                           ]
2415                          ,split_by_field = "ip_src"                                 <1>  
2416                        )
2417
2418 ----
2419 <1> Deprecated split by field. not used any more (post v2.08)
2420
2421
2422 *Some rules regarding split stream variables and burst/multi-burst*::
2423
2424 * When using burst/multi-burst, the number of packets are split to the defualt number of threads specified in the YAML cofiguraiton file, without any need to explicitly split the threads.
2425 * When the number of packets in a burst is smaller than the number of threads, one thread handles the burst. 
2426 * In the case of a stream with a burst of *1* packet, only the first DP thread handles the stream.
2427
2428 ==== Tutorial: Field Engine, Null stream 
2429
2430 The following example creates a stream with no packets. The example uses the inter-stream gap (ISG) of the Null stream, and then starts a new stream. Essentially, this uses one property of the stream (ISG) without actually including packets in the stream.
2431
2432 This method can create loops like the following:
2433
2434 image::images/stl_null_stream_02.png[title="Null stream",align="left",width={p_width_1}, link="images/stl_null_stream_02.png"]
2435  
2436 1. S1 - Sends a burst of packets, then proceed to stream NULL.
2437 2. NULL - Waits the inter-stream gap (ISG) time, then proceed to S1. 
2438
2439 Null stream configuration:
2440
2441 1. Mode: Burst 
2442 2. Number of packets: 0
2443
2444
2445 ==== Tutorial: Field Engine, Stream Barrier (Split)
2446
2447 *(Future Feature - not yet implemented)*
2448
2449 In some situations, it is necessary to split streams into threads in such a way that specific streams will continue only after all the threads have passed the same path. In the figure below, a barrier ensures that stream S3 starts only after all threads of S2 are complete. 
2450
2451 image::images/stl_barrier_03.png[title="Stream Barrier",align="left",width={p_width}, link="images/stl_barrier_03.png"]
2452
2453 ==== Tutorial: PCAP file to one stream 
2454
2455 *Goal*:: Load a stream template packet from a pcap file instead of Scapy.
2456
2457 Assumption: The pcap file contains only one packet. If the pcap file contains more than one packet, this procedure loads only the first packet.
2458
2459 *File*:: link:{github_stl_path}/udp_1pkt_pcap.py[stl/udp_1pkt_pcap.py]
2460
2461 [source,python]
2462 ----
2463
2464     def get_streams (self, direction = 0, **kwargs):
2465         return [STLStream(packet = 
2466                           STLPktBuilder(pkt ="stl/yaml/udp_64B_no_crc.pcap"), # path relative to pwd   <1>
2467                            mode = STLTXCont(pps=10)) ] 
2468
2469 ----
2470 <1> Takes the packet from the pcap file, relative to the directory in which you are running the script.
2471
2472
2473 *File*:: link:{github_stl_path}/udp_1pkt_pcap_relative_path.py[udp_1pkt_pcap_relative_path.py]
2474
2475
2476 [source,python]
2477 ----
2478
2479     def get_streams (self, direction = 0, **kwargs):
2480         return [STLStream(packet = STLPktBuilder(pkt ="yaml/udp_64B_no_crc.pcap",
2481                                                  path_relative_to_profile = True), <1>
2482                          mode = STLTXCont(pps=10)) ] 
2483
2484 ----
2485 <1> Takes the packet from the pcap file, relative to the directory of the *profile* file location.
2486
2487
2488
2489 ==== Tutorial: Teredo tunnel (IPv6 over IPv4)
2490
2491 The following example demonstrates creating an IPv6 packet within an IPv4 packet, and creating a range of IP addresses.
2492
2493 *File*:: link:{github_stl_path}/udp_1pkt_ipv6_in_ipv4.py[stl/udp_1pkt_ipv6_in_ipv4.py]
2494
2495 [source,python]
2496 ----
2497     def create_stream (self):
2498         # Teredo Ipv6 over Ipv4 
2499         pkt =  Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/
2500               UDP(dport=3797,sport=3544)/
2501               IPv6(dst="2001:0:4137:9350:8000:f12a:b9c8:2815",
2502                    src="2001:4860:0:2001::68")/
2503               UDP(dport=12,sport=1025)/ICMPv6Unknown()
2504
2505         vm = STLScVmRaw( [ 
2506                             # tuple gen for inner Ipv6 
2507                             STLVmTupleGen ( ip_min="16.0.0.1", ip_max="16.0.0.2", 
2508                                             port_min=1025, port_max=65535,
2509                                             name="tuple"),                      <1>
2510
2511                              STLVmWrFlowVar (fv_name="tuple.ip", 
2512                                              pkt_offset= "IPv6.src",
2513                                              offset_fixup=12 ),                 <2>
2514                              STLVmWrFlowVar (fv_name="tuple.port", 
2515                                              pkt_offset= "UDP:1.sport" )        <3>
2516                           ]
2517                        )
2518 ----
2519 <1> Defines a stream struct called tuple with the following variables: `tuple.ip`, `tuple.port`
2520 <2> Writes a stream `tuple.ip` variable with an offset determined by the `IPv6.src` offset plus the `offset_fixup` of 12 bytes (only 4 LSB).
2521 <3> Writes a stream `tuple.port` variable into the second UDP header. 
2522
2523
2524 ==== Tutorial: Mask instruction 
2525
2526 STLVmWrMaskFlowVar is single-instruction-multiple-data Field Engine instruction. The pseudocode is as follows:
2527
2528 .Pseudocode 
2529 [source,bash]
2530 ----
2531         uint32_t val=(cast_to_size)rd_from_variable("name") # read flow-var
2532         val+=m_add_value                                    # add value
2533
2534         if (m_shift>0) {                                    # shift 
2535             val=val<<m_shift
2536         }else{
2537             if (m_shift<0) {
2538                 val=val>>(-m_shift)
2539             }
2540         }
2541
2542         pkt_val=rd_from_pkt(pkt_offset)                     # RMW
2543         pkt_val = (pkt_val & ~m_mask) | (val & m_mask)
2544         wr_to_pkt(pkt_offset,pkt_val)
2545 ----
2546
2547
2548 *Example 1*::
2549
2550 In this example, STLVmWrMaskFlowVar casts a stream variable with 2 bytes to be 1 byte.
2551
2552 [source,python]
2553 ----
2554         vm = STLScVmRaw( [ STLVmFlowVar(name="mac_src", 
2555                                         min_value=1, 
2556                                         max_value=30, 
2557                                         size=2, op="dec",step=1), 
2558                            STLVmWrMaskFlowVar(fv_name="mac_src", 
2559                                               pkt_offset= 11,
2560                                               pkt_cast_size=1, 
2561                                               mask=0xff) # mask command ->write it as one byte
2562                           ]
2563                        )
2564
2565 ----
2566
2567
2568 *Example 2*::
2569
2570 In this example, STLVmWrMaskFlowVar shifts a variable by 8, which effectively multiplies by 256.
2571
2572 [source,python]
2573 ----
2574
2575         vm = STLScVmRaw( [ STLVmFlowVar(name="mac_src", 
2576                                         min_value=1, 
2577                                         max_value=30, 
2578                                         size=2, op="dec",step=1), 
2579                            STLVmWrMaskFlowVar(fv_name="mac_src", 
2580                                               pkt_offset= 10,
2581                                               pkt_cast_size=2, 
2582                                               mask=0xff00,
2583                                               shift=8) # take the var shift it 8 (x256) write only to LSB
2584                           ]
2585                        )
2586 ----
2587
2588
2589 .Output 
2590 [format="csv",cols="1^", options="header",width="20%"]
2591 |=================
2592  value
2593  0x0100 
2594  0x0200 
2595  0x0300 
2596 |=================
2597
2598 *Example 3*::
2599
2600 In this example, STLVmWrMaskFlowVar instruction to generate the values shown in the table below as offset values for `pkt_offset`.
2601
2602 [source,python]
2603 ----
2604         vm = STLScVmRaw( [ STLVmFlowVar(name="mac_src", 
2605                                         min_value=1, 
2606                                         max_value=30, 
2607                                         size=2, 
2608                                         op="dec",step=1), 
2609                            STLVmWrMaskFlowVar(fv_name="mac_src", 
2610                                               pkt_offset= 10,
2611                                               pkt_cast_size=1, 
2612                                               mask=0x1,
2613                                               shift=-1)         <1>
2614                           ]
2615                        )
2616
2617 ----
2618 <1> Divides the value of `mac_src` by 2, and writes the LSB. For every two packets, the value written is changed.
2619
2620 .Output 
2621 [format="csv",cols="1^", options="header",width="20%"]
2622 |=================
2623 value
2624  0x00 
2625  0x00 
2626  0x01 
2627  0x01 
2628  0x00 
2629  0x00 
2630  0x01 
2631  0x01 
2632 |=================
2633
2634 ==== Tutorial: Advanced traffic profile
2635
2636 *Goal*::
2637
2638 * Define a different profile to operate in each traffic direction. 
2639 * Define a different profile for each port.
2640 * Tune a profile tune by the arguments of tunables.
2641
2642 Every traffic profile must define the following function:
2643
2644 [source,python]
2645 ----
2646 def get_streams (self, direction = 0, **kwargs)
2647 ----
2648
2649 `direction` is a mandatory field, required for any profile being loaded.
2650
2651 A profile can be given any key-value pairs which can be used to customize this profile. These are called "tunables".
2652
2653 The profile defines which tunables can be input to customize output.
2654
2655 *Usage notes for defining parameters*::
2656
2657 * All parameters require default values. 
2658 * A profile must be loadable with no parameters specified.
2659 * **kwargs (see Python documentation for information about keyworded arguments) contain all of the automatically provided values which are not tunables.
2660 * Every tuanble must be expressed as key-value pair with default value.
2661
2662
2663 For example, for the profile below, 'pcap_with_vm.py':
2664
2665 * The profile receives 'direction' as a tunable and mandatory field.
2666 * The profile defines 4 additional tunables.
2667 * Automatic values such as 'port_id' which are not tunables will be provided on kwargs.
2668
2669
2670 *File*:: link:{github_stl_path}/pcap_with_vm.py[stl/pcap_with_vm.py]
2671
2672 [source,python]
2673 ----
2674 def get_streams (self,
2675                  direction = 0,
2676                  ipg_usec = 10.0,
2677                  loop_count = 5,
2678                  ip_src_range = None,
2679                  ip_dst_range = {'start' : '10.0.0.1', 'end': '10.0.0.254'},
2680                  **kwargs)
2681 ----
2682
2683 *Direction*::
2684 `direction` is a tunable that is always provided by the API/console when loading a profile, but it can be overridden by the user. It is used to make the traffic profile more usable - for example, as a bi-directional profile. However, the profile can ignore this parameter.
2685
2686 By default, `direction` is equal to port_id % 2, so *even* numbered ports are provided with ''0'' and the *odd* numbered ports with ''1''.
2687
2688 [source,python]
2689 ----
2690 def get_streams (self, direction = 0,**kwargs):
2691     if direction = 0:
2692         rate =100                                       <1>
2693     else:    
2694         rate =200
2695     return [STLHltStream(tcp_src_port_mode = 'decrement',
2696                          tcp_src_port_count = 10,
2697                          tcp_src_port = 1234,
2698                          tcp_dst_port_mode = 'increment',
2699                          tcp_dst_port_count = 10,
2700                          tcp_dst_port = 1234,
2701                          name = 'test_tcp_ranges',
2702                          direction = direction,
2703                          rate_pps = rate,
2704                          ),
2705            ]
2706 ----
2707 <1> Specifies different rates (100 and 200) based on direction.
2708
2709 [source,bash]
2710 ----
2711 $start -f ex1.py -a 
2712 ----
2713  
2714 For 4 interfaces:
2715  
2716 * Interfaces 0 and 2: direction 0 
2717 * Interfaces 1 and 3: direction 1
2718  
2719 The rate changes accordingly. 
2720
2721 *Customzing Profiles Using ''port_id''*::
2722
2723 Keyworded arguments (**kwargs) provide default values that are passed along to the profile.
2724
2725 In the following, 'port_id' (port ID for the profile) is a **kwarg. Using port_id, you can define a complex profile based on different ID of ports, providing a different profile for each port.
2726
2727
2728 [source,python]
2729 ----
2730  
2731 def create_streams (self, direction = 0, **args):
2732
2733     port_id = args.get('port_id')
2734
2735     if port_id == 0:
2736      return [STLHltStream(tcp_src_port_mode = 'decrement',
2737                          tcp_src_port_count = 10,
2738                          tcp_src_port = 1234,
2739                          tcp_dst_port_mode = 'increment',
2740                          tcp_dst_port_count = 10,
2741                          tcp_dst_port = 1234,
2742                          name = 'test_tcp_ranges',
2743                          direction = direction,
2744                          rate_pps = rate,
2745                          ),
2746            ]
2747
2748    if port_id == 1:
2749         return STLHltStream(
2750                 #enable_auto_detect_instrumentation = '1', # not supported yet
2751                 ip_dst_addr = '192.168.1.3',
2752                 ip_dst_count = '1',
2753                 ip_dst_mode = 'increment',
2754                 ip_dst_step = '0.0.0.1',
2755                 ip_src_addr = '192.168.0.3',
2756                 ip_src_count = '1',
2757                 ip_src_mode = 'increment',
2758                 ip_src_step = '0.0.0.1',
2759                 l3_imix1_ratio = 7,
2760                 l3_imix1_size = 70,
2761                 l3_imix2_ratio = 4,
2762                 l3_imix2_size = 570,
2763                 l3_imix3_ratio = 1,
2764                 l3_imix3_size = 1518,
2765                 l3_protocol = 'ipv4',
2766                 length_mode = 'imix',
2767                 #mac_dst_mode = 'discovery', # not supported yet
2768                 mac_src = '00.00.c0.a8.00.03',
2769                 mac_src2 = '00.00.c0.a8.01.03',
2770                 pkts_per_burst = '200000',
2771                 rate_percent = '0.4',
2772                 transmit_mode = 'continuous',
2773                 vlan_id = '1',
2774                 direction = direction,
2775                 )
2776    
2777    if port_id = 3:
2778          ..
2779 ----
2780  
2781 *Full example using the TRex Console*::
2782
2783 The following command displays information about tunables for the pcap_with_vm.py traffic profile.
2784
2785 [source,bash]
2786 ----
2787 -=TRex Console v1.1=-
2788
2789 Type 'help' or '?' for supported actions
2790
2791 trex>profile -f stl/pcap_with_vm.py
2792
2793 Profile Information:
2794
2795
2796 General Information:
2797 Filename:         stl/pcap_with_vm.py
2798 Stream count:          5
2799
2800 Specific Information:
2801 Type:             Python Module
2802 Tunables:         ['direction = 0', 'ip_src_range = None', 'loop_count = 5', 'ipg_usec = 10.0',
2803                    "ip_dst_range = {'start': '10.0.0.1', 'end': '10.0.0.254'}"]
2804
2805 trex>                                                                                                                                                        
2806 ----
2807
2808 One can provide tunables on all those fields. The following command changes some:
2809
2810 [source,bash]
2811 ----
2812 trex>start -f stl/pcap_with_vm.py -t ipg_usec=15.0,loop_count=25
2813
2814 Removing all streams from port(s) [0, 1, 2, 3]:              [SUCCESS]
2815
2816
2817 Attaching 5 streams to port(s) [0]:                          [SUCCESS]
2818
2819
2820 Attaching 5 streams to port(s) [1]:                          [SUCCESS]
2821
2822
2823 Attaching 5 streams to port(s) [2]:                          [SUCCESS]
2824
2825
2826 Attaching 5 streams to port(s) [3]:                          [SUCCESS]
2827
2828
2829 Starting traffic on port(s) [0, 1, 2, 3]:                    [SUCCESS]
2830
2831 61.10 [ms]
2832
2833 trex>
2834 ----
2835
2836
2837 The following command customizes these to different ports:
2838
2839 [source,bash]
2840 ----
2841
2842 trex>start -f stl/pcap_with_vm.py --port 0 1 -t ipg_usec=15.0,loop_count=25#ipg_usec=100,loop_count=300
2843
2844 Removing all streams from port(s) [0, 1]:                    [SUCCESS]
2845
2846
2847 Attaching 5 streams to port(s) [0]:                          [SUCCESS]
2848
2849
2850 Attaching 5 streams to port(s) [1]:                          [SUCCESS]
2851
2852
2853 Starting traffic on port(s) [0, 1]:                          [SUCCESS]
2854
2855 51.00 [ms]
2856
2857 trex>
2858 ----
2859
2860
2861 ==== Tutorial: Per stream statistics 
2862
2863 * Per stream statistics are implemented using hardware assist when possible (examples: Intel X710/XL710 NIC flow director rules).
2864 * With other NICs (examples: Intel I350, 82599), per stream statistics are implemented in software.
2865 * Implementation:
2866 ** User chooses 32-bit packet group ID (pg_id) for each stream that need statistic reporting. Same pg_id can be used for more than one stream. In this case, statistics for all streams with the same pg_id will be combined.
2867 ** The IPv4 identification  (or IPv6 flow label in case of IPv6 packet) field of the stream is changed to a value within the reserved range 0xff00 to 0xffff (0xff00 to 0xfffff in case of IPv6). Note that if a stream for which no statistics are needed has an IPv4 Id (or IPv6 flow label) in the reserved range, it is changed (the left bit becomes 0).
2868 ** Software implementation: Hardware rules are used to direct packets from relevant streams to rx thread, where they are counted. 
2869 ** Hardware implementation: Hardware rules are inserted to count packets from relevant streams.
2870 * Summed up statistics (per stream, per port) is sent using a link:http://zguide.zeromq.org/[ZMQ] async channel to clients.
2871
2872 *Limitations*::
2873
2874 * The feature supports following packet types:
2875 ** IPv4 over Ethernet
2876 ** IPv4 with one VLAN tag (except 82599 which does not support this type of packet)
2877 ** IPv6 over Ethernet (except 82599 which does not support this type of packet)
2878 ** IPv6 with one VLAN tag (except 82599 which does not support this type of packet)
2879
2880 * Maximum number of concurrent streams (with different pg_id) on which statistics may be collected: 127
2881
2882 Two examples follow, one using the console and the other using the Python API.
2883
2884 *Console*::
2885
2886 The following simple traffic profile defines 2 streams and configures them with 2 different PG IDs.
2887
2888 *File*:: link:{github_stl_path}/flow_stats.py[stl/flow_stats.py]
2889
2890 [source,python]
2891 ----
2892
2893 class STLS1(object):
2894
2895     def get_streams (self, direction = 0):
2896         return [STLStream(packet = STLPktBuilder(pkt ="stl/yaml/udp_64B_no_crc.pcap"),
2897                           mode = STLTXCont(pps = 1000),
2898                           flow_stats = STLFlowStats(pg_id = 7)), <1>
2899
2900                 STLStream(packet = STLPktBuilder(pkt ="stl/yaml/udp_594B_no_crc.pcap"),
2901                           mode = STLTXCont(pps = 5000),
2902                           flow_stats = STLFlowStats(pg_id = 12)) <2>
2903                ]
2904
2905
2906 ----
2907 <1> Assigned to PG ID 7
2908 <2> Assigned to PG ID 12
2909
2910 The following command injects this to the console and uses the textual user interface (TUI) to display the TRex activity:
2911
2912 [source,bash]
2913 ----
2914 trex>start -f stl/flow_stats.py --port 0
2915
2916 Removing all streams from port(s) [0]:                       [SUCCESS]
2917
2918
2919 Attaching 2 streams to port(s) [0]:                          [SUCCESS]
2920
2921
2922 Starting traffic on port(s) [0]:                             [SUCCESS]
2923
2924 155.81 [ms]
2925
2926 trex>tui
2927
2928 Streams Statistics
2929
2930    PG ID    |        12         |         7
2931  --------------------------------------------------
2932  Tx pps     |         5.00 Kpps |        999.29 pps   #<1>
2933  Tx bps L2  |        23.60 Mbps |       479.66 Kbps
2934  Tx bps L1  |        24.40 Mbps |       639.55 Kbps
2935  ---        |                   |
2936  Rx pps     |         5.00 Kpps |        999.29 pps   #<2>
2937  Rx bps     |               N/A |               N/A   #<3>
2938  ----       |                   |
2939  opackets   |            222496 |             44500
2940  ipackets   |            222496 |             44500
2941  obytes     |         131272640 |           2670000
2942  ibytes     |               N/A |               N/A   #<3>
2943  -----      |                   |
2944  tx_pkts    |      222.50 Kpkts |       44.50 Kpkts
2945  rx_pkts    |      222.50 Kpkts |       44.50 Kpkts
2946  tx_bytes   |         131.27 MB |           2.67 MB
2947  rx_bytes   |               N/A |               N/A   #<3>
2948
2949 ----
2950 <1> Tx bandwidth of the streams matches the configured values.
2951 <2> Rx bandwidth (999.29 pps) matches the Tx bandwidth (999.29 pps), indicating that there were no drops.
2952 <3> RX BPS is not supported on this platform (no hardware support for BPS), so TRex displays N/A.
2953
2954
2955 *Flow Stats Using The Python API*::
2956
2957 The Python API example uses the following traffic profile:
2958
2959 [source,python]
2960 ----
2961 def rx_example (tx_port, rx_port, burst_size):
2962
2963     # create client
2964     c = STLClient()
2965     
2966     try:
2967         pkt = STLPktBuilder(pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/
2968                                   UDP(dport=12,sport=1025)/IP()/'a_payload_example')
2969
2970         s1 = STLStream(name = 'rx',
2971                        packet = pkt,
2972                        flow_stats = STLFlowStats(pg_id = 5),    <1>
2973                        mode = STLTXSingleBurst(total_pkts = 5000,
2974                                                percentage = 80  
2975                                                ))
2976
2977         # connect to server
2978         c.connect()
2979
2980         # prepare our ports - TX/RX
2981         c.reset(ports = [tx_port, rx_port])
2982
2983         # add the stream to the TX port
2984         c.add_streams([s1], ports = [tx_port])
2985
2986         # start and wait for completion
2987         c.start(ports = [tx_port])
2988         c.wait_on_traffic(ports = [tx_port])
2989
2990         # fetch stats for PG ID 5
2991         flow_stats = c.get_stats()['flow_stats'].get(5)    <2>
2992
2993         tx_pkts  = flow_stats['tx_pkts'].get(tx_port, 0)   <2>
2994         tx_bytes = flow_stats['tx_bytes'].get(tx_port, 0)  <2>
2995         rx_pkts  = flow_stats['rx_pkts'].get(rx_port, 0)   <2>
2996
2997 ----
2998 <1> Configures the stream to use PG ID 5.
2999 <2> The structure of the object ''flow_stats'' is described below.
3000
3001 ==== Tutorial: flow_stats object structure
3002
3003 The flow_stats object is a dictionary whose keys are the configured PG IDs. The next level is a dictionary containing 'tx_pkts', 'tx_bytes', 'rx_pkts', and 'rx_bytes' (on supported HW). Each of these keys contains a dictionary of per port values.
3004
3005 The following shows a flow_stats object for 3 PG IDs after a specific run:
3006
3007 [source,bash]
3008 ----
3009 {
3010  5: {'rx_pkts'  : {0: 0, 1: 0, 2: 500000, 3: 0, 'total': 500000},
3011      'tx_bytes' : {0: 0, 1: 39500000, 2: 0, 3: 0, 'total': 39500000},
3012      'tx_pkts'  : {0: 0, 1: 500000, 2: 0, 3: 0, 'total': 500000}},
3013
3014  7: {'rx_pkts'  : {0: 0, 1: 0, 2: 0, 3: 288, 'total': 288},
3015      'tx_bytes' : {0: 17280, 1: 0, 2: 0, 3: 0, 'total': 17280},
3016      'tx_pkts'  : {0: 288, 1: 0, 2: 0, 3: 0, 'total': 288}},
3017
3018  12: {'rx_pkts' : {0: 0, 1: 0, 2: 0, 3: 1439, 'total': 1439},
3019       'tx_bytes': {0: 849600, 1: 0, 2: 0, 3: 0, 'total': 849600},
3020       'tx_pkts' : {0: 1440, 1: 0, 2: 0, 3: 0, 'total': 1440}}
3021 }
3022 ----
3023
3024
3025 ==== Tutorial: Per stream latency/jitter/packet errors
3026
3027 * Per stream latency/jitter is implemented by software. This is an extension of the per stream statistics. Meaning, whenever you choose to get latency info for a stream, the statistics described
3028 in the "Per stream statistics" section is also available.
3029 * Implementation:
3030 ** User chooses 32-bit packet group ID (pg_id) for each stream that need latency reporting. pg_id should be unique per stream.
3031 ** The IPv4 identification field (or IPv6 flow label in case of IPv6 packet) of the stream is changed to some defined constant value (in the reserved range described in the "per stream statistics" section), in order to signal the hardware to pass the stream to software.
3032 ** Last 16 bytes of the packet payload is used to pass needed information. Information contains ID of the stream, packet sequence number (per stream), timestamp of packet transmission.
3033
3034 * Gathered info (per stream) is sent using a link:http://zguide.zeromq.org/[ZMQ] async channel to clients.
3035
3036 *Limitations*::
3037
3038 * The feature supports following packet types:
3039 ** IPv4 over Ethernet
3040 ** IPv4 with one VLAN tag (except 82599 which does not support this type of packet)
3041 ** IPv6 over Ethernet (except 82599 which does not support this type of packet)
3042 ** IPv6 with one VLAN tag (except 82599 which does not support this type of packet)
3043 * Packets must contain at least 16 bytes of payload.
3044 * Each stream must have unique pg_id number. This also means that a given "latency collecting" stream can't be transmitted from two interfaces in parallel (internally it means that there are two streams). 
3045 * Maximum number of concurrent streams (with different pg_id) on which latency info may be collected: 128 (This is in addition to the streams which collect per stream statistics).
3046 * Global multiplier does not apply to this type of stream. The reason is that latency streams are processed by software, so multiplying them might accidently overwhelm the RX core.
3047   This means that if you have profile with 1 latency stream, and 1 non latency stream, and you change the traffic multipler, latency stream keeps the same rate. If you want to change
3048   the rate of a latency stream, you need to manually edit your profile file. Usually this is not necessary, since normally you stress the system using non latency stream, and (in parallel) measure latency 
3049   using constant rate latency stream.
3050
3051 [IMPORTANT]
3052 =====================================
3053 Latency streams are not supported in full line rate like normal streams. Both from, transmit and receive point of view. This is a design consideration to keep the latency measurement accurate and preserve CPU resource. One of the reason for doing so that in most cases it is enough to have a latency stream not in full rate. For example, if the required latency resolution is 10usec there is no need to send a latency stream in speed higher than 100KPPS- usually queues are built over time, so it is not possible that one packet will have a latency and another packet in the same path will not have the same latency. The none latency stream could be in full line rate (e.g. 100MPPS) to load the DUT while the low speed latency stream will measure this path latency. 
3054 Don't expect the total latency streams rate to be higher than 1-5MPPS 
3055 =====================================
3056
3057 Two examples follow. One using the console and the other using the Python API.
3058
3059 *Console*::
3060
3061 The following simple traffic profile defines 2 streams and configures them with 2 different PG IDs.
3062
3063 *File*:: link:{github_stl_path}/flow_stats_latency.py[stl/flow_stats_latency.py]
3064
3065 [source,python]
3066 ----
3067
3068 class STLS1(object):
3069
3070     def get_streams (self, direction = 0):
3071         return [STLStream(packet = STLPktBuilder(pkt ="stl/yaml/udp_64B_no_crc.pcap"),
3072                           mode = STLTXCont(pps = 1000),
3073                           flow_stats = STLFlowLatencyStats(pg_id = 7)), <1>
3074
3075                 STLStream(packet = STLPktBuilder(pkt ="stl/yaml/udp_594B_no_crc.pcap"),
3076                           mode = STLTXCont(pps = 5000),
3077                           flow_stats = STLFlowLatencyStats(pg_id = 12)) <2>
3078                ]
3079
3080
3081 ----
3082 <1> Assigned to PG ID 7 , PPS would be *1000* regardless of the multplier 
3083 <2> Assigned to PG ID 12, PPS would be *5000* regardless of the multplier 
3084
3085 The following command injects this to the console and uses the textual user interface (TUI) to display the TRex activity:
3086
3087 [source,bash]
3088 ----
3089 trex>start -f stl/flow_stats.py --port 0
3090
3091 trex>tui
3092
3093 Latency Statistics (usec)
3094
3095    PG ID     |       7       |       12
3096  ----------------------------------------------
3097  Max latency  |              0 |              0 #<1>
3098  Avg latency  |              5 |              5 #<2>
3099  -- Window -- |                |
3100  Last (max)   |              3 |              4 #<3>
3101  Last-1       |              3 |              3
3102  Last-2       |              4 |              4
3103  Last-3       |              4 |              3
3104  Last-4       |              4 |              4
3105  Last-5       |              3 |              4
3106  Last-6       |              4 |              3
3107  Last-7       |              4 |              3
3108  Last-8       |              4 |              4
3109  Last-9       |              4 |              3
3110  ---          |                |
3111  Jitter       |              0 |              0 #<4>
3112  ----         |                |
3113  Errors       |              0 |              0 #<5>
3114
3115 ----
3116 <1> Maximum latency measured over the stream lifetime (in usec).
3117 <2> Average latency over the stream lifetime (usec).
3118 <3> Maximum latency measured between last two data reads from server (We currently read every 0.5 second).
3119     Numbers below are maximum latency for previous measuring periods, so we get latency history for last few seconds.
3120 <4> Jitter of latency measurements.
3121 <5> Indication of number of errors (it is the sum of seq_too_high and seq_too_low. You can see description in Python API doc below). In the future it will be possible to 'zoom in', to see specific counters.
3122     For now, if you need to see specific counters, you can use the Python API.
3123    
3124
3125 An example of API usage is as follows
3126
3127 *Example File*:: link:{github_stl_examples_path}/stl_flow_latency_stats.py[stl_flow_latency_stats.py]
3128
3129 [source,python]
3130 ----
3131
3132     stats = c.get_stats()
3133
3134     flow_stats = stats['flow_stats'].get(5)
3135     lat_stats = stats['latency'].get(5)                 <1>
3136
3137
3138     tx_pkts  = flow_stats['tx_pkts'].get(tx_port, 0)
3139     tx_bytes = flow_stats['tx_bytes'].get(tx_port, 0)
3140     rx_pkts  = flow_stats['rx_pkts'].get(rx_port, 0)
3141     drops = lat_stats['err_cntrs']['dropped']
3142     ooo = lat_stats['err_cntrs']['out_of_order']
3143     dup = lat_stats['err_cntrs']['dup']
3144     sth = lat_stats['err_cntrs']['seq_too_high']
3145     stl = lat_stats['err_cntrs']['seq_too_low']
3146     lat = lat_stats['latency']
3147     jitter = lat['jitter']
3148     avg = lat['average']
3149     tot_max = lat['total_max']
3150     last_max = lat['last_max']
3151     hist = lat ['histogram']
3152     
3153     # lat_stats will be in this format   
3154
3155     latency_stats ==  {  
3156          'err_cntrs':{                  # error counters <2>
3157             u'dup':0,                   # Same sequence number was received twice in a row
3158             u'out_of_order':0,          # Packets received with sequence number too low (We assume it is reorder)
3159             u'dropped':0                # Estimate of number of packets that were dropped (using seq number)
3160             u'seq_too_high':0,          # seq number too high events
3161             u'seq_too_low':0,           # seq number too low events
3162          },
3163          'latency':{  
3164             'jitter':0,                 # in usec
3165             'average':15.2,             # average latency (usec)
3166             'last_max':0,               # last 0.5 sec window maximum latency (usec)
3167             'total_max':44,             # maximum latency (usec)
3168             'histogram':[               # histogram of latency
3169                {  
3170                   u'key':20,            # bucket counting packets with latency in the range 20 to 30 usec
3171                   u'val':489342         # number of samples that hit this bucket's range
3172                },
3173                {  
3174                   u'key':30,
3175                   u'val':10512
3176                },
3177                {  
3178                   u'key':40,
3179                   u'val':143
3180                },
3181                {  
3182                   'key':0,              # bucket counting packets with latency in the range 0 to 10 usec
3183                   'val':3
3184                }
3185             ]
3186          }
3187       },
3188
3189    
3190 ----
3191 <1> Get the Latency dictionary
3192 <2> For calculating packet error events, we add sequence number to each packet's payload. We decide what went wrong only according to sequence number
3193     of last packet received and that of the previous packet. 'seq_too_low' and 'seq_too_high' count events we see. 'dup', 'out_of_order' and 'dropped'
3194     are heuristics we apply to try and understand what happened. They will be accurate in common error scenarios.
3195     We describe few scenarios below to help understand this. + 
3196
3197 *Error counters scenarios*::
3198 Scenario 1: Received packet with seq num 10, and another one with seq num 10. We increment 'dup' and 'seq_too_low' by 1. + 
3199 Scenario 2: Received pacekt with seq num 10 and then packet with seq num 15. We assume 4 packets were dropped, and increment 'dropped' by 4, and 'seq_too_high' by 1.
3200   We expect next packet to arrive with sequence number 16. + 
3201 Scenario 2 continue: Received packet with seq num 11. We increment 'seq_too_low' by 1. We increment 'out_of_order' by 1. We *decrement* 'dropped' by 1.
3202   (We assume here that one of the packets we considered as dropped before, actually arrived out of order).
3203
3204 ==== Tutorial: HLT traffic profile 
3205
3206 The traffic_config API has set of arguments for specifying streams - in particular, the packet template, which field, and how to send it.
3207 // clarify "which field"
3208 It is possible to define a traffic profile using HTTAPI arguments.
3209 // clarify names: "HLT traffic profile", "traffic_config API", "HTTAP"
3210 The API creates native Scapy/Field Engine instructions.
3211 For limitations see xref:altapi-support[here].
3212
3213 *File*:: link:{github_stl_path}/hlt/hlt_udp_inc_dec_len_9k.py[stl/hlt/hlt_udp_inc_dec_len_9k.py]
3214
3215 [source,python]
3216 ----
3217
3218 class STLS1(object):
3219     '''
3220     Create 2 Eth/IP/UDP streams with different packet size:
3221     First stream will start from 64 bytes (default) and will increase until max_size (9,216)
3222     Seconds stream will decrease the packet size in reverse way
3223     '''
3224
3225     def create_streams (self):
3226         max_size = 9*1024
3227         return [STLHltStream(length_mode = 'increment',
3228                              frame_size_max = max_size,
3229                              l3_protocol = 'ipv4',
3230                              ip_src_addr = '16.0.0.1',
3231                              ip_dst_addr = '48.0.0.1',
3232                              l4_protocol = 'udp',
3233                              udp_src_port = 1025,
3234                              udp_dst_port = 12,
3235                              rate_pps = 1,
3236                              ),
3237                 STLHltStream(length_mode = 'decrement',
3238                              frame_size_max = max_size,
3239                              l3_protocol = 'ipv4',
3240                              ip_src_addr = '16.0.0.1',
3241                              ip_dst_addr = '48.0.0.1',
3242                              l4_protocol = 'udp',
3243                              udp_src_port = 1025,
3244                              udp_dst_port = 12,
3245                              rate_pps = 1,
3246                              )
3247                ]
3248
3249     def get_streams (self, direction = 0, **kwargs):
3250         return self.create_streams()
3251 ----
3252
3253 The following command, within a bash window, runs the traffic profile with the simulator to generate pcap file.
3254
3255 [source,bash]
3256 ----
3257 $ ./stl-sim -f stl/hlt/hlt_udp_inc_dec_len_9k.py -o b.pcap -l 10 
3258 ----
3259
3260 The following commands, within a bash window, convert to native JSON or YAML.
3261
3262 [source,bash]
3263 ----
3264 $ ./stl-sim -f stl/hlt/hlt_udp_inc_dec_len_9k.py --json
3265 ----
3266
3267 [source,bash]
3268 ----
3269 $ ./stl-sim -f stl/hlt/hlt_udp_inc_dec_len_9k.py --yaml
3270 ----
3271
3272 Alternatively, use the following command to convert to a native Python profile.
3273
3274 [source,bash]
3275 ----
3276 $ ./stl-sim -f stl/hlt/hlt_udp_inc_dec_len_9k.py --native 
3277 ----
3278
3279 .Auto-generated code
3280 [source,python]
3281 ----
3282 # !!! Auto-generated code !!!
3283 from trex_stl_lib.api import *
3284
3285 class STLS1(object):
3286     def get_streams(self):
3287         streams = []
3288         
3289         packet = (Ether(src='00:00:01:00:00:01', dst='00:00:00:00:00:00', type=2048) / 
3290                   IP(proto=17, chksum=5882, len=9202, ihl=5L, id=0) / 
3291                   UDP(dport=12, sport=1025, len=9182, chksum=55174) / 
3292                   Raw(load='!' * 9174))
3293         vm = STLScVmRaw([CTRexVmDescFlowVar(name='pkt_len', size=2, op='inc', 
3294                           init_value=64, min_value=64, max_value=9216, step=1),
3295                          CTRexVmDescTrimPktSize(fv_name='pkt_len'),
3296                          CTRexVmDescWrFlowVar(fv_name='pkt_len', 
3297                          pkt_offset=16, add_val=-14, is_big=True),
3298                          CTRexVmDescWrFlowVar(fv_name='pkt_len', 
3299                          pkt_offset=38, add_val=-34, is_big=True),
3300                          CTRexVmDescFixIpv4(offset=14)], split_by_field = 'pkt_len')
3301         stream = STLStream(packet = CScapyTRexPktBuilder(pkt = packet, vm = vm),
3302                            mode = STLTXCont(pps = 1.0))
3303         streams.append(stream)
3304         
3305         packet = (Ether(src='00:00:01:00:00:01', dst='00:00:00:00:00:00', type=2048) / 
3306                   IP(proto=17, chksum=5882, len=9202, ihl=5L, id=0) / 
3307                   UDP(dport=12, sport=1025, len=9182, chksum=55174) / 
3308                   Raw(load='!' * 9174))
3309         vm = STLScVmRaw([CTRexVmDescFlowVar(name='pkt_len', size=2, op='dec', 
3310                          init_value=9216, min_value=64, 
3311                          max_value=9216, step=1),
3312                          CTRexVmDescTrimPktSize(fv_name='pkt_len'),
3313                          CTRexVmDescWrFlowVar(fv_name='pkt_len', pkt_offset=16, 
3314                          add_val=-14, is_big=True),
3315                          CTRexVmDescWrFlowVar(fv_name='pkt_len', 
3316                          pkt_offset=38, add_val=-34, is_big=True),
3317                          CTRexVmDescFixIpv4(offset=14)], split_by_field = 'pkt_len')
3318         stream = STLStream(packet = CScapyTRexPktBuilder(pkt = packet, vm = vm),
3319                            mode = STLTXCont(pps = 1.0))
3320         streams.append(stream)
3321
3322         return streams
3323
3324 def register():
3325     return STLS1()
3326 ----    
3327
3328 Use the following command within the TRex console to run the profile.
3329
3330 [source,bash]
3331 ----
3332 TRex>start -f stl/hlt/hlt_udp_inc_dec_len_9k.py -m 10mbps -a     
3333 ----
3334
3335
3336 === PCAP Based Traffic Tutorials
3337
3338 ==== PCAP Based Traffic
3339
3340 TRex provides a method of using a pre-recorded traffic as a profile template.
3341
3342 There are two main distinct ways of creating a profile or a test based on a PCAP.
3343
3344 * Local PCAP push 
3345 * Server based push
3346
3347 ===== Local PCAP push
3348
3349 On this mode, the PCAP file is loaded locally by the Python client,
3350 transformed to a list of streams which each one contains a single packet
3351 and points to the next one.
3352
3353 This allows of a very flexible structure which can basically provide every
3354 functionality that a regular list of streams allow.
3355
3356 However, due to the overhead of processing and 
3357 sending a list of streams this method is limited to a file size (on default 1MB)
3358
3359
3360 *Pros:*
3361
3362 * supports most CAP file formats
3363 * supports field engine
3364 * provides a way of locally manipulating packets as streams
3365 * supports same rate as regular streams
3366
3367 *Cons:*
3368
3369 * limited in file size
3370 * high configuration time due to transmitting the CAP file as streams
3371
3372
3373 ===== Server based push
3374
3375 To provide also a way of injecting a much larger PCAP files, TRex also provides
3376 a server based push.
3377
3378 The mechansim is much different and it simply providing a server a PCAP file which
3379 in turn is loaded to the server and injected packet after packet.
3380
3381 This method provides an unlimited file size to be injected, and the overhead of
3382 setting up the server with the required configuration is much lower.
3383
3384
3385 *Pros:*
3386
3387 * no limitation of PCAP file size
3388 * no overhead in sending any size of PCAP to the server
3389
3390 *Cons:*
3391
3392 * does not support field engine
3393 * support only PCAP and ERF formats
3394 * requires the file path to be accessible from the server
3395 * rate of transmition is usually limited by I/O performance and buffering (HDD)
3396
3397
3398 ==== Tutorial: Simple PCAP file - Profile
3399
3400 *Goal*:: Load a pcap file with a *number* of packets, creating a stream with a burst value of 1 for each packet. The inter-stream gap (ISG) for each stream is equal to the inter-packet gap (IPG).
3401
3402 *File*:: link:{github_stl_path}/pcap.py[pcap.py]
3403
3404 [source,python]
3405 ----
3406     def get_streams (self,
3407                      ipg_usec = 10.0,                           <1>
3408                      loop_count = 1):                           <2>
3409
3410         profile = STLProfile.load_pcap(self.pcap_file,          <3>
3411                                        ipg_usec = ipg_usec, 
3412                                        loop_count = loop_count)
3413 ----
3414 <1> The inter-stream gap in microseconds.
3415 <2> Loop count.
3416 <3> Input pcap file. 
3417
3418 // Please leave this comment - helping rendition.
3419
3420 image::images/stl_loop_count_01b.png[title="Example of multiple streams",align="left",width="80%", link="images/stl_loop_count_01b.png"]
3421
3422 // OBSOLETE: image::images/stl_loop_count_01b.png[title="Streams, loop_count",align="left",width={p_width_1a}, link="images/stl_loop_count_01b.png"]
3423
3424 The figure shows the streams for a pcap file with 3 packets, with a loop configured.
3425
3426 * Each stream is configured to Burst mode with 1 packet.
3427 * Each stream triggers the next stream. 
3428 * The last stream triggers the first with `action_loop=loop_count` if `loop_count` > 1.
3429
3430 The profile runs on one DP thread because it has a burst with 1 packet. (Split cannot work in this case).
3431
3432 To run this example, enter:
3433
3434 [source,bash]
3435 ----
3436 ./stl-sim -f stl/pcap.py --yaml
3437 ----
3438
3439 The following output appears:
3440
3441 [source,python]
3442 ----
3443 $./stl-sim -f stl/pcap.py --yaml
3444 - name: 1
3445   next: 2                      <1> 
3446   stream:
3447     action_count: 0
3448     enabled: true
3449     flags: 0
3450     isg: 10.0
3451     mode:
3452       percentage: 100
3453       total_pkts: 1
3454       type: single_burst
3455     packet:
3456       meta: ''
3457     rx_stats:
3458       enabled: false
3459     self_start: true
3460     vm:
3461       instructions: []
3462       split_by_var: ''
3463 - name: 2
3464   next: 3
3465   stream:
3466     action_count: 0
3467     enabled: true
3468     flags: 0
3469     isg: 10.0
3470     mode:
3471       percentage: 100
3472       total_pkts: 1
3473       type: single_burst
3474     packet:
3475       meta: ''
3476     rx_stats:
3477       enabled: false
3478     self_start: false
3479     vm:
3480       instructions: []
3481       split_by_var: ''
3482 - name: 3
3483   next: 4
3484   stream:
3485     action_count: 0
3486     enabled: true
3487     flags: 0
3488     isg: 10.0
3489     mode:
3490       percentage: 100
3491       total_pkts: 1
3492       type: single_burst
3493     packet:
3494       meta: ''
3495     rx_stats:
3496       enabled: false
3497     self_start: false
3498     vm:
3499       instructions: []
3500       split_by_var: ''
3501 - name: 4
3502   next: 5
3503   stream:
3504     action_count: 0
3505     enabled: true
3506     flags: 0
3507     isg: 10.0
3508     mode:
3509       percentage: 100
3510       total_pkts: 1
3511       type: single_burst
3512     packet:
3513       meta: ''
3514     rx_stats:
3515       enabled: false
3516     self_start: false
3517     vm:
3518       instructions: []
3519       split_by_var: ''
3520 - name: 5
3521   next: 1                   <2>
3522   stream:
3523     action_count: 1         <3>
3524     enabled: true
3525     flags: 0
3526     isg: 10.0
3527     mode:
3528       percentage: 100
3529       total_pkts: 1
3530       type: single_burst
3531     packet:
3532       meta: ''
3533     rx_stats:
3534       enabled: false
3535     self_start: false       <4>    
3536     vm:
3537       instructions: []
3538       split_by_var: ''
3539 ----
3540 <1> Each stream triggers the next stream.
3541 <2> The last stream triggers the first. 
3542 <3> The current loop count is given in: `action_count: 1`
3543 <4> `Self_start` is enabled for the first stream, disabled for all other streams.
3544
3545
3546 ==== Tutorial: Simple PCAP file - API
3547
3548 For this case we can use the local push:
3549
3550 [source,bash]
3551 ----
3552 c = STLClient(server = "localhost")
3553
3554 try:
3555
3556     c.connect()
3557     c.reset(ports = [0])
3558
3559     d = c.push_pcap(pcap_file = "my_file.pcap",             # our local PCAP file
3560                     ports = 0,                              # use port 0
3561                     ipg_usec = 100,                         # IPG
3562                     count = 1)                              # inject only once
3563
3564     c.wait_on_traffic()
3565
3566
3567     stats = c.get_stats()
3568     opackets = stats[port]['opackets']
3569     print("{0} packets were Tx on port {1}\n".format(opackets, port))
3570
3571   except STLError as e:
3572       print(e)
3573       sys.exit(1)
3574
3575   finally:
3576       c.disconnect()
3577
3578 ----
3579
3580 ==== Tutorial: PCAP file iterating over dest IP 
3581
3582 For this case we can use the local push:
3583
3584 [source,bash]
3585 ----
3586 c = STLClient(server = "localhost")
3587
3588 try:
3589
3590     c.connect()
3591     port = 0
3592     c.reset(ports = [port])
3593
3594     vm = STLIPRange(dst = {'start': '10.0.0.1', 'end': '10.0.0.254', 'step' : 1})
3595
3596     c.push_pcap(pcap_file = "my_file.pcap",             # our local PCAP file
3597                 ports = port,                           # use 'port'
3598                 ipg_usec = 100,                         # IPG
3599                 count = 1,                              # inject only once
3600                 vm = vm                                 # provide VM object
3601                 )
3602
3603     c.wait_on_traffic()
3604
3605     stats = c.get_stats()
3606     opackets = stats[port]['opackets']
3607     print("{0} packets were Tx on port {1}\n".format(opackets, port))
3608
3609   except STLError as e:
3610       print(e)
3611       sys.exit(1)
3612
3613   finally:
3614       c.disconnect()
3615
3616 ----
3617
3618 ==== Tutorial: PCAP file with VLAN 
3619
3620 This is a more intresting case where we can provide the push API a function hook.
3621 The hook will be called for each packet that is loaded from the PCAP file.
3622
3623 [source,bash]
3624 ----
3625 # generate a packet hook function with a VLAN ID
3626 def packet_hook_generator (vlan_id):
3627
3628     # this function will be called for each packet and will expect
3629     # the new packet as a return value
3630     def packet_hook (packet):
3631         packet = Ether(packet)
3632
3633         if vlan_id >= 0 and vlan_id <= 4096:
3634             packet_l3 = packet.payload
3635             packet = Ether() / Dot1Q(vlan = vlan_id) / packet_l3
3636
3637         return str(packet)
3638
3639     return packet_hook
3640
3641 c = STLClient(server = "localhost")
3642
3643 try:
3644
3645     c.connect()
3646     port = 0
3647     c.reset(ports = [port])
3648
3649     vm = STLIPRange(dst = {'start': '10.0.0.1', 'end': '10.0.0.254', 'step' : 1})
3650
3651     d = c.push_pcap(pcap_file = "my_file.pcap",
3652                     ports = port,         
3653                     ipg_usec = 100,
3654                     count = 1,
3655                     packet_hook = packet_hook_generator(vlan_id = 1)
3656                     )
3657
3658     c.wait_on_traffic()
3659
3660     stats = c.get_stats()
3661     opackets = stats[port]['opackets']
3662     print("{0} packets were Tx on port {1}\n".format(opackets, port))
3663
3664   except STLError as e:
3665       print(e)
3666       sys.exit(1)
3667
3668   finally:
3669       c.disconnect()
3670
3671 ----
3672
3673 ==== Tutorial: PCAP file and Field Engine - Profile
3674
3675 The following example loads a pcap file to many streams, and attaches Field Engine program to each stream. For example, the Field Engine can change the `IP.src` of all the streams to a random IP address.
3676  
3677 *File*:: link:{github_stl_path}/pcap_with_vm.py[stl/pcap_with_vm.py]
3678
3679 [source,python]
3680 ----
3681
3682     def create_vm (self, ip_src_range, ip_dst_range):
3683         if not ip_src_range and not ip_dst_range:
3684             return None
3685
3686         # until the feature of offsets will be fixed for PCAP use hard coded offsets
3687
3688         vm = []
3689
3690         if ip_src_range:
3691             vm += [STLVmFlowVar(name="src", 
3692                                 min_value = ip_src_range['start'], 
3693                                 max_value = ip_src_range['end'], 
3694                                 size = 4, op = "inc"),
3695                    #STLVmWrFlowVar(fv_name="src",pkt_offset= "IP.src")
3696                    STLVmWrFlowVar(fv_name="src",pkt_offset = 26)
3697                   ]
3698
3699         if ip_dst_range:
3700             vm += [STLVmFlowVar(name="dst", 
3701                                 min_value = ip_dst_range['start'], 
3702                                 max_value = ip_dst_range['end'], 
3703                                 size = 4, op = "inc"),
3704                    
3705                    #STLVmWrFlowVar(fv_name="dst",pkt_offset= "IP.dst")
3706                    STLVmWrFlowVar(fv_name="dst",pkt_offset = 30)
3707                    ]
3708
3709         vm += [#STLVmFixIpv4(offset = "IP")
3710               STLVmFixIpv4(offset = 14)
3711               ]
3712
3713         return vm
3714
3715
3716     def get_streams (self,
3717                      ipg_usec = 10.0,
3718                      loop_count = 5,
3719                      ip_src_range = None,
3720                      ip_dst_range = {'start' : '10.0.0.1', 
3721                                         'end': '10.0.0.254'}):
3722
3723         vm = self.create_vm(ip_src_range, ip_dst_range)                 <1> 
3724         profile = STLProfile.load_pcap(self.pcap_file, 
3725                                       ipg_usec = ipg_usec, 
3726                                       loop_count = loop_count, 
3727                                       vm = vm)                          <2> 
3728
3729         return profile.get_streams()
3730 ----
3731 <1> Creates Field Engine program.
3732 <2> Applies the Field Engine to all packets -> converts to streams. 
3733
3734 .Output 
3735 [format="csv",cols="1^,2^,1^", options="header",width="40%"]
3736 |=================
3737 pkt, IPv4 , flow 
3738  1  , 10.0.0.1, 1 
3739  2  , 10.0.0.1, 1 
3740  3  , 10.0.0.1, 1 
3741  4  , 10.0.0.1, 1 
3742  5  , 10.0.0.1, 1 
3743  6  , 10.0.0.1, 1
3744  7  , 10.0.0.2, 2
3745  8  , 10.0.0.2, 2 
3746  9  , 10.0.0.2, 2 
3747  10  , 10.0.0.2,2  
3748  11  , 10.0.0.2,2  
3749  12  , 10.0.0.2,2 
3750 |=================
3751
3752
3753 ==== Tutorial: Huge server side PCAP file
3754
3755 Now we would like to use the remote push API.
3756 This will require the file path to be visible to the server.
3757
3758 [source,bash]
3759 ----
3760 c = STLClient(server = "localhost")
3761
3762 try:
3763
3764     c.connect()
3765     c.reset(ports = [0])
3766
3767     # use an absolute path so the server can reach this
3768     pcap_file = os.path.abspath(pcap_file)
3769
3770     c.push_remote(pcap_file = pcap_file,                  
3771                   ports = 0,                              
3772                   ipg_usec = 100,                         
3773                   count = 1)                              
3774
3775     c.wait_on_traffic()
3776
3777
3778     stats = c.get_stats()
3779     opackets = stats[port]['opackets']
3780     print("{0} packets were Tx on port {1}\n".format(opackets, port))
3781
3782   except STLError as e:
3783       print(e)
3784       sys.exit(1)
3785
3786   finally:
3787       c.disconnect()
3788
3789 ----
3790
3791 ==== Tutorial: A long list of PCAP files of varied sizes
3792
3793 This is also a good candidate for the remote push API.
3794 The total overhead for sending the PCAP files will be high if the list is long,
3795 so we would prefer to inject them with remote API and to save the transmition of the packets.
3796
3797 [source,bash]
3798 ----
3799 c = STLClient(server = "localhost")
3800
3801 try:
3802
3803     c.connect()
3804     c.reset(ports = [0])
3805
3806     # iterate over the list and send each file to the server
3807     for pcap_file in pcap_file_list:
3808         pcap_file = os.path.abspath(pcap_file)
3809
3810         c.push_remote(pcap_file = pcap_file,                  
3811                       ports = 0,                              
3812                       ipg_usec = 100,                         
3813                       count = 1)                              
3814
3815         c.wait_on_traffic()
3816
3817
3818         stats = c.get_stats()
3819         opackets = stats[port]['opackets']
3820         print("{0} packets were Tx on port {1}\n".format(opackets, port))
3821
3822   except STLError as e:
3823       print(e)
3824       sys.exit(1)
3825
3826   finally:
3827       c.disconnect()
3828
3829 ----
3830
3831 === Performance Tweaking
3832 In this section we provide some advanced features to help get the most of TRex performance.
3833 The reason that those features are not active out of the box because they might have
3834 some impact on other areas and in general, might sacrafice one or more properties
3835 that requires the user to explicitly give up on those.
3836
3837 ==== Caching MBUFs
3838
3839
3840 see xref:trex_cache_mbuf[here]
3841
3842
3843 ==== Core masking per interface
3844 By default, TRex will regard any TX command with a **greedy approach**:
3845 All the DP cores associated with this port will be assigned in order to produce the maximum
3846 throughput.
3847
3848 image::images/core_mask_split.png[title="Greedy Approach - Splitting",align="left",width={p_width}, link="images/core_mask_split.png"]
3849
3850 However, in some cases it might be beneficial to provide a port with a subset of the cores to use.
3851
3852
3853 For example, when injecting traffic on two ports and the following conditions are met:
3854
3855 * the two ports are adjacent
3856 * the profile is symmetric
3857
3858 Due to TRex architecture, adjacent ports (e.g. port 0 & port 1) shares the same cores,
3859 and using the greedy approach will cause all the cores to transmit on both port 0 and port 1.
3860
3861 When the profile is *symmetric* it will be wiser to pin half the cores to port 0 and half
3862 the cores to port 1 and thus avoid cache trashing and bouncing.
3863 If the profile is not symmetric, the static pinning may deny CPU cycles from the more congested port.
3864
3865 image::images/core_mask_pin.png[title="Pinning Cores To Ports",align="left",width={p_width}, link="images/core_mask_pin.png"]
3866
3867 TRex provides this in two ways:
3868
3869
3870 ==== Predefind modes
3871
3872 As said above, the default mode is 'split' mode, but you can provide a predefined mode called 'pin'.
3873 This can be done by both API and from the console:
3874
3875 [source,bash]
3876 ----
3877
3878 trex>start -f stl/syn_attack.py -m 40mpps --total -p 0 1 --pin        <-- provide '--pin' to the command
3879
3880 Removing all streams from port(s) [0, 1]:                    [SUCCESS]
3881
3882
3883 Attaching 1 streams to port(s) [0]:                          [SUCCESS]
3884
3885
3886 Attaching 1 streams to port(s) [1]:                          [SUCCESS]
3887
3888
3889 Starting traffic on port(s) [0, 1]:                          [SUCCESS]
3890
3891 60.20 [ms]
3892
3893 trex>
3894
3895 ----
3896
3897
3898 .API example to PIN cores 
3899 [source,python]
3900 ----
3901  c.start(ports = [port_a, port_b], mult = rate,core_mask=STLClient.CORE_MASK_PIN) <1>      
3902 ----       
3903 <1> core_mask = STLClient.CORE_MASK_PIN 
3904
3905 .API example to MASK cores 
3906 [source,python]
3907 ----
3908  c.start(ports = [port_a, port_b], mult = rate, core_mask=[0x1,0x2])<1>
3909 ----       
3910 <1> DP Core 0 (mask==1) is assign to port 1 and DP core 1 (mask==2) is for port 2
3911
3912
3913 [source,bash]
3914 ----
3915
3916 We can see in the CPU util. available from the TUI window,
3917 that each core was reserverd for an interface:
3918
3919 Global Stats:
3920
3921 Total Tx L2  : 20.49 Gb/sec
3922 Total Tx L1  : 26.89 Gb/sec
3923 Total Rx     : 20.49 Gb/sec
3924 Total Pps    : 40.01 Mpkt/sec       <-- performance meets the requested rate
3925 Drop Rate    : 0.00 b/sec
3926 Queue Full   : 0 pkts
3927
3928
3929 Cpu Util(%)
3930
3931   Thread   | Avg | Latest | -1  | -2  | -3  | -4  | -5  | -6  | -7  | -8 
3932
3933  0   (0)   |  92 |     92 |  92 |  91 |  91 |  92 |  91 |  92 |  93 |  94
3934  1 (IDLE)  |   0 |      0 |   0 |   0 |   0 |   0 |   0 |   0 |   0 |   0
3935  2   (1)   |  96 |     95 |  95 |  96 |  96 |  96 |  96 |  95 |  94 |  95
3936  3 (IDLE)  |   0 |      0 |   0 |   0 |   0 |   0 |   0 |   0 |   0 |   0
3937  4   (0)   |  92 |     93 |  93 |  91 |  91 |  93 |  93 |  93 |  93 |  93
3938  5 (IDLE)  |   0 |      0 |   0 |   0 |   0 |   0 |   0 |   0 |   0 |   0
3939  6   (1)   |  88 |     88 |  88 |  88 |  88 |  88 |  88 |  88 |  87 |  87
3940  7 (IDLE)  |   0 |      0 |   0 |   0 |   0 |   0 |   0 |   0 |   0 |   0
3941
3942 ----
3943
3944
3945 If we had used the *default mode*, the table should have looked like this, and yield
3946 much worse performance:
3947
3948 [source,bash]
3949 ----
3950
3951 Global Stats:
3952
3953 Total Tx L2  : 12.34 Gb/sec
3954 Total Tx L1  : 16.19 Gb/sec
3955 Total Rx     : 12.34 Gb/sec
3956 Total Pps    : 24.09 Mpkt/sec       <-- performance is quite low than requested
3957 Drop Rate    : 0.00 b/sec
3958 Queue Full   : 0 pkts
3959
3960 Cpu Util(%)
3961
3962   Thread   | Avg | Latest | -1  | -2  | -3  | -4  | -5  | -6  | -7  | -8  
3963
3964  0  (0,1)  | 100 |    100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 
3965  1 (IDLE)  |   0 |      0 |   0 |   0 |   0 |   0 |   0 |   0 |   0 |   0 
3966  2  (0,1)  | 100 |    100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 
3967  3 (IDLE)  |   0 |      0 |   0 |   0 |   0 |   0 |   0 |   0 |   0 |   0 
3968  4  (0,1)  | 100 |    100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 
3969  5 (IDLE)  |   0 |      0 |   0 |   0 |   0 |   0 |   0 |   0 |   0 |   0 
3970  6  (0,1)  | 100 |    100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 | 100 
3971  7 (IDLE)  |   0 |      0 |   0 |   0 |   0 |   0 |   0 |   0 |   0 |   0 
3972
3973 ----
3974
3975 This feature is also available from the Python API by providing:
3976 *CORE_MASK_SPLIT* or *CORE_MASK_PIN* to the start API.
3977
3978
3979 ==== Manual mask
3980 Sometimes for debug purposes or for a more advanced core scheduling you might want
3981 to provide a manual masking that will guide the server on which cores to use.
3982
3983 For example, let's assume we have a profile that utilize 95% of the traffic on one side,
3984 and in the other direction it provides 5% of the traffic.
3985 Let's assume also we have 8 cores assigned to the two interfaces.
3986
3987 We want to assign 3 cores to interface 0 and 1 core only to interface 1.
3988
3989 We can provide this line to the console (or for the API by providing a list of masks to the start
3990 command):
3991
3992 [source,bash]
3993 ----
3994 trex>start -f stl/syn_attack.py -m 10mpps --total -p 0 1 --core_mask 0xE 0x1
3995
3996 Removing all streams from port(s) [0, 1]:                    [SUCCESS]
3997
3998
3999 Attaching 1 streams to port(s) [0]:                          [SUCCESS]
4000
4001
4002 Attaching 1 streams to port(s) [1]:                          [SUCCESS]
4003
4004
4005 Starting traffic on port(s) [0, 1]:                          [SUCCESS]
4006
4007 37.19 [ms]
4008
4009 trex>                   
4010 ----
4011
4012 [source,python]
4013 ----
4014  c.start(ports = [port_a, port_b], mult = rate,core_mask=[0x0xe,0x1]) <1>
4015 ----       
4016 <1> mask of cores per port
4017
4018
4019
4020 The following output is received on the TUI CPU util window:
4021
4022 [source,bash]
4023 ----
4024
4025 Total Tx L2  : 5.12 Gb/sec
4026 Total Tx L1  : 6.72 Gb/sec
4027 Total Rx     : 5.12 Gb/sec
4028 Total Pps    : 10.00 Mpkt/sec
4029 Drop Rate    : 0.00 b/sec
4030 Queue Full   : 0 pkts
4031
4032 Cpu Util(%)
4033
4034   Thread   | Avg | Latest | -1  | -2  | -3  | -4  | -5  | -6  | -7  | -8 
4035
4036  0   (1)   |  45 |     45 |  45 |  45 |  45 |  45 |  46 |  45 |  46 |  45
4037  1 (IDLE)  |   0 |      0 |   0 |   0 |   0 |   0 |   0 |   0 |   0 |   0
4038  2   (0)   |  15 |     15 |  14 |  15 |  15 |  14 |  14 |  14 |  14 |  14
4039  3 (IDLE)  |   0 |      0 |   0 |   0 |   0 |   0 |   0 |   0 |   0 |   0
4040  4   (0)   |  14 |     14 |  14 |  14 |  14 |  14 |  14 |  14 |  15 |  14
4041  5 (IDLE)  |   0 |      0 |   0 |   0 |   0 |   0 |   0 |   0 |   0 |   0
4042  6   (0)   |  15 |     15 |  15 |  15 |  15 |  15 |  15 |  15 |  15 |  15
4043  7 (IDLE)  |   0 |      0 |   0 |   0 |   0 |   0 |   0 |   0 |   0 |   0
4044
4045 ----
4046
4047 === Reference
4048
4049 Additional profiles and examples are available in the `stl/hlt` folder.
4050
4051 For information about the Python client API, see the link:cp_stl_docs/index.html[Python Client API documentation].
4052
4053 === Console commands 
4054
4055 ==== Overview 
4056
4057 The console uses TRex client API to control TRex.
4058
4059 *Important information about console usage*::
4060
4061 // it seems that all of these provide background info, not guidelines for use. the use of "should" is unclear.
4062
4063 * The console does not save its own state. It caches the server state. It is assumed that there is only one console with R/W permission at any given time, so once connected as R/W console (per user/interface), it can read the server state and then cache all operations. 
4064 * Many read-only clients can exist for the same user interface. 
4065 * The console syncs with the server to get the state during connection stage, and caches the server information locally.
4066 * In case of crash or exit of the console, it will sync again at startup.
4067 * Command line parameters order is not important.
4068 * The console can display TRex stats in real time. You can open two consoles simultaneously - one for commands (R/W) and one for displaying statistics (read only).
4069
4070 ==== Ports State
4071
4072 [options="header",cols="^1,3a"]
4073 |=================
4074 | state   |    meaning
4075 | IDLE    | No streams
4076 | STREAMS | Has streams. Not transmitting (did not start transmission, or it was stopped).
4077 | WORK    | Has streams. Transmitting.
4078 | PAUSE   | Has streams. Transmission paused. 
4079 |=================
4080
4081
4082 [source,bash]
4083 ----
4084
4085   IDLE -> (add streams) -> STREAMS (start) -> WORK (stop) -> STREAMS (start) 
4086                                            |   WORK (pause) -> PAUSE (resume )---
4087                                            |                                     | 
4088                                            |                                     |
4089                                            --------------------------------------    
4090 ----
4091
4092 ==== Common Arguments 
4093
4094 Following command line arguments are common to many commands.
4095
4096 ===== Help
4097 You can specify -h or --help after each command to get full description of its purpose and arguments.
4098
4099 *Example*::
4100
4101 [source,bash]
4102 ----
4103 $streams -h
4104 ----
4105
4106 ===== Port mask 
4107
4108 Port mask enables selecting range, or set of ports.
4109
4110 *Example*::
4111
4112 [source,bash]
4113 ----
4114 $<command>   [-a] [--port 1 2 3]  [--port 0xff]  [--port clients/servers] 
4115
4116   port mask : 
4117     [-a]           : all ports 
4118     [--port 1 2 3]  : port 1,2 3
4119     [--port 0xff]   : port by mask 0x1 for port 0 0x3 for port 0 and 1
4120 ----
4121
4122 ===== Duration 
4123
4124 Duration is expressed in seconds, minutes, or hours. 
4125
4126 *Example*::
4127
4128 [source,bash]
4129 ----
4130 $<command> [-d 100] [-d 10m] [-d 1h] 
4131   
4132   duration:
4133    -d 100 : Seconds 
4134    -d 10m : Minutes
4135    -d 1h  : Hours
4136 ----
4137
4138
4139 ===== Multiplier 
4140
4141 The traffic profile defines default bandwidth for each stream. Using the multiplier command line argument, it is possible to set different bandwidth. It is possible to specify either packets or bytes per second, percentage of total port rate, or just factor to multiply the original rate by.
4142
4143 *Example*::
4144
4145 [source,bash]
4146 ----
4147 $<command> [-m 100] [-m 10gb] [-m 10kpps] [-m 40%]
4148   
4149   multiplier :
4150   
4151   -m 100    : Multiply original rate by given factor.
4152   -m 10gbps : From graph calculate the maximum rate as this bandwidth for all streams( for each port )
4153   -m 10kpps : From graph calculate the maximum rate as this pps for all streams      ( for each port )
4154   -m 40%    : From graph calculate the maximum rate as this precent from total port rate ( for each port )
4155 ----
4156 // What does it mean from graph???
4157
4158
4159 ==== Commands 
4160
4161 ===== connect 
4162
4163 Attempts to connet to the server you were connected to. Can be used in case server was restarted. Can not be used
4164 in order to connect to different server. In addition:
4165
4166 * Syncs the port info and stream info state.
4167 * Reads all counter statistics for reference.
4168
4169 // IGNORE: this line helps rendering of next line
4170
4171 *Example*::
4172
4173 [source,bash]
4174 ----
4175 $connect
4176 ----
4177
4178 ===== reset 
4179
4180 Resets the server and client to a known state. Not used in normal scenarios.
4181
4182 - Forces acquire on all ports
4183 - Stops all traffic on all ports
4184 - Removes all streams from all ports
4185
4186
4187 *Example*::
4188
4189 [source,bash]
4190 ----
4191 $reset  
4192 ----
4193
4194 ===== portattr
4195
4196 Configures port attributes.
4197
4198 *Example*::
4199
4200 [source,python]
4201 ----
4202 $portattr --help
4203 usage: port_attr [-h] [--port PORTS [PORTS ...] | -a] [--prom {on,off}]
4204                  [--link {up,down}] [--led {on,off}] [--fc {none,tx,rx,full}]
4205                  [--supp]
4206
4207 Sets port attributes
4208
4209 optional arguments:
4210   -h, --help            show this help message and exit
4211   --port PORTS [PORTS ...], -p PORTS [PORTS ...]
4212                         A list of ports on which to apply the command
4213   -a                    Set this flag to apply the command on all available
4214                         ports
4215   --prom {on,off}       Set port promiscuous on/off
4216   --link {up,down}      Set link status up/down
4217   --led {on,off}        Set LED status on/off
4218   --fc {none,tx,rx,full}
4219                         Set Flow Control type
4220   --supp                Show which attributes are supported by current NICs
4221 ----
4222
4223 image::images/console_link_down.png[title="Setting link down on port 0 affects port 1 at loopback"]
4224
4225
4226 ===== clear 
4227
4228 Clears all port stats counters.
4229
4230 *Example*::
4231
4232 [source,bash]
4233 ----
4234 $clear -a
4235 ----
4236
4237
4238 ===== stats 
4239
4240 Can be used to show global/port/stream statistics. +
4241 Also, can be used to retrieve extended stats from port (xstats)
4242
4243 *Example*::
4244
4245 [source,bash]
4246 ----
4247 $stats --port 0 -p
4248 $stats -s
4249 ----
4250
4251 *Xstats error example*::
4252
4253 [source,bash]
4254 ----
4255
4256 trex>stats -x --port 0 2
4257 Xstats:
4258
4259             Name:              |     Port 0:     |     Port 2:
4260 \------------------------------------------------------------------
4261 rx_good_packets                |       154612905 |       153744994
4262 tx_good_packets                |       154612819 |       153745136
4263 rx_good_bytes                  |      9895225920 |      9839679168
4264 tx_good_bytes                  |      9276768500 |      9224707392
4265 rx_unicast_packets             |       154611873 |       153743952
4266 rx_unknown_protocol_packets    |       154611896 |       153743991
4267 tx_unicast_packets             |       154612229 |       153744562
4268 mac_remote_errors              |               1 |               0 #<1>
4269 rx_size_64_packets             |       154612170 |       153744295
4270 tx_size_64_packets             |       154612595 |       153744902
4271
4272 ----
4273
4274 <1> Error that can be seen only with this command
4275
4276 // IGNORE - this line helps rendering
4277
4278 ===== streams
4279
4280 Shows info about configured streams on each port, from the client cache. 
4281
4282 *Example*::
4283   
4284 [source,bash]
4285 ----
4286 $streams 
4287
4288 Port 0:
4289
4290     ID     |     packet type     |  length  |       mode       |      rate       | next stream
4291
4292     1      | Ethernet:IP:UDP:Raw |       64 |    continuous    |           1 pps |      -1
4293     2      | Ethernet:IP:UDP:Raw |       64 |    continuous    |       1.00 Kpps |      -1
4294
4295 Port 1:
4296
4297     ID     |     packet type     |  length  |       mode       |      rate       | next stream
4298
4299     1      | Ethernet:IP:UDP:Raw |       64 |    continuous    |           1 pps |      -1
4300     2      | Ethernet:IP:UDP:Raw |       64 |    continuous    |       1.00 Kpps |      -1
4301
4302 ----
4303
4304
4305 *Example*::
4306
4307 Use this command to show only ports 1 and 2. 
4308
4309 [source,bash]
4310 ----
4311 $streams --port 1 2 
4312
4313  ..
4314  ..
4315 ----
4316
4317 *Example*::
4318
4319 Use this command to show full information for stream 0 and port 0, output in JSON format.
4320
4321 [source,bash]
4322 ----
4323 $streams --port 0 --streams 0
4324
4325 ----
4326         
4327
4328 ===== start 
4329
4330 Start transmitting traffic on set of ports
4331
4332 * Removes all streams
4333 * Loads new streams
4334 * Starts traffic (can set multiplier, duration and other parameters)
4335 * Acts only on ports in "stopped: mode. If `--force` is specified, port(s) are first stopped.
4336 * Note: If any ports are not in "stopped" mode, and `--force` is not used the command fails.
4337
4338 // IGNORE: this line helps rendering of next line
4339
4340 *Example*::
4341
4342 Use this command to start a profile on all ports, with a maximum bandwidth of 10 GB.
4343
4344 [source,bash]
4345 ----
4346 $start -a -f stl/imix.py  -m 10gb
4347 ----
4348
4349 *Example*::
4350
4351 Use this command to start a profile on ports 1 and 2, and multiply the bandwidth specified in the traffic profile by 100.
4352    
4353 [source,bash]
4354 ----
4355 $start -port 1 2 -f stl/imix.py  -m 100
4356 ----
4357
4358
4359 ===== stop
4360
4361 * Operates on a set of ports 
4362 * Changes the mode of the port(s) to "stopped"
4363 * Does not remove streams
4364
4365 // IGNORE: this line helps rendering of next line
4366
4367 *Example*::
4368
4369 Use this command to stop the specified ports.
4370
4371 [source,bash]
4372 ----
4373 $stop --port 0
4374
4375 ----
4376
4377
4378 ===== pause 
4379
4380 * Operates on a set of ports 
4381 * Changes a working set of ports to "pause" (no traffic transmission) state.
4382
4383 *Example*::
4384
4385 [source,bash]
4386 ----
4387 $pause --port 0
4388
4389 ----
4390
4391
4392 ===== resume 
4393
4394 * Operates on a set of ports 
4395 * Changes a working set of port(s) to "resume" state (transmitting traffic again).
4396 * All ports should be in "paused" status. If any of the ports is not paused, the command fails.
4397
4398 // IGNORE: this line helps rendering of next line
4399
4400 *Example*::
4401
4402 [source,bash]
4403 ----
4404 $resume --port 0
4405
4406 ----
4407
4408
4409 ===== update 
4410
4411 Update the bandwidth multiplier for a set of ports.
4412
4413 * All ports must be in "work" state. If any ports are not in "work" state, the command fails
4414
4415 // IGNORE: this line helps rendering of next line
4416
4417 *Example*::
4418
4419 Multiplly traffic on all ports by a factor of 5.
4420
4421 [source,bash]
4422 ----
4423 >update -a -m 5
4424 ----
4425
4426
4427 [NOTE]
4428 =====================================
4429  We might add in the future the ability to disable/enable specific stream, load a new stream dynamically, and so on.
4430 =====================================
4431
4432 // clarify note above
4433
4434 ===== TUI
4435
4436 The textual user interface (TUI) displays constantly updated TRex statistics in a textual window.
4437
4438 *Example*::
4439         
4440 [source,bash]
4441 ----
4442 $tui
4443 ----
4444
4445 Enters a Stats mode and displays three types of TRex statistics:
4446 * Global/port stats/version/connected etc 
4447 * Per port
4448 * Per port stream 
4449
4450
4451 The followig keyboard commands operate in the TUI window: +
4452  q - Quit the TUI window (get back to console) +
4453  c - Clear all counters +
4454  d, s, l - change display between dashboard (d), streams (s) and l (latency) info. +
4455
4456 === Benchmarks of 40G NICs
4457
4458 link:trex_stateless_bench.html[TRex stateless benchmarks]
4459
4460 === Appendix
4461
4462 ==== Scapy packet examples
4463
4464 [source,python]
4465 ----
4466
4467 # UDP header 
4468 Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)
4469
4470 # UDP over one vlan
4471 Ether()/Dot1Q(vlan=12)/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)
4472
4473 # UDP QinQ
4474 Ether()/Dot1Q(vlan=12)/Dot1Q(vlan=12)/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)
4475
4476 #TCP over IP over VLAN
4477 Ether()/Dot1Q(vlan=12)/IP(src="16.0.0.1",dst="48.0.0.1")/TCP(dport=12,sport=1025)
4478
4479 # IPv6 over vlan
4480 Ether()/Dot1Q(vlan=12)/IPv6(src="::5")/TCP(dport=12,sport=1025)
4481
4482 #Ipv6 over UDP over IP 
4483 Ether()/IP()/UDP()/IPv6(src="::5")/TCP(dport=12,sport=1025)
4484
4485 #DNS packet
4486 Ether()/IP()/UDP()/DNS()
4487
4488 #HTTP packet 
4489 Ether()/IP()/TCP()/"GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n"
4490 ----
4491
4492
4493 ==== HLT supported Arguments anchor:altapi-support[]
4494
4495 include::build/hlt_args.asciidoc[]
4496
4497 ==== FD.IO open source project using TRex 
4498
4499 link:https://gerrit.fd.io/r/gitweb?p=csit.git;a=tree;f=resources/tools/t-rex[here]
4500
4501
4502 ==== Using Stateless client via JSON-RPC
4503
4504 For functions that do not require complex objects and can use JSON-serializable input/output, you can use Stateless API via JSON-RPC proxy server. +
4505 Thus, you can use Stateless TRex *from any language* supporting JSON-RPC.
4506
4507 ===== How to run TRex side:
4508
4509 * Run the Stateless TRex server in one of 2 ways:
4510
4511 ** Either run TRex directly in shell:
4512 +
4513 [source,bash]
4514 ----
4515 sudo ./t-rex-64 -i
4516 ----
4517
4518 ** Or run it via JSON-RPC command to trex_daemon_server:
4519 +
4520 [source,python]
4521 ----
4522 start_trex(trex_cmd_options, user, block_to_success = True, timeout = 40, stateless = True)
4523 ----
4524
4525 * Run the RPC "proxy" to stateless, here are also 2 ways:
4526
4527 ** run directly:
4528 +
4529 [source,bash]
4530 ----
4531 cd automation/trex_control_plane/stl/examples
4532 python rpc_proxy_server.py
4533 ----
4534
4535 ** Send JSON-RPC command to master_daemon:
4536 +
4537 [source,python]
4538 ----
4539 if not master_daemon.is_stl_rpc_proxy_running():
4540     master_daemon.start_stl_rpc_proxy()
4541 ----
4542
4543 Done :)
4544
4545 Now you can send requests to the rpc_proxy_server and get results as array of 2 values:
4546
4547 * If fail, result will be: [False, <traceback log with error>]
4548 * If success, result will be: [True, <return value of called function>]
4549
4550 In same directory of rpc_proxy_server.py, there is python example of usage: using_rpc_proxy.py
4551
4552 ===== Native Stateless API functions:
4553
4554 * acquire
4555 * connect
4556 * disconnect
4557 * get_stats
4558 * get_warnings
4559 * push_remote
4560 * reset
4561 * wait_on_traffic
4562
4563 ...can be called directly as server.push_remote(\'udp_traffic.pcap'). +
4564 If you need any other function of stateless client, you can either add it to rpc_proxy_server.py, or use this method: +
4565 server.*native_method*(<string of function name>, <args of the function>) +
4566
4567 ===== HLTAPI Methods can be called here as well:
4568
4569 * connect
4570 * cleanup_session
4571 * interface_config
4572 * traffic_config
4573 * traffic_control
4574 * traffic_stats
4575
4576 [NOTE]
4577 =====================================================================
4578 In case of names collision with native functions (such as connect), for HLTAPI, function will change to have "hlt_" prefix.
4579 =====================================================================
4580
4581 ===== Example of running from Java:
4582
4583 [source,java]
4584 ----
4585 package com.cisco.trex_example;
4586
4587 import java.net.URL;
4588 import java.util.ArrayList;
4589 import java.util.Arrays;
4590 import java.util.Map;
4591 import java.util.HashMap;
4592
4593 import com.googlecode.jsonrpc4j.JsonRpcHttpClient;
4594
4595 public class TrexMain {
4596
4597     @SuppressWarnings("rawtypes")
4598     public static Object verify(ArrayList response) {
4599         if ((boolean) response.get(0)) {
4600             return response.get(1);
4601         }
4602         System.out.println("Error: " + response.get(1));
4603         System.exit(1);
4604         return null;
4605     }
4606
4607     @SuppressWarnings("rawtypes")
4608     public static void main(String[] args) throws Throwable {
4609         try {
4610             String trex_host = "csi-trex-11";
4611             int rpc_proxy_port = 8095;
4612             Map<String, Object> kwargs = new HashMap<>();
4613             ArrayList<Integer> ports = new ArrayList<Integer>();
4614             HashMap res_dict = new HashMap<>();
4615             ArrayList res_list = new ArrayList();
4616             JsonRpcHttpClient rpcConnection = new JsonRpcHttpClient(new URL("http://" + trex_host + ":" + rpc_proxy_port));
4617
4618             System.out.println("Initializing Native Client");
4619             kwargs.put("server", trex_host);
4620             kwargs.put("force", true);
4621             verify(rpcConnection.invoke("native_proxy_init", kwargs, ArrayList.class));
4622             kwargs.clear();
4623
4624             System.out.println("Connecting to TRex server");
4625             verify(rpcConnection.invoke("connect", kwargs, ArrayList.class));
4626             
4627             System.out.println("Resetting all ports");
4628             verify(rpcConnection.invoke("reset", kwargs, ArrayList.class));
4629
4630             System.out.println("Getting ports info");
4631             kwargs.put("func_name", "get_port_info"); // some "custom" function
4632             res_list = (ArrayList) verify(rpcConnection.invoke("native_method", kwargs, ArrayList.class));
4633             System.out.println("Ports info is: " + Arrays.toString(res_list.toArray()));
4634             kwargs.clear();
4635             for (int i = 0; i < res_list.size(); i++) {
4636                     Map port = (Map) res_list.get(i);
4637                     ports.add((int)port.get("index"));
4638                     }
4639
4640             System.out.println("Sending pcap to ports: " + Arrays.toString(ports.toArray()));
4641             kwargs.put("pcap_filename", "stl/sample.pcap");
4642             verify(rpcConnection.invoke("push_remote", kwargs, ArrayList.class));
4643             kwargs.clear();
4644             verify(rpcConnection.invoke("wait_on_traffic", kwargs, ArrayList.class));
4645
4646             System.out.println("Getting stats");
4647             res_dict = (HashMap) verify(rpcConnection.invoke("get_stats", kwargs, ArrayList.class));
4648             System.out.println("Stats: " + res_dict.toString());
4649
4650             System.out.println("Deleting Native Client instance");
4651             verify(rpcConnection.invoke("native_proxy_del", kwargs, ArrayList.class));
4652
4653         } catch (Throwable e) {
4654             e.printStackTrace();
4655         }
4656     }
4657 }
4658
4659 ----
4660
4661
4662