The TRex RPC Server =================== :Author: Itay Marom, Dan Klein :email: trex-dev@cisco.com :revnumber: 1.1 :quotes.++: :numbered: :web_server_url: https://trex-tgn.cisco.com/trex :local_web_server_url: csi-wiki-01:8181/trex :toclevels: 7 include::trex_ga.asciidoc[] == Change log [options="header",cols="^1,^h,3a"] |================= | Version | name | meaning | 1.00 | Itay Marom (imarom) | - first version | 1.01 | Dan Klein (danklei) | - added usage examples using Python code as Higher-level usage - added logic and explanation behind VM commands | 1.1 | Dan Klein (danklei) | - Fixed some consistency issues - added RPC interaction examples appendix | 1.2 | Hanoch Haim (hhaim) | - add tuple generator command | 1.3 | Hanoch Haim (hhaim) | - update VM instructions | 1.4 | Hanoch Haim (hhaim) | - add random trim instruction | 1.5 | Hanoch Haim (hhaim) | - add more instructions (v1.92) | 1.6 | Itay Marom (imarom) | - added API synchronization |================= == Audience of this document Anyone that wants to understand the low level protocol to TRex server. for example a GUI developer that wants to develop a GUI for TRex Server. == RPC Support On TRex 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 === Transport Layer TRex server transport layer is implemented using ZMQ. The default configuration is TCP on port 5555, however this is configurable. {zwsp} + The communication model is based on the request-reply ZMQ model: http://zguide.zeromq.org/page:all#Ask-and-Ye-Shall-Receive {zwsp} + for more on ZMQ and implementation please refer to: {zwsp} + http://zeromq.org/intro:read-the-manual === RPC Reprensentation Protocol The RPC reprensentation protocol is JSON RPC v2.0. Every request and response will be encoded in a JSON RPC v2.0 format. {zwsp}+ For more info on JSON RPC v2.0 spec please refer to: {zwsp}+ http://www.jsonrpc.org/specification {zwsp}+ Later on in the document we will describe all the supported commands. === TRex Console To debug RPC it is possible to enable verbose command from Console see link:draft_trex_stateless.html#_console_commands[here] On the 'client' side: [source,bash] ---- 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": {} } [SUCCESS] ---- == RPC Server Component Position Illustration The following diagram illustres the RPC server component's place: image::images/rpc_server_big_picture.png[title="RPC Server Position",align="left",width=800, link="images/rpc_server_big_picture.png"] == RPC Server Port State Machine 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: image::images/rpc_states.png[title="Port States",align="left",width=150, link="images/rpc_states.png"] == RPC Commands The following RPC commands are supported === API Synchronization * *Name* - 'api_sync' * *API Class* - 'None' * *Valid States* - 'not relevant' * *Description* - Sync with server about API classes. This allows the server and the client to be sure they are fully synced. The return values are used for furthur communication with the server. every API from a specific class requires its corresponding api_h parameter added to the specific parameters of the function. * *Parameters* - ** *api_vers* [list] - A list of objects of type xref:api_class['api_class'] * *Result* ['object'] - A list of objects of type xref:api_class_rc['api_class_rc'] .Object type 'api_class' [options="header",cols="1,1,3"] |================= | Field | Type | Description | type | string | name of the API class | major | int | major version | minor | int | minor version |================= .Object type 'api_class_rc' [options="header",cols="1,1,3"] |================= | Field | Type | Description | type | string | name of the API class | api_h | string | API handler for this API class |================= Example: [source,bash] ---- 'Request': { "id": "6d4e9gs3", "jsonrpc": "2.0", "method": "api_sync", "params": { "api_vers": [ { "type": "core" "major": 1, "minor": 0, } ] } } 'Response': { "id": "6d4e9gs3", "jsonrpc": "2.0", "result": { "api_vers": [ { "type": "core" "api_h": "SPhoCDIV", } ] } } ---- === Ping * *Name* - 'ping' * *API Class* - 'None' * *Valid States* - 'not relevant' * *Description* - Pings the TRex server * *Parameters* - None * *Result* ['object'] - {} Example: [source,bash] ---- 'Request': { "jsonrpc": "2.0", "id": 1, "method": "ping", "params": null } 'Response': { "jsonrpc" : "2.0", "id" : 1, "result" : {} } ---- === Get Server Supported Commands * *Name* - 'get_supported_cmds' * *API Class* - 'core' * *Valid States* - 'not relevant' * *Description* - Queries the server for all the supported commands * *Parameters* - None * *Result* ['array'] - A list of all the supported commands by the server Example: [source,bash] ---- 'Request': { "id": "7rqf0xyd", "jsonrpc": "2.0", "method": "get_supported_cmds", "params": { "api_h": "VGDJwdiY" } } 'Response': { "id": "7rqf0xyd", "jsonrpc": "2.0", "result": [ "push_remote", "validate", "start_traffic", "get_all_streams", "shutdown", "get_stream", "test_add", "stop_traffic", "get_utilization", "release", "test_sub", "api_sync", "get_port_status", "get_port_stats", "publish_now", "get_system_info", "get_supported_cmds", "get_version", "get_port_xstats_names", "update_traffic", "get_active_pgids", "pause_traffic", "get_owner", "acquire", "set_port_attr", "get_port_xstats_values", "remove_rx_filters", "resume_traffic", "add_stream", "remove_stream", "remove_all_streams", "ping", "get_stream_list" ] } ---- === Get Version * *Name* - 'get_version' * *API Class* - 'core' * *Valid States* - 'not relevant' * *Description* - Queries the server for version information * *Parameters* - None * *Result* ['object'] - See table below .Object type 'return values for get_version' [options="header",cols="1,1,3"] |================= | Field | Type | Description | version | string | TRex version | build_date | string | build date | build_time | string | build time | built_by | string | who built this version |================= [source,bash] ---- 'Request': { "id": "wapkk8m6", "jsonrpc": "2.0", "method": "get_version", "params": { "api_h": "SPhoCDIV" } } 'Response': { "id": "wapkk8m6", "jsonrpc": "2.0", "result": { "build_date": "Sep 16 2015", "build_time": "12:33:01", "built_by": "imarom", "version": "v0.0" } } ---- === Get System Info * *Name* - 'get_system_info' * *API Class* - 'core' * *Description* - Queries the server for system properties * *Parameters* - None * *Result* ['object'] - See table below .return value: 'get_system_info' [options="header",cols="1,1,3"] |================= | Field | Type | Description | dp_core_count | int | DP core count (total) | dp_core_count_per_port | int | DP core count per pair of ports | 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 | array of object ''ports'' - see below |================= .return value: 'get_system_info'.'ports' [options="header",cols="1,1,3"] |================= | Field | Type | Description | description | string | description of port | driver | string | driver type | numa | int | NUMA of port | pci_addr | string | PCI address of port | hw_macaddr | string | HW MAC of port (masked by src_macaddr) | src_macaddr | string | src MAC of port | dst_macaddr | string | dest MAC of port | is_virtual | bool | is port virtual | is_fc_supported | bool | is flow control supported | is_led_supported | bool | is led on/off supported | is_link_supported | bool | is link status change supported | index | int | port index | speed | int | current max speed of the port (1, 10, 40, 100) | supp_speeds | array | list of max speeds supported by port | rx | object | see below |================= .return value: 'get_system_info'.'ports'.'rx' [options="header",cols="1,1,3"] |================= | Field | Type | Description | caps | array | list of capabilities: "flow_stats", "latency" etc. | counters | int | number of different pg_ids one can use at the same time |================= [source,bash] ---- 'Request': { "id": "kn92anod", "jsonrpc": "2.0", "method": "get_system_info", "params": { "api_h": "o8VEJEOd" } } 'Response': { "id": "kn92anod", "jsonrpc": "2.0", "result": { "core_type": "Intel(R) Xeon(R) CPU E5-2667 v3 @ 3.20GHz", "dp_core_count": 1, "dp_core_count_per_port": 1, "hostname": "csi-trex-11", "port_count": 2, "ports": [ { "description": "VMXNET3 Ethernet Controller", "driver": "rte_vmxnet3_pmd", "dst_macaddr": "00:0c:29:2a:99:bc", "hw_macaddr": "00:0c:29:2a:99:b2", "index": 0, "is_fc_supported": false, "is_led_supported": false, "is_link_supported": false, "is_virtual": true, "numa": -1, "pci_addr": "0000:03:00.0", "rx": { "caps": [ "flow_stats", "latency", "rx_bytes" ], "counters": 127 }, "speed": 10, "src_macaddr": "00:0c:29:2a:99:b2", "supp_speeds": [ 10000 ] }, { "description": "VMXNET3 Ethernet Controller", "driver": "rte_vmxnet3_pmd", "dst_macaddr": "00:0c:29:2a:99:b2", "hw_macaddr": "00:0c:29:2a:99:bc", "index": 1, "is_fc_supported": false, "is_led_supported": false, "is_link_supported": false, "is_virtual": true, "numa": -1, "pci_addr": "0000:0b:00.0", "rx": { "caps": [ "flow_stats", "latency", "rx_bytes" ], "counters": 127 }, "speed": 10, "src_macaddr": "00:0c:29:2a:99:bc", "supp_speeds": [ 10000 ] } ], "uptime": "Oct 31 2016 @ 16:25:28" } } ---- === Get Port Status * *Name* - 'get_port_status' * *API Class* - 'core' * *Valid States* - 'all' * *Description* - Queries the server for status * *Parameters* - ** *port_id* ['int'] - port id to query for owner * *Result* ['object'] - see below [source,bash] ---- 'Request': { "id": "oveilf0n", "jsonrpc": "2.0", "method": "get_port_status", "params": { "api_h": "VGDJwdiY", "port_id": 7 } } 'Response': { "id": "oveilf0n", "jsonrpc": "2.0", "result": { "attr": { "fc": { "mode": 0 }, "link": { "up": true }, "promiscuous": { "enabled": false } }, "max_stream_id": 3, "owner": "", "speed": 10000, "state": "TX" } } ---- .return value: 'get_port_status' [options="header",cols="1,1,3"] |================= | Field | Type | Description | owner | string | name of current owner (or "" if none) | state | string | state of port (DOWN, IDLE, STREAMS, TX, PAUSE) |================= === Acquire * *Name* - 'Acquire' * *API Class* - 'core' * *Valid States* - 'all' * *Description* - Takes ownership over the port * *Parameters* - ** *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'] - handler for future sessions [source,bash] ---- 'Request': { "id": "b1tr56yz", "jsonrpc": "2.0", "method": "Acquire", "params": { "api_h": "SPhoCDIV", "user": "itay", "port_id": 1, "force": false, } } 'Response': { "id": "b1tr56yz", "jsonrpc": "2.0", "result": "AQokC3ZA" } ---- === Release * *Name* - 'release' * *API Class* - 'core' * *Valid States* - 'owned' * *Description* - Release owernship over the device * *Parameters* - ** *handler* ['string'] - unique connection handler ** *port_id* ['int'] - port id to release * *Result* ['object'] - {} [source,bash] ---- 'Request': { "id": "m785dxwd", "jsonrpc": "2.0", "method": "release", "params": { "api_h": "SPhoCDIV", "handler": "37JncCHr", "port_id": 1 } } 'Response': { "id": "m785dxwd", "jsonrpc": "2.0", "result": {} } ---- === Add Stream * *Name* - 'add_stream' * *API Class* - 'core' * *Valid States* - 'owned' * *Description* - Adds a stream to a port * *Parameters* ** *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 xref:stream_obj['stream'] * *Result* ['object'] - {} The object type 'stream' anchor:stream_obj[] Add_stream gets a single parameter of type object. The format of that object is as follows: .Object type 'stream' [options="header",cols="1,1,3"] |================= | Field | Type | Description | enabled | boolean | is this stream enabled | self_start | boolean | is this stream triggered by starting injection or triggered by another stream | action_count | uint16_t | In case it is bigger than zero and next stream is not -1 (set) the number of goto will be limited to this number. Maximum value is 65K. default is zero. Zero means - not limit. | random_seed | uint32_t | For creating reproducible tests with random number, each stream can get a seed. this field is optional. In case of zero the seed value won't be taken | flags | uint16_t | bit 0 (LSB) : 1 - take the src MAC from the packet instead of config file. bit 1-2 (LSB) how to set the dest MAC ( stCFG_FILE = 0, stPKT = 1,stARP = 2 ) | 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 xref:packet_obj['packet'] | mode | object | object of type xref:mode_obj['mode'] | vm | object | array of objects of type xref:vm_obj['vm'] | rx_stats | object | object of type xref:rx_stats_obj['rx_stats'] |================= ==== packet anchor:packet_obj[] packet contains binary and meta data .Object type 'packet' [options="header",cols="1,1,3"] |================= | 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 anchor:mode_obj[] mode object can be 'one' of the following objects: .Object type 'rate' [options="header",cols="1,1,3"] |================= | Field | Type | Description | type | string | [''pps'',''bps_L1'',''bps_L2'',''percentage'' | value | double | rate |================= .Object type 'mode - continuous' [options="header",cols="1,1,3"] |================= | Field | Type | Description | type | string | ''continuous'' | rate | object | rate object |================= .Object type 'mode - single_burst' [options="header",cols="1,1,3"] |================= | Field | Type | Description | type | string | ''single_burst'' | rate | object | rate object | total pkts | int | total packets in the burst |================= .Object type 'mode - multi_burst' [options="header",cols="1,1,3"] |================= | Field | Type | Description | type | string | ''multi_burst'' | rate | object | rate object | 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 |================= ==== vm an Object that include instructions array and properties of the field engine program anchor:vm_obj[] .Object type 'packet' [options="header",cols="1,1,3"] |================= | Field | Type | Description | Instructions | array | list of instructional objects | split_by_var | string | name of the field by which to split into threads | Restart | boolean | restart the field engine program when stream moving from inactive->active |================= Array of VM instruction objects to be used with this stream Any element in the array can be one of the following object types: ===== fix_checksum_hw Fix TCP/UDP and IPv4 headers using hardware assit engine .Object type 'vm - fix_checksum_hw' [options="header",cols="1,1,3"] |================= | Field | Type | Description | type | string | ''fix_checksum_hw'' | l2_len | uint16 | len of L2 (e.g. 14 Ether) | l3_len | uint16 | len of l3 header (e.g. 20 for IP) | l4_type | uint16 | the type of L4 header either UDP or TCP ( L4_TYPE_UDP = 11 | L4_TYPE_TCP = 13) |================= ===== fix_checksum_ipv4 .Object type 'vm - fix_checksum_ipv4' [options="header",cols="1,1,3"] |================= | Field | Type | Description | type | string | ''fix_checksum_ipv4'' | pkt_offset | uint16 | offset of the field to fix |================= ===== flow_var .Object type 'vm - flow_var' [options="header",cols="1,1,3"] |================= | 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 | step | uint64_t as string | step, how much to inc or dec. 1 is the default (in case of 'random' this field is not used) |================= ===== repetable_random Instruction to choose a limited number of random values from a big range The values could be deterministic by providing seed .Object type 'vm - flow_var' [options="header",cols="1,1,3"] |================= | Field | Type | Description | type | string | ''flow_var_rand_limit''' | name | string | flow var name - this should be a unique identifier | size | [1,2,4,8] | size of the var in bytes | limit | uint64_t as string | the number of values to choose | seed | uint64_t as string | seed of the random, in case there is no seed time will be taken | min_value | uint64_t as string | minimum value for the field | max_value | uint64_t as string | maximum value for the field |================= an example of tuple_flow_var variable [source,bash] ---- size = 2 limit = 5 seed = 0x1234 min_value = 0 max_value = 10 ---- results could be [source,bash] ---- 7 , 8, 1 ,5, 2 , 7 , 8, 1 ,5, 2, 7 , 8, 1 ,5, 2 ---- ===== write_flow_var .Object type 'vm - write_flow_var' [options="header",cols="1,1,3"] |================= | 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 |================= ===== trim_pkt_size .Object type 'vm - trim_pkt_size' [options="header",cols="1,1,3"] |================= | Field | Type | Description | type | string | ''trim_pkt_size'' | name | string | flow var name to take the new trim packet size from. The var size should be valid packet size and less than template packet size. see `stl/udp_rand_size.yaml` for an example |================= ===== tuple_flow_var .Object type 'vm - tuple_flow_var' [options="header",cols="1,1,3"] |================= | Field | Type | Description | type | string | ''tuple_flow_var''' | name | string | tuple generator name - this should be a unique identifier name.ip and name.port will be added | ip_min | uint32_t as string | ipv4 min ip as uint32_t e.g. 10.0.0.1 | ip_max | uint32_t as string | ipv4 max ip as uint32_t e.g. 10.0.1.255 | port_min | uint16_t as string | ipv4 min port as uint16_t e.g. 1025 | port_max | uint16_t as string | ipv4 max port as uint16_t e.g. 65000 | limit_flows | uint32_t as string | the number of flows. 0 means we will use all the ip/port min-max range | flags | uint16_t as string | 1 - unlimited number of flows. in case the first bit is enabled port_min and port_max is ignored and the maximum number of flows will be generated on those ips |================= an example of tuple_flow_var variable [source,bash] ---- ip_min = 10.0.0.1 ip_max = 10.0.0.5 port_min = 1025 port_max = 1028 limit_flows = 10 ---- .Results [options="header",cols="1,1,3"] |================= | IP | PORT | FLOW | 10.0.0.1 | 1025 | 1 | 10.0.0.2 | 1025 | 2 | 10.0.0.3 | 1025 | 3 | 10.0.0.4 | 1025 | 4 | 10.0.0.5 | 1025 | 5 | 10.0.0.1 | 1026 | 6 << the port is inc here | 10.0.0.2 | 1026 | 7 | 10.0.0.3 | 1026 | 8 | 10.0.0.4 | 1026 | 9 | 10.0.0.5 | 1026 | 10 | 10.0.0.1 | 1025 | 1 << back to the first flow |================= The variable name.port and name.ip could be written to any offset in the packet (usualy to src_ip and src_port as client) ===== write_mask_flow_var .Object type 'vm - write_mask_flow_var' [options="header",cols="1,1,3"] |================= | Field | Type | Description | type | string | ''write_mask_flow_var''' | name | string | flow variable name | pkt_offset | uint16_t as string | offset at the packet to perform the write | add_value | int32_t as string | delta to add to the field prior to writing - can be negative | pkt_cast_size | uint_t as string | size in bytes only 1,2,4 are valid | mask | uint32_t as string | 1 means care e.g. 0xff will write to only 8 LSB bits | shift | int8_t as string | Positive will shift left (multiply by x2) negative will shift right (divided by 2) e.g. 1 will multiply by 2 | is_big_endian | boolean | should write as big endian or little |================= .Pseudocode [source,bash] ---- uint32_t val=(cast_to_size)rd_from_varible("name"); # read flow-var val+=m_add_value; # add value if (m_shift>0) { # shift val=val<>(-m_shift); } } pkt_val=rd_from_pkt(pkt_offset) # RMW pkt_val = (pkt_val & ~m_mask) | (val & m_mask) wr_to_pkt(pkt_offset,pkt_val) ---- an example of tuple_flow_var variable [source,bash] ---- name = "a" (varible 2 byte start 1-10 inc ) pkt_cast_size = 1 ( cast to uint8_t ) add_value = 0 mask = 0xf0 shift = 4 is_big_endian =1 ---- .Results [options="header",cols="1,1,3"] |================= | var "a" | PKT- before write | PKT post write | 1 | 0x03 | 0x13 | 2 | 0x03 | 0x23 | 3 | 0x03 | 0x33 | 4 | 0x03 | 0x43 | 5 | 0x03 | 0x53 |================= The use cases of this instruction is to write to a bit field (valn/mpls) TIP: For more information and examples on VM objects please refer to: link:vm_doc.html[VM examples] ==== rx_stats anchor:rx_stats_obj[] Describes rx stats for the stream {zwsp} + IMPORTANT: In case rx_stats is enabled, meta data will be written in the end of the packet. please also consider the following constraints: ===== Constrains * *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 ===== The bytes needed for activating rx_stats * *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. .Object type 'rx_stats' [options="header",cols="1,1,3"] |================= | Field | Type | Description | enabled | boolean | is rx_stats enabled for this stream | stream_id | int | stream_id for which to collect rx_stats. + This could be stream_id different from the stream object which contains the rx_stats object. | seq_enabled | boolean | should write 32 bit sequence | latency_enabled | boolean | should write 32 bit latency |================= [source,bash] ---- 'Request': { "id": 1, "jsonrpc": "2.0", "method": "add_stream", "params": { "api_h": "SPhoCDIV", "handler": "37JncCHr", "port_id": 1, "stream_id": 502 "stream": { "enabled": true, "isg": 4.3, "mode": { "rate": { "type": "pps", "value": 10 }, "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": {} } ---- 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. === Remove Stream * *Name* - 'remove_stream' * *API Class* - 'core' * *Valid States* - 'owned' * *Description* - Removes a stream from a port * *Parameters* ** *handler* ['string'] - unique connection handler ** *port_id* ['int'] - port assosicated with the stream. ** *stream_id* ['int'] - stream to remove * *Result* ['object'] - {} [source,bash] ---- 'Request': { "id": 1 "jsonrpc": "2.0", "method": "remove_stream", "params": { "api_h": "SPhoCDIV", "handler": "37JncCHr", "port_id": 1, "stream_id": 502 } } 'Response': { "id": 1 "jsonrpc": "2.0", "result": {} } ---- === Get Stream ID List * *Name* - 'get_stream_list' * *API Class* - 'core' * *Valid States* - 'unowned', 'owned', 'active' * *Description* - fetch all the assoicated streams for a port * *Parameters* ** *handler* ['string'] - unique connection handler ** *port_id* ['int'] - port to query for registered streams * *Result* ['array'] - array of 'stream_id' [source,bash] ---- 'Request': { "id": 1, "jsonrpc": "2.0", "method": "get_stream_list", "params": { "api_h": "SPhoCDIV", "handler": "37JncCHr", "port_id": 1 } } 'Response': { "id": 1, "jsonrpc": "2.0", "result": [ 502, 18 ] } ---- === Get Stream * *Name* - 'get_stream' * *API Class* - 'core' * *Valid States* - 'unowned', 'owned', 'active' * *Description* - get a specific stream object * *Parameters* ** *handler* ['string'] - unique connection handler ** *port_id* ['int'] - port for the associated stream ** *stream_id* ['int'] - the requested stream id * *Result* ['object'] - object xref:stream_obj['stream'] [source,bash] ---- 'Request': { "id": 1, "jsonrpc": "2.0", "method": "get_stream", "params": { "api_h": "SPhoCDIV", "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 } } } ---- === Remove All Streams * *Name* - 'remove_all_streams' * *API Class* - 'core' * *Valid States* - 'owned' * *Description* - remove all streams from a port * *Parameters* ** *handler* ['string'] - unique connection handler ** *port_id* ['int'] - port for the associated stream * *Result* ['object'] - {} [source,bash] ---- 'Request': { "id": 1, "jsonrpc": "2.0", "method": "remove_all_streams", "params": { "api_h": "SPhoCDIV", "handler": "37JncCHr", "port_id": 2 } } 'Response': { "id": 1, "jsonrpc": "2.0", "result": {} } ---- === Start Traffic * *Name* - 'start_traffic' * *API Class* - 'core' * *Valid States* - 'owned' * *Description* - Starts the traffic on a specific port. if traffic has already started an error will be returned * *Parameters* ** *handler* ['string'] - unique connection handler ** *port_id* ['int'] - port id on which to start traffic ** *core_mask* ['uint64'] [*optional*] - a non zero mask to specify which cores will be active during TX, if no value is provided, the value is all bits on (MAX_UINT64) * *Result* ['object'] - {} [source,bash] ---- 'Request': { "id": "b3llt8hs", "jsonrpc": "2.0", "method": "start_traffic", "params": { "api_h": "SPhoCDIV", "handler": "37JncCHr", "port_id": 3 "core_mask": 0xff } 'Response': { "id": "b3llt8hs", "jsonrpc": "2.0", "result": {} } ---- === Stop Traffic * *Name* - 'stop_traffic' * *API Class* - 'core' * *Valid States* - 'active' * *Description* - Stops the traffic on a specific port. if the port has already started nothing will happen * *Parameters* ** *handler* ['string'] - unique connection handler ** *port_id* ['int'] - port id on which to stop traffic * *Result* ['object'] - {} [source,bash] ---- 'Request': { "id": "h2fyhni7", "jsonrpc": "2.0", "method": "stop_traffic", "params": { "api_h": "SPhoCDIV", "handler": "37JncCHr", "port_id": 3 } } 'Response': { "id": "h2fyhni7", "jsonrpc": "2.0", "result": {} } ---- === Remove RX Filters * *Name* - 'remove_rx_filters' * *API Class* - 'core' * *Valid States* - 'owned' * *Description* - Post to calling stop, the client should call this function to remove any RX filters that were attached. this is because the server cannot know when it is safe to remove those (after stop some packets might take time to get to arrive - RTT) * *Parameters* ** *handler* ['string'] - unique connection handler ** *port_id* ['int'] - port id on which to remove all RX filters * *Result* ['object'] - {} [source,bash] ---- 'Request': { "id": "1jwrw9nx", "jsonrpc": "2.0", "method": "remove_rx_filters", "params": { "api_h": "SPhoCDIV", "handler": "ywVlqZa8", "port_id": 3 } } 'Response': { "id": "1jwrw9nx", "jsonrpc": "2.0", "result": {} } ---- === Get Global Stats * *Name* - 'get_global_stats' * *API Class* - 'core' * *Valid States* - 'unowned', 'owned', 'active' * *Description* - Get machine global stats * *Parameters* - None * *Result* ['object'] - See Below .Return value of 'get_global_stats' [options="header",cols="1,1,3"] |================= | 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 |================= === Get Port Stats * *Name* - 'get_port_stats' * *API Class* - 'core' * *Valid States* - 'unowned', 'owned', 'active' * *Description* - Get port stats * *Parameters* ** *port_id* [int] - The port id for query * *Result* ['object'] - See Below .Return value of 'get_port_stats' [options="header",cols="1,1,3"] |================= | 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 |================= === Get Stream Stats * *Name* - 'get_steram_stats' * *API Class* - 'core' * *Valid States* - 'unowned', 'owned', 'active' * *Description* - Get port stats * *Parameters* ** *port_id* [int] - The port id for query ** *stream_id* [int] - The stream id for query * *Result* ['object'] - See Below .Return value of 'get_stream_stats' [options="header",cols="1,1,3"] |================= | 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) |================= === Get Utilization * *Name* - 'get_utilization' * *API Class* - 'core' * *Valid States* - 'all' * *Description* - Get the CPU and MBUFs utilization. * *Parameters* - None * *Result* ['object'] - ** *cpu* - The CPU utilization per DP thread (in their order). Each element is array of history (most latest is first in array, interval between values is 1 sec, values are integers 0-100). ** *mbuf_stats* - The MBUFs are per CPU socket, per bucket of sizes: 64b, 9kb etc. Each bucket is array of 2 values: first is number of free elements and second is total. [source,bash] ---- 'Request': { "id": "vlxrc9r6", "jsonrpc": "2.0", "method": "get_utilization", "params": { "api_h": "2AIar0tl" } } 'Response': {'id': 'vlxrc9r6', 'jsonrpc': '2.0', 'result': {'cpu': [[30, 33, 28, 21, 30, 35, 33, 38, 29, 25, 37, 35, 31, 34, 35, 37, 26, 31, 26, 27], [37, 31, 24, 21, 26, 32, 34, 36, 27, 28, 36, 33, 35, 35, 35, 36, 30, 39, 35, 40], [32, 34, 25, 29, 28, 44, 37, 40, 32, 33, 38, 33, 33, 35, 33, 25, 22, 26, 27, 31], [28, 33, 17, 21, 27, 36, 30, 30, 27, 25, 36, 35, 38, 43, 41, 28, 31, 32, 31, 41], [27, 31, 27, 32, 26, 36, 27, 33, 30, 29, 29, 28, 30, 36, 33, 31, 26, 30, 25, 35], [31, 31, 21, 24, 23, 31, 28, 33, 33, 33, 31, 21, 30, 33, 31, 23, 27, 29, 36, 36], [27, 32, 38, 23, 35, 44, 38, 28, 29, 31, 38, 38, 31, 32, 32, 33, 24, 28, 29, 32], [26, 26, 24, 30, 36, 36, 33, 26, 37, 24, 29, 40, 39, 37, 36, 26, 26, 25, 38, 25], [27, 37, 33, 25, 28, 37, 39, 30, 31, 26, 34, 27, 37, 31, 28, 33, 36, 39, 27, 38], [31, 31, 31, 26, 31, 28, 31, 35, 24, 25, 31, 24, 34, 30, 31, 35, 29, 30, 28, 30], [28, 40, 24, 27, 30, 26, 34, 27, 28, 31, 41, 29, 35, 33, 35, 35, 31, 31, 30, 39], [20, 34, 29, 27, 34, 25, 28, 43, 26, 26, 36, 31, 28, 36, 39, 26, 18, 24, 29, 26], [26, 29, 34, 25, 26, 42, 30, 38, 30, 26, 37, 29, 43, 36, 36, 29, 27, 37, 33, 28], [29, 30, 30, 27, 34, 34, 32, 34, 26, 28, 37, 28, 36, 38, 29, 35, 26, 32, 28, 37]], 'mbuf_stats': {'cpu-socket-0': {'1024b': [73696, 73710], '128b': [98280, 98280], '2048b': [98266, 98280], '256b': [73710, 73710], '4096b': [1152, 1152], '512b': [73710, 73710], '64b': [191468, 196560], '9kb': [6912, 8960]}, 'cpu-socket-1': {'1024b': [73696, 73710], '128b': [98280, 98280], '2048b': [98266, 98280], '256b': [73710, 73710], '4096b': [1152, 1152], '512b': [73710, 73710], '64b': [191429, 196560], '9kb': [6912, 8960]}}}} ---- === Get Xstat names * *Name* - 'get_port_xstats_names' * *API Class* - 'core' * *Valid States* - 'all' * *Description* - Get array of names of extended stats of port. List may vary per NIC type. * *Parameters* - port_id * *Result* ['object'] - See example below [source,bash] ---- 'Request': { "id": "m348pnzr", "jsonrpc": "2.0", "method": "get_port_xstats_names", "params": { "api_h": "f682qkNJ", "port_id": 0 } } 'Response': { "id": "m348pnzr", "jsonrpc": "2.0", "result": { "xstats_names": [ "rx_good_packets", "tx_good_packets", "rx_good_bytes", "tx_good_bytes", "rx_errors", "tx_errors", "rx_mbuf_allocation_errors", "rx_q0packets", "rx_q0bytes", "rx_q0errors", "rx_q1packets", "rx_q1bytes", "rx_q1errors", "tx_q0packets", "tx_q0bytes", "tx_q1packets", "tx_q1bytes", "tx_q2packets", "tx_q2bytes", "tx_q3packets", "tx_q3bytes", "rx_unicast_packets", "rx_multicast_packets", "rx_broadcast_packets", "rx_dropped", "rx_unknown_protocol_packets", "tx_unicast_packets", "tx_multicast_packets", "tx_broadcast_packets", "tx_dropped", "tx_link_down_dropped", "rx_crc_errors", "rx_illegal_byte_errors", "rx_error_bytes", "mac_local_errors", "mac_remote_errors", "rx_length_errors", "tx_xon_packets", "rx_xon_packets", "tx_xoff_packets", "rx_xoff_packets", "rx_size_64_packets", "rx_size_65_to_127_packets", "rx_size_128_to_255_packets", "rx_size_256_to_511_packets", "rx_size_512_to_1023_packets", "rx_size_1024_to_1522_packets", "rx_size_1523_to_max_packets", "rx_undersized_errors", "rx_oversize_errors", "rx_mac_short_dropped", "rx_fragmented_errors", "rx_jabber_errors", "tx_size_64_packets", "tx_size_65_to_127_packets", "tx_size_128_to_255_packets", "tx_size_256_to_511_packets", "tx_size_512_to_1023_packets", "tx_size_1024_to_1522_packets", "tx_size_1523_to_max_packets", "rx_flow_director_atr_match_packets", "rx_flow_director_sb_match_packets", "tx_low_power_idle_status", "rx_low_power_idle_status", "tx_low_power_idle_count", "rx_low_power_idle_count", "rx_priority0_xon_packets", "rx_priority1_xon_packets", "rx_priority2_xon_packets", "rx_priority3_xon_packets", "rx_priority4_xon_packets", "rx_priority5_xon_packets", "rx_priority6_xon_packets", "rx_priority7_xon_packets", "rx_priority0_xoff_packets", "rx_priority1_xoff_packets", "rx_priority2_xoff_packets", "rx_priority3_xoff_packets", "rx_priority4_xoff_packets", "rx_priority5_xoff_packets", "rx_priority6_xoff_packets", "rx_priority7_xoff_packets", "tx_priority0_xon_packets", "tx_priority1_xon_packets", "tx_priority2_xon_packets", "tx_priority3_xon_packets", "tx_priority4_xon_packets", "tx_priority5_xon_packets", "tx_priority6_xon_packets", "tx_priority7_xon_packets", "tx_priority0_xoff_packets", "tx_priority1_xoff_packets", "tx_priority2_xoff_packets", "tx_priority3_xoff_packets", "tx_priority4_xoff_packets", "tx_priority5_xoff_packets", "tx_priority6_xoff_packets", "tx_priority7_xoff_packets", "tx_priority0_xon_to_xoff_packets", "tx_priority1_xon_to_xoff_packets", "tx_priority2_xon_to_xoff_packets", "tx_priority3_xon_to_xoff_packets", "tx_priority4_xon_to_xoff_packets", "tx_priority5_xon_to_xoff_packets", "tx_priority6_xon_to_xoff_packets", "tx_priority7_xon_to_xoff_packets" ] } } ---- === Get Xstat values * *Name* - 'get_port_xstats_values' * *API Class* - 'core' * *Valid States* - 'all' * *Description* - Get array of values of extended stats of port. Order of values matches the get_port_xstats_names. * *Parameters* - port_id * *Result* ['object'] - See example below [source,bash] ---- 'Request': { "id": "tfonjtfc", "jsonrpc": "2.0", "method": "get_port_xstats_values", "params": { "api_h": "f682qkNJ", "port_id": 7 } } 'Response': { "id": "tfonjtfc", "jsonrpc": "2.0", "result": { "xstats_values": [ 0, 0, ... 0, 0 ] } } ---- === Setting port attributes * *Name* - 'set_port_attr' * *API Class* - 'core' * *Valid States* - 'all' * *Description* - Sets port attributes * *Parameters* - ** *port_id* ['int'] - port to apply attributes ** *attr* ['object'] - dictionary with attributes, each of them is optional, see below * *Result* ['object'] - {} .Object type 'attr' [options="header",cols="1,1,1,3"] |================= | Field | Subfield | Type | Description | link_status | up | bool | True = link up | promiscuous | enabled | bool | True = promiscuous enabled | led_status | on | bool | False = turn off LEDs | flow_ctrl_mode | mode | int | Flow control: 0 = none, 1 = tx, 2 = rx, 3 = full |================= Request example: [source,bash] ---- 'Request': { "id": "uuopmfln", "jsonrpc": "2.0", "method": "set_port_attr", "params": { "api_h": "f682qkNJ", "attr": { "flow_ctrl_mode": { "mode": 1 }, "promiscuous": { "enabled": true } }, "handler": "vGp4EyA5", "port_id": 7 } } ---- == Typical Transactions Examples the following examples represents common scenarios. commands in [...] represents 'meta commands' and not real RPC commands such as 'repeat', 'wait' and etc. === Init/Boot This sequence represents a client implementing the protocol taking ownership over the server and preparing to perform work ==== Commands Flow * *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 === Simple Traffic With Adding/Editing Streams describes a simple scenario where a user wants to add or edit one or more streams to one or more ports ==== Commands Flow * *[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 === Logout Describes the log off from the machine ==== Commands Flow * *stop_traffic* ['optional'] - if traffic has started - stop it * *get_global_stats* ['optional'] - make sure the machine has stopped * *remove_all_streams* ['optional'] - if you want to clear all the previous streams - use this * *release* - release the ownership over the device :numbered!: [appendix] Interaction Examples -------------------- This appendix brings examples with data for the this RPC interaction. + <<_add_stream, add_stream>> method example ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The following example represents an interaction between the RPC client and the server's response. Simple single packet client request ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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. [underline]#Client request# [source, bash] ---- { "id" : "2bqgd2r4", "jsonrpc" : "2.0", "method" : "add_stream", "params" : { "api_h": "SPhoCDIV", "handler" : "37JncCHr", "port_id" : 1, "stream" : { "enabled" : true, "isg" : 0, "mode" : { "rate": { "type": "pps", "value": 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 } } ---- [underline]#Server's response# [source, bash] ---- { "id" : "2bqgd2r4", "jsonrpc" : "2.0", "result" : {} } ---- Two linked packets with VM instructions client request ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ On the following example, a **batch request** is being issued to the server, containing two `add_stream` requests. [underline]#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. [underline]#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'. [underline]#Client request# [source, bash] ---- [ { "id" : "tq49f6uj", "jsonrpc" : "2.0", "method" : "add_stream", "params" : { "api_h": "SPhoCDIV", "handler" : "2JjzhMai", "port_id" : 3, "stream" : { "enabled" : true, "isg" : 0, "mode" : { "rate": { "type": "pps", "value": 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" : { "api_h": "SPhoCDIV", "handler" : "2JjzhMai", "port_id" : 3, "stream" : { "enabled" : true, "isg" : 0, "mode" : { "rate": { "type": "pps", "value": 100 }, "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 } } ] ---- [underline]#Server's response# [source, bash] ---- [ { "id" : "tq49f6uj", "jsonrpc" : "2.0", "result" : {} }, { "id" : "2m7i5olx", "jsonrpc" : "2.0", "result" : {} } ] ---- Another Example of tuple generator ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [source, bash] ---- - name: udp_64B stream: self_start: True packet: binary: stl/udp_64B_no_crc.pcap # pcap should not include CRC mode: type: continuous pps: 100 rx_stats: [] # program that define 1M flows with IP range 16.0.0.1-16.0.0.254 # we will create a script that do that for you # this is the low level instructions vm: [ { "type" : "tuple_flow_var", # name of the command "name" : "tuple_gen", # tuple_gen.ip tuple_gen.port can be used "ip_min" : 0x10000001, # min ip 16.0.0.1 "ip_max" : 0x100000fe, # max ip 16.0.0.254 "port_min" : 1025, # min port 1025 "port_max" : 65500, # max port 65500 "limit_flows" : 1000000, # number of flows "flags" : 0, # 1 - for unlimited }, { "type" : "write_flow_var", # command name "name" : "tuple_gen.ip", # varible to write "add_value" : 0, # no need to add value "is_big_endian" : true, # write as big edian "pkt_offset" : 26, # write tuple_gen.ip into ipv4.src_ip }, { "type" : "fix_checksum_ipv4", # fix ipv4 header checksum "pkt_offset" : 14, # offset of ipv4 header }, { "type" : "write_flow_var", # command name "name" : "tuple_gen.port", # varible to write "add_value" : 0, # no need to add value "is_big_endian" : true, # write as big edian "pkt_offset" : 34, # write tuple_gen.port into udp.src_port } ] ----