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