Version | name | meaning |
---|---|---|
1.00 |
Itay Marom (imarom) |
|
1.01 |
Dan Klein (danklei) |
|
1.1 |
Dan Klein (danklei) |
|
TRex implements a RPC protocol in order to config, view and in general execute remote calls on TRex
In this document we will provide information on how a client can implement the protocol used to communicate with TRex
In general, we will describe the following:
-
Transport Layer - The transport layer used to communicate with TRex server
-
RPC Reprensentation Protocol - The format in which remote procedures are carried
TRex server transport layer is implemented using ZMQ.
The default configuration is TCP on port 5555, however this is configurable.
The communication model is based on the request-reply ZMQ model:
for more on ZMQ and implementation please refer to:
http://zeromq.org/intro:read-the-manual
The RPC reprensentation protocol is JSON RPC v2.0. Every request and response will be encoded in a JSON RPC v2.0 format.
For more info on JSON RPC v2.0 spec please refer to:
Later on in the document we will describe all the supported commands.
Before we get into the commands, it’s worth mentioning that TRex has a mock RPC server designed to allow playing around with the server in order to understand the response and perform adjustments to the request.
TRex also provides a Python based console that can connect to the server (mock or real) and send various commands to the server.
Building the mock server is performed like this:
trex-core/linux> ./b configure
trex-core/linux> ./b --target=mock-rpc-server-64-debug
Launching the mock server is performed like this:
trex-core/scripts> ./mock-rpc-server-64-debug
-= Starting RPC Server Mock =-
Listening on tcp://localhost:5050 [ZMQ]
Setting Server To Full Verbose
Server Started
When the mock server is up, you can already send commands to the server.
Let’s demonstrate the operation with the Python based TRex console:
trex-core/scripts> ./trex-console
Connecting To RPC Server On tcp://localhost:5050
[SUCCESS]
-=TRex Console V1.0=-
Type 'help' or '?' for supported actions
TRex >
As we will see later on, a basic RPC command supported by the server is ping.
Let’s issue a ping command to the server and see what happens on both sides:
On the client side:
TRex > verbose on
verbose set to on
TRex > ping
-> Pinging RPC server
[verbose] Sending Request To Server:
{
"id": "l0tog11a",
"jsonrpc": "2.0",
"method": "ping",
"params": null
}
[verbose] Server Response:
{
"id": "l0tog11a",
"jsonrpc": "2.0",
"result": "ACK"
}
[SUCCESS]
On the server side:
trex-core/scripts> ./mock-rpc-server-64-debug
-= Starting RPC Server Mock =-
Listening on tcp://localhost:5050 [ZMQ]
Setting Server To Full Verbose
Server Started
[verbose][req resp] Server Received:
{
"id" : "maa5a3g1",
"jsonrpc" : "2.0",
"method" : "ping",
"params" : null
}
[verbose][req resp] Server Replied:
{
"id" : "maa5a3g1",
"jsonrpc" : "2.0",
"result" : "ACK"
}
Any port on the server can be in numbered of states, each state provides other subset of the commands that are allowed to be executed.
We define the following possible states:
-
unowned - The specific port is either unowned or another user is owning the port
-
owned - The specific port has been acquired by the client
-
active - The specific port is in the middle of injecting traffic - currently active
Each port command will specify on which states it is possible to execute it.
For port related commands valid only on owned or active, a field called 'handler' MUST be passed along with the rest of the parameters.
This will identify the connection:
The following RPC commands are supported
-
Name - ping
-
Valid States - not relevant
-
Description - Pings the TRex server
-
Paramters - None
-
Result [string] - "ACK" On Sucess
Example:
'Request':
{
"jsonrpc": "2.0",
"id": 1,
"method": "ping",
"params": null
}
'Response':
{
"jsonrpc" : "2.0",
"id" : 1,
"result" : "ACK"
}
-
Name - get_supported_cmds
-
Valid States - not relevant
-
Description - Queries the server for all the supported commands
-
Paramters - None
-
Result [array] - A list of all the supported commands by the server
Example:
'Request':
{
"jsonrpc": "2.0",
"id": 1,
"method": "get_supported_cmds",
"params": null
}
'Response':
{
"jsonrpc": "2.0",
"id": 1,
"result": [
"remove_all_streams",
"remove_stream",
"add_stream",
"get_reg_cmds",
"ping",
"test_sub",
"get_version",
"test_add"
]
}
-
Name - get_version
-
Valid States - not relevant
-
Description - Queries the server for version information
-
Paramters - None
-
Result [object] - See table below
Field | Type | Description |
---|---|---|
version |
string |
TRex version |
build_date |
string |
build date |
build_time |
string |
build time |
built_by |
string |
who built this version |
'Request':
{
"id": "wapkk8m6",
"jsonrpc": "2.0",
"method": "get_version",
"params": null
}
'Response':
{
"id": "wapkk8m6",
"jsonrpc": "2.0",
"result": {
"build_date": "Sep 16 2015",
"build_time": "12:33:01",
"built_by": "imarom",
"version": "v0.0"
}
}
-
Name - get_system_info
-
Description - Queries the server for system properties
-
Paramters - None
-
Result [object] - See table below
Field | Type | Description |
---|---|---|
dp_core_count |
int |
DP core count |
core_type |
string |
DP core type |
hostname |
string |
machine host name |
uptime |
string |
uptime of the server |
port_count |
int |
number of ports on the machine |
ports |
array |
arary of object 'port' - see below |
Field | Type | Description |
---|---|---|
driver |
string |
driver type |
speed |
string |
speed of the port (1g, 10g, 40g, 100g) |
status |
string |
down, idle or transmitting |
'Request':
{
"id": "zweuldlh",
"jsonrpc": "2.0",
"method": "get_system_info",
"params": null
}
'Response':
{
"id": "zweuldlh",
"jsonrpc": "2.0",
"result": {
"core_type": "Intel(R) Xeon(R) CPU E5-2650 0 @ 2.00GHz",
"dp_core_count": 1,
"hostname": "csi-kiwi-03.cisco.com",
"port_count": 4,
"ports": [
{
"driver": "E1000",
"index": 0,
"speed": "1g",
"status": "down"
},
{
"driver": "E1000",
"index": 1,
"speed": "1g",
"status": "down"
},
{
"driver": "E1000",
"index": 2,
"speed": "1g",
"status": "down"
},
{
"driver": "E1000",
"index": 3,
"speed": "1g",
"status": "down"
}
]
}
}
-
Name - get_owner
-
Valid States - all
-
Description - Queries the server for a specific port current owner
-
Paramters -
-
port_id [int] - port id to query for owner
-
-
Result [string] - owner name if exists, otherwise none
'Request':
{
"id": "hxjkuwj9",
"jsonrpc": "2.0",
"method": "get_owner",
"params": {
"port_id": 1
}
}
'Response':
{
"id": "hxjkuwj9",
"jsonrpc": "2.0",
"result": {
"owner": "itay"
}
}
-
Name - Acquire
-
Valid States - all
-
Description - Takes ownership over the port
-
Paramters -
-
port_id [int] - port id to take ownership
-
user [string] - User name aquiring the system
-
force [boolean] - force action even if another user is holding the port
-
-
Result [string] - unique connection handler for future requests for that port
'Request':
{
"id": "b1tr56yz",
"jsonrpc": "2.0",
"method": "Acquire",
"params": {
"user": "itay"
"port_id": 1
"force": false,
}
}
'Response':
{
"id": "b1tr56yz",
"jsonrpc": "2.0",
"result": "4cBWDxS2"
}
-
Name - release
-
Valid States - owned
-
Description - Release owernship over the device
-
Paramters -
-
handler [string] - unique connection handler
-
port_id [int] - port id to release
-
-
Result [string] - "ACK" on success
'Request':
{
"id": "m785dxwd",
"jsonrpc": "2.0",
"method": "release",
"params": {
"handler": "37JncCHr"
"port_id": 1
}
}
'Response':
{
"id": "m785dxwd",
"jsonrpc": "2.0",
"result": "ACK"
}
-
Name - add_stream
-
Valid States - owned
-
Description - Adds a stream to a port
-
Paramters
-
handler [string] - unique connection handler
-
port_id [int] - port id associated with this stream
-
stream_id [int] - stream id associated with the stream object
-
stream - object of type stream
-
-
Result [string] - "ACK" in case of success
Add_stream gets a single parameter of type object.
The format of that object is as follows:
Field | Type | Description |
---|---|---|
enabled |
boolean |
is this stream enabled |
self_start |
boolean |
is this stream triggered by starting injection or triggered by another stream |
isg |
double |
[usec] inter stream gap - delay time in usec until the stream is started |
next_stream_id |
int |
next stream to start after this stream. -1 means stop after this stream |
packet |
object |
object of type packet |
mode |
object |
object of type mode |
vm |
array |
array of objects of type vm |
rx_stats |
object |
object of type rx_stats |
packet contains binary and meta data
Field | Type | Description |
---|---|---|
binary |
byte array |
binary dump of the packet to be used in the stream as array of bytes |
meta |
string |
meta data object. opaque to the RPC server. will be passed on queries |
mode object can be one of the following objects:
Field | Type | Description |
---|---|---|
type |
string |
'continuous' |
pps |
double |
rate in packets per second |
Field | Type | Description |
---|---|---|
type |
string |
'single_burst' |
pps |
double |
rate in packets per second |
total pkts |
int |
total packets in the burst |
Field | Type | Description |
---|---|---|
type |
string |
'multi_burst' |
pps |
int |
rate in packets per second |
pkts_per_burst |
int |
packets in a single burst |
ibg |
double |
[usec] inter burst gap. delay between bursts in usec |
count |
int |
number of bursts. '0' means loop forever, '1' will fall back to single burst |
Array of VM instruction objects to be used with this stream
Any element in the array can be one of the following object types:
Field | Type | Description |
---|---|---|
type |
string |
'fix_checksum_ipv4' |
pkt_offset |
uint16 |
offset of the field to fix |
Field | Type | Description |
---|---|---|
type |
string |
'flow_var'' |
name |
string |
flow var name - this should be a unique identifier |
size |
[1,2,4,8] |
size of the flow var in bytes |
op |
[inc, dec, random] |
operation type to perform on the field |
init value |
uint64_t as string |
init value for the field |
min value |
uint64_t as string |
minimum value for the field |
max value |
uint64_t as string |
maximum value for the field |
Field | Type | Description |
---|---|---|
type |
string |
'write_flow_var' |
name |
string |
flow var name to write |
pkt_offset |
uint16 |
offset at the packet to perform the write |
add_value |
int |
delta to add to the field prior to writing - can be negative |
is_big_endian |
boolean |
should write as big endian or little |
Tip
|
For more information and examples on VM objects please refer to: VM examples |
-
performance - this will have performance impact as rx packets will be examined
-
override - up to 10 bytes at the end of the packet will be overidden by the meta data required
-
stream_id consumes 2 bytes
-
seq_enabled consumes 4 bytes
-
latency_enabled consumes 4 bytes
so if no seq or latency are enabled 2 bytes will be used.
if seq or latency alone are enabled, 6 bytes will be used.
if both are enabled then 10 bytes will be used.
Field | Type | Description |
---|---|---|
enabled |
boolean |
is rx_stats enabled for this stream |
stream_id |
int |
stream_id for which to collect rx_stats. |
seq_enabled |
boolean |
should write 32 bit sequence |
latency_enabled |
boolean |
should write 32 bit latency |
'Request':
{
"id": 1,
"jsonrpc": "2.0",
"method": "add_stream",
"params": {
"handler": "37JncCHr",
"port_id": 1,
"stream_id": 502
"stream": {
"enabled": true,
"isg": 4.3,
"mode": {
"pps": 3,
"total_pkts": 5000,
"type": "single_burst"
},
"next_stream_id": -1,
"packet": {
"binary": [
4,
1,
255
],
"meta": ""
},
"rx_stats": {
"enabled": false
},
"self_start": true,
}
}
}
'Response':
{
"id": 1,
"jsonrpc": "2.0",
"result": "ACK"
}
This request-reply sequence demonstrate a method in which rx_stats are diabled. In case rx_stats feature is enabled, rx_object must include all rx_stats object fields as described above.
-
Name - remove_stream
-
Valid States - owned
-
Description - Removes a stream from a port
-
Paramters
-
handler [string] - unique connection handler
-
port_id [int] - port assosicated with the stream.
-
stream_id [int] - stream to remove
-
-
Result [string] - "ACK" in case of success
'Request':
{
"id": 1
"jsonrpc": "2.0",
"method": "remove_stream",
"params": {
"handler": "37JncCHr",
"port_id": 1,
"stream_id": 502
}
}
'Response':
{
"id": 1
"jsonrpc": "2.0",
"result": "ACK"
}
-
Name - get_stream_list
-
Valid States - owned, active
-
Description - fetch all the assoicated streams for a port
-
Paramters
-
handler [string] - unique connection handler
-
port_id [int] - port to query for registered streams
-
-
Result [array] - array of stream_id
'Request':
{
"id": 1,
"jsonrpc": "2.0",
"method": "get_stream_list",
"params": {
"handler": "37JncCHr",
"port_id": 1
}
}
'Response':
{
"id": 1,
"jsonrpc": "2.0",
"result": [
502,
18
]
}
-
Name - get_stream
-
Valid States - owned, active
-
Description - get a specific stream object
-
Paramters
-
handler [string] - unique connection handler
-
port_id [int] - port for the associated stream
-
stream_id [int] - the requested stream id
-
-
Result [object] - object stream
'Request':
{
"id": 1,
"jsonrpc": "2.0",
"method": "get_stream",
"params": {
"handler": "37JncCHr",
"port_id": 1,
"stream_id": 7
}
}
'Response':
{
"id": 1,
"jsonrpc": "2.0",
"result": {
"stream": {
"enabled": true,
"isg": 4.3,
"mode": {
"pps": 3,
"type": "continuous"
},
"next_stream_id": -1,
"packet": {
"binary": [
4,
1,
255
],
"meta": ""
},
"self_start": true
}
}
}
-
Name - remove_all_streams
-
Valid States - owned
-
Description - remove all streams from a port
-
Paramters
-
handler [string] - unique connection handler
-
port_id [int] - port for the associated stream
-
-
Result [string] - "ACK" on success
'Request':
{
"id": 1,
"jsonrpc": "2.0",
"method": "remove_all_streams",
"params": {
"handler": "37JncCHr",
"port_id": 2
}
}
'Response':
{
"id": 1,
"jsonrpc": "2.0",
"result": "ACK"
}
-
Name - start_traffic
-
Valid States - owned
-
Description - Starts the traffic on a specific port. if traffic has already started an error will be returned
-
Paramters
-
handler [string] - unique connection handler
-
port_id [int] - port id on which to start traffic
-
-
Result [string] - "ACK" on success
'Request':
{
"id": "b3llt8hs",
"jsonrpc": "2.0",
"method": "start_traffic",
"params": {
"handler": "37JncCHr",
"port_id": 3
}
'Response':
{
"id": "b3llt8hs",
"jsonrpc": "2.0",
"result": "ACK"
}
-
Name - stop_traffic
-
Valid States - active
-
Description - Stops the traffic on a specific port. if the port has already started nothing will happen
-
Paramters
-
handler [string] - unique connection handler
-
port_id [int] - port id on which to stop traffic
-
-
Result [string] - "ACK" on success
'Request':
{
"id": "h2fyhni7",
"jsonrpc": "2.0",
"method": "stop_traffic",
"params": {
"handler": "37JncCHr",
"port_id": 3
}
}
'Response':
{
"id": "h2fyhni7",
"jsonrpc": "2.0",
"result": "ACK"
}
-
Name - get_global_stats
-
Valid States - owned, active
-
Description - Get machine global stats
-
Paramters - None
-
Result [object] - See Below
Field | Type | Description |
---|---|---|
state |
string |
server state: can be unowned, owned or active |
cpu_util |
double |
DP CPU util. in % |
tx_bps |
double |
total TX bits per second |
rx_bps |
double |
total RX bits per second |
tx_pps |
double |
total TX packets per second |
rx_pps |
double |
total RX packets per second |
total_tx_pkts |
int |
total TX packets |
total_rx_pkts |
int |
total RX packets |
total_tx_bytes |
int |
total TX bytes |
total_rx_bytes |
int |
total RX bytes |
tx_rx_error |
int |
total Tx/Rx errors |
-
Name - get_port_stats
-
Valid States - owned, active
-
Description - Get port stats
-
Paramters
-
port_id [int] - The port id for query
-
-
Result [object] - See Below
Field | Type | Description |
---|---|---|
status |
string |
down, idle or transmitting |
tx_bps |
double |
total TX bits per second |
rx_bps |
double |
total RX bits per second |
tx_pps |
double |
total TX packets per second |
rx_pps |
double |
total RX packets per second |
total_tx_pkts |
int |
total TX packets |
total_rx_pkts |
int |
total RX packets |
total_rx_bytes |
int |
total TX bytes |
total_tx_bytes |
int |
total RX bytes |
tx_rx_error |
int |
total Tx/Rx errors |
-
Name - get_steram_stats
-
Valid States - owned, active
-
Description - Get port stats
-
Paramters
-
port_id [int] - The port id for query
-
stream_id [int] - The stream id for query
-
-
Result [object] - See Below
Field | Type | Description |
---|---|---|
tx_bps |
double |
total TX bits per second |
tx_pps |
double |
total TX packets per second |
total_tx_pkts |
int |
total TX packets |
total_tx_bytes |
int |
total TX bytes |
rx_bps |
double |
total RX bits per second (if rx_stats enabled) |
rx_pps |
double |
total RX packets per second (if rx_stats enabled) |
total_rx_pkts |
int |
total RX packets (if rx_stats enabled) |
total_rx_bytes |
int |
total RX bytes (if rx_stats enabled) |
latency |
array |
array of 2 ordered elements average, maximum (if rx_stats enabled) |
the following examples represents common scenarios. commands in […] represents meta commands and not real RPC commands such as repeat, wait and etc.
This sequence represents a client implementing the protocol taking ownership over the server and preparing to perform work
-
ping - Ping the server to verify the server is up
-
get_owner - if owner is not me or none prompt to the user if he wants to force it
-
acquire - Ask or force for exclusive control over the server. save the handler given for future commands
-
get_version - Verify the server is compatible with the GUI
-
get_system_info - Get the installed ports and cores
-
get_stream_list - for every port, get the list and sync the GUI
-
get_stream - for every stream in a port list, get the stream info and sync the GUI
describes a simple scenario where a user wants to add or edit one or more streams to one or more ports
-
[init] - perform the init procedure from above
-
[GUI add/edit streams] - GUI provides the user a way to add or edit streams and sync them
-
remove_all_streams [optional] - remove all previous streams to start from scratch
-
add_stream - configure a specific port with a stream.
-
[repeat previous] - repeat the above for how many ports and streams desired
-
get_stream_list [optional] - sanity - verify the server is synced with the GUI
-
start_traffic - start traffic on the specific port / all the ports
-
get_global_stats [optional] - make sure the machine is transmiting traffic
-
[perfrom test] - perform the required test
-
stop_traffic - when done, stop the traffic on the specific port / all the ports
-
get_global_stats [optional] - make sure the machine has stopped
Describes the log off from the machine
The following examples represents common scenarios implemented by a higher layer, which uses the API described above.
The examples are written in Python, however similar examples can be shown in any programming language.
CTRexPktBuilder
is a Python module designed to provide a progammer API for dynamic packet building.
Since the packet is built to be used by TRex, a CTRexVM
subclass has been created to describe how TRex should use the described packet in its transmission.
While the entire CTRexPktBuilder
class (which is initialized by specifying the total length of the packet) responsible to both building the packet layer by layer, the CTRexVM
class is responsible for controlling the ranging of the values as desribed in the VM objects section, and other attributes being used by TRex data-plane once the server receives its streams.
The following conde snippet describes how an ICMP Echo packet is built.
from packet_builder import CTRexPktBuilder
import dpkt
pkt_bld = CTRexPktBuilder() # (1)
pkt_bld.add_pkt_layer("l2", dpkt.ethernet.Ethernet())
# set Ethernet layer attributes
pkt_bld.set_eth_layer_addr("l2", "src", "00:15:17:a7:75:a3")
pkt_bld.set_eth_layer_addr("l2", "dst", "e0:5f:b9:69:e9:22")
pkt_bld.set_layer_attr("l2", "type", dpkt.ethernet.ETH_TYPE_IP)
# set IP layer attributes
pkt_bld.add_pkt_layer("l3_ip", dpkt.ip.IP())
pkt_bld.set_ip_layer_addr("l3_ip", "src", "21.0.0.2")
pkt_bld.set_ip_layer_addr("l3_ip", "dst", "22.0.0.12")
pkt_bld.set_layer_attr("l3_ip", "p", dpkt.ip.IP_PROTO_ICMP)
# set ICMP layer attributes
pkt_bld.add_pkt_layer("icmp", dpkt.icmp.ICMP())
pkt_bld.set_layer_attr("icmp", "type", dpkt.icmp.ICMP_ECHO)
# set Echo(ICMP) layer attributes
pkt_bld.add_pkt_layer("icmp_echo", dpkt.icmp.ICMP.Echo())
pkt_bld.set_layer_attr("icmp_echo", "id", 24528)
pkt_bld.set_layer_attr("icmp_echo", "seq", 11482)
pkt_bld.set_pkt_payload('hello world')
# finally, set IP header len with relation to payload data
pkt_bld.set_layer_attr("l3_ip", "len", len(pkt_bld.get_layer('l3_ip')))
-
Initialize the packet builder instance.
This example created a packet without any ranging to it, so in this case TRex is expected to reply the same packet over and over without any changes to it.
When adding sending this packet as part of the Add Stream command, the packet content specified under packet
would look for the created ICMP packet like this:
>>> print pkt_bld.dump_pkt()
[224, 95, 185, 105, 233, 34, 0, 21, 23, 167, 117, 163, 8, 0, 69, 0, 0, 39,
0, 0, 0, 0, 64, 1, 79, 201, 21, 0, 0, 2, 22, 0, 0, 12, 8, 0, 217, 134, 95,
208, 44, 218, 104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]
Each of the array items representing a byte data-representation, hence ranging from 0 to 255.
The following example creates an HTTP GET packet, hence layering Ethernet/IP/TCP/HTTP.
from packet_builder import CTRexPktBuilder
import dpkt
pkt_bld = CTRexPktBuilder()
pkt_bld.add_pkt_layer("l2", dpkt.ethernet.Ethernet())
# set Ethernet layer attributes
pkt_bld.set_eth_layer_addr("l2", "src", "00:15:17:a7:75:a3")
pkt_bld.set_eth_layer_addr("l2", "dst", "e0:5f:b9:69:e9:22")
pkt_bld.set_layer_attr("l2", "type", dpkt.ethernet.ETH_TYPE_IP)
# set IP layer attributes
pkt_bld.add_pkt_layer("l3_ip", dpkt.ip.IP())
pkt_bld.set_ip_layer_addr("l3_ip", "src", "21.0.0.2")
pkt_bld.set_ip_layer_addr("l3_ip", "dst", "22.0.0.12")
pkt_bld.set_layer_attr("l3_ip", "p", dpkt.ip.IP_PROTO_TCP)
# set TCP layer attributes
pkt_bld.add_pkt_layer("l4_tcp", dpkt.tcp.TCP())
pkt_bld.set_layer_attr("l4_tcp", "sport", 13311)
pkt_bld.set_layer_attr("l4_tcp", "dport", 80)
pkt_bld.set_layer_attr("l4_tcp", "flags", 0)
pkt_bld.set_layer_attr("l4_tcp", "win", 32768)
pkt_bld.set_layer_attr("l4_tcp", "seq", 0)
# set packet payload, for example HTTP GET request
pkt_bld.set_pkt_payload('GET /10k_60k HTTP/1.1\r\nHost: 22.0.0.3\r\nConnection: Keep-Alive\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)\r\nAccept: */*\r\nAccept-Language: en-us\r\nAccept-Encoding: gzip, deflate, compress\r\n\r\n')
# finally, set IP header len with relation to payload data
pkt_bld.set_layer_attr("l3_ip", "len", len(pkt_bld.get_layer('l3_ip')))
Now, we extened the single packet created with three VM instructions, in order to range over the source IP of the packet.
pkt_bld.set_vm_ip_range(ip_layer_name="l3_ip", # (1)
ip_field="src", # (2)
ip_init="10.0.0.1", ip_start="10.0.0.1", ip_end="10.0.0.255",
add_value=1,
operation="inc")
-
l3_ip
corresponds with the layer name given to the IP layer of the packet. This helps identifying and diffrenciate in packet containing more than one IP header. -
the name of the field on which we want to range.
Now, we added ranging for source IP starting from 10.0.0.1 to 10.0.0.255.
This will generate the follwing VM instructions, which will be provided under vm
field of the add_stream command:
>>> print pkt_bld.vm.dump(),
[{'name': 'l3__src', 'ins_name': 'flow_var', 'max_value': '167772415', 'min_value': '167772161', 'init_value': '167772161', 'size': 4, 'op': 'inc'},
{'is_big_endian': False, 'pkt_offset': 26, 'type': 'write_flow_var', 'name': 'l3__src', 'add_value': 1},
{'pkt_offset': 14, 'type': 'fix_checksum_ipv4'}]
As we can see, three instructions has been generated for this ranging criteria:
-
flow_var
instruction - for defining the ranging parameters. -
write_flow_var
instruction - for specifying where and how the modification should take place. -
fix_checksum_ipv4
instruction - for updated the checksum field
Warning
|
The order of the instruction does matter. In this example, if the fix_checksum_ipv4 instruction would have been places prior to the write_flow_var instruction, the generated packet would have satyed with the old checksum values.
|
Note
|
By default, with each change to the IP header, a fix_checksum_ipv4 instruction is added. This can be canceled by passing add_checksum_inst=False in functions which ranges over an IP field.
|
Now, we shall extend our ranging and add another field to range on, this time we’ll pick the TOS field of the IP header.
So, we’ll add the following code snippet ontop of the ranging method we already applied:
pkt_bld.set_vm_custom_range(layer_name="l3_ip",
hdr_field="tos",
init_val="10", start_val="10", end_val="200", add_val=2, val_size=1,
operation="inc")
So, in this case we chose to range the TOS field from 10 to 200 in steps of 2.
Finally, let’s see the expected JSON output of the VM instructions:
>>> print pkt_bld.vm.dump()
[{ 'init_value': '167772161', # (1)
'ins_name': 'flow_var',
'max_value': '167772415',
'min_value': '167772161',
'name': 'l3__src',
'op': 'inc',
'size': 4},
{ 'init_value': '10', # (2)
'ins_name': 'flow_var',
'max_value': '200',
'min_value': '10',
'name': 'l3__tos',
'op': 'inc',
'size': 1},
{ 'add_value': 2, # (3)
'is_big_endian': False,
'name': 'l3__tos',
'pkt_offset': 15,
'type': 'write_flow_var'},
{ 'add_value': 1, # (4)
'is_big_endian': False,
'name': 'l3__src',
'pkt_offset': 26,
'type': 'write_flow_var'},
{ 'pkt_offset': 14, 'type': 'fix_checksum_ipv4'} # (5)
]
-
flow_var
instruction for source IP. -
flow_var
instruction for TOS field -
write_flow_var
instruction for TOS. -
write_flow_var
instruction for source IP. -
fix_checksum_ipv4
instruction for both ranging options
Note
|
In this case only one checksum instruction has been generated, since both ranging options applies to the same IP header. |
This appendix brings examples with data for the this RPC interaction.
add_stream method example
The following example represents an interaction between the RPC client and the server’s response.
On the following example, there’s no VM instructions, rx_stats option is disabled and there’s only a single packet which isn’t connected to any other packet.
Client request
{
"id" : "2bqgd2r4",
"jsonrpc" : "2.0",
"method" : "add_stream",
"params" : {
"handler" : "37JncCHr",
"port_id" : 1,
"stream" : {
"enabled" : true,
"isg" : 0,
"mode" : {
"pps" : 100,
"type" : "continuous"
},
"next_stream_id" : -1,
"packet" : {
"binary" : [
0,
80,
86,
128,
13,
... # more packet data
77,
79,
250,
154,
66
],
"meta" : ""
},
"rx_stats" : {
"enabled" : false
},
"self_start" : true,
"vm" : []
},
"stream_id" : 0
}
}
Server’s response
{
"id" : "2bqgd2r4",
"jsonrpc" : "2.0",
"result" : "ACK"
}
On the following example, a batch request is being issued to the server, containing two add_stream
requests.
First request
The first client request is similar to the previous example.
However, in this case the rx_stats object is enbaled and set to monitor ancestor’s stream_id
(which is 0 in this case).
Ontop, this stream points to the next stream as the one to follow, as described under next_stream_id
of stream
object.
Second request
In this stream the big difference is that it has VM instructions under the vm
field of the stream
object.
Ontop, this stream is the last stream of the sequence, so next_stream_id
of stream
object is set to -1.
Client request
[
{
"id" : "tq49f6uj",
"jsonrpc" : "2.0",
"method" : "add_stream",
"params" : {
"handler" : "2JjzhMai",
"port_id" : 3,
"stream" : {
"enabled" : true,
"isg" : 0,
"mode" : {
"pps" : 100,
"type" : "continuous"
},
"next_stream_id" : 1,
"packet" : {
"binary" : [
0,
80,
86,
... # more packet data
250,
154,
66
],
"meta" : ""
},
"rx_stats" : {
"enabled" : true,
"latency_enabled" : false,
"seq_enabled" : false,
"stream_id" : 0
},
"self_start" : true,
"vm" : []
},
"stream_id" : 0
}
},
{
"id" : "2m7i5olx",
"jsonrpc" : "2.0",
"method" : "add_stream",
"params" : {
"handler" : "2JjzhMai",
"port_id" : 3,
"stream" : {
"enabled" : true,
"isg" : 0,
"mode" : {
"pps" : 200,
"type" : "continuous"
},
"next_stream_id" : -1,
"packet" : {
"binary" : [
0,
80,
86,
128,
... # more packet data
216,
148,
25
],
"meta" : ""
},
"rx_stats" : {
"enabled" : false
},
"self_start" : false,
"vm" : [
{
"init_value" : "65537",
"max_value" : "65551",
"min_value" : "65537",
"name" : "l3__src",
"op" : "inc",
"size" : 4,
"type" : "flow_var"
},
{
"add_value" : 1,
"is_big_endian" : false,
"name" : "l3__src",
"pkt_offset" : 34,
"type" : "write_flow_var"
}
]
},
"stream_id" : 1
}
}
]
Server’s response
[
{
"id" : "tq49f6uj",
"jsonrpc" : "2.0",
"result" : "ACK"
},
{
"id" : "2m7i5olx",
"jsonrpc" : "2.0",
"result" : "ACK"
}
]