trex_rpc_cmd_stream.cpp revision f6d11f9e
1/*
2 Itay Marom, Dan Klein
3 Cisco Systems, Inc.
4*/
5
6/*
7Copyright (c) 2015-2015 Cisco Systems, Inc.
8
9Licensed under the Apache License, Version 2.0 (the "License");
10you may not use this file except in compliance with the License.
11You may obtain a copy of the License at
12
13    http://www.apache.org/licenses/LICENSE-2.0
14
15Unless required by applicable law or agreed to in writing, software
16distributed under the License is distributed on an "AS IS" BASIS,
17WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18See the License for the specific language governing permissions and
19limitations under the License.
20*/
21#include "trex_rpc_cmds.h"
22#include <trex_rpc_server_api.h>
23#include <trex_stream.h>
24#include <trex_stateless.h>
25#include <trex_stateless_port.h>
26#include <trex_streams_compiler.h>
27#include <common/base64.h>
28#include <iostream>
29#include <memory>
30
31using namespace std;
32
33
34/***************************
35 * add new stream
36 *
37 **************************/
38trex_rpc_cmd_rc_e
39TrexRpcCmdAddStream::_run(const Json::Value &params, Json::Value &result) {
40
41    uint8_t port_id = parse_port(params, result);
42
43    uint32_t stream_id  = parse_int(params, "stream_id", result);
44
45    const Json::Value &section = parse_object(params, "stream", result);
46
47    /* get the type of the stream */
48    const Json::Value &mode = parse_object(section, "mode", result);
49    string type = parse_string(mode, "type", result);
50
51    /* allocate a new stream based on the type */
52    std::unique_ptr<TrexStream> stream = allocate_new_stream(section, port_id, stream_id, result);
53
54    /* save this for future queries */
55    stream->store_stream_json(section);
56
57    /* some fields */
58    stream->m_enabled         = parse_bool(section, "enabled", result);
59    stream->m_self_start      = parse_bool(section, "self_start", result);
60    stream->m_flags           = parse_int(section, "flags", result);
61    stream->m_action_count    = parse_uint16(section, "action_count", result);
62    stream->m_random_seed     = parse_uint32(section, "random_seed", result,0); /* default is zero */
63
64    /* inter stream gap */
65    stream->m_isg_usec  = parse_double(section, "isg", result);
66
67    stream->m_next_stream_id = parse_int(section, "next_stream_id", result);
68
69    const Json::Value &pkt = parse_object(section, "packet", result);
70    std::string pkt_binary = base64_decode(parse_string(pkt, "binary", result));
71
72    /* check packet size */
73    if ( (pkt_binary.size() < TrexStream::MIN_PKT_SIZE_BYTES) || (pkt_binary.size() > TrexStream::MAX_PKT_SIZE_BYTES) ) {
74        std::stringstream ss;
75        ss << "bad packet size provided: should be between " << TrexStream::MIN_PKT_SIZE_BYTES << " and " << TrexStream::MAX_PKT_SIZE_BYTES;
76        generate_execute_err(result, ss.str());
77    }
78
79    /* fetch the packet from the message */
80
81    stream->m_pkt.len    = std::max(pkt_binary.size(), 60UL);
82
83    /* allocate and init to zero ( with () ) */
84    stream->m_pkt.binary = new uint8_t[stream->m_pkt.len]();
85    if (!stream->m_pkt.binary) {
86        generate_internal_err(result, "unable to allocate memory");
87    }
88
89    const char *pkt_buffer = pkt_binary.c_str();
90
91    /* copy the packet - if less than 60 it will remain zeroes */
92    for (int i = 0; i < pkt_binary.size(); i++) {
93        stream->m_pkt.binary[i] = pkt_buffer[i];
94    }
95
96    /* meta data */
97    stream->m_pkt.meta = parse_string(pkt, "meta", result);
98
99    /* parse VM */
100    const Json::Value &vm =  parse_object(section ,"vm", result);
101    parse_vm(vm, stream, result);
102
103    /* parse RX info */
104    const Json::Value &rx = parse_object(section, "flow_stats", result);
105
106    stream->m_rx_check.m_enabled = parse_bool(rx, "enabled", result);
107
108    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(stream->m_port_id);
109
110    /* if it is enabled - we need more fields */
111    if (stream->m_rx_check.m_enabled) {
112
113        if (port->get_rx_caps() == 0) {
114            generate_parse_err(result, "RX stats is not supported on this interface");
115        }
116
117        stream->m_rx_check.m_pg_id      = parse_int(rx, "stream_id", result);
118        std::string type = parse_string(rx, "rule_type", result);
119        if (type == "latency") {
120            stream->m_rx_check.m_rule_type = TrexPlatformApi::IF_STAT_PAYLOAD;
121        } else {
122            stream->m_rx_check.m_rule_type = TrexPlatformApi::IF_STAT_IPV4_ID;
123        }
124    }
125
126    /* make sure this is a valid stream to add */
127    validate_stream(stream, result);
128
129    try {
130        port->add_stream(stream.get());
131        stream.release();
132    } catch (const TrexException &ex) {
133        generate_execute_err(result, ex.what());
134    }
135
136    result["result"] = Json::objectValue;
137
138    return (TREX_RPC_CMD_OK);
139}
140
141
142
143std::unique_ptr<TrexStream>
144TrexRpcCmdAddStream::allocate_new_stream(const Json::Value &section, uint8_t port_id, uint32_t stream_id, Json::Value &result) {
145
146    std::unique_ptr<TrexStream> stream;
147
148    const Json::Value &mode = parse_object(section, "mode", result);
149    std::string type = parse_string(mode, "type", result);
150
151
152    if (type == "continuous") {
153
154        stream.reset(new TrexStream( TrexStream::stCONTINUOUS, port_id, stream_id));
155
156    } else if (type == "single_burst") {
157
158        uint32_t total_pkts      = parse_int(mode, "total_pkts", result);
159
160        stream.reset(new TrexStream(TrexStream::stSINGLE_BURST, port_id, stream_id));
161        stream->set_single_burst(total_pkts);
162
163
164    } else if (type == "multi_burst") {
165
166        double    ibg_usec         = parse_double(mode, "ibg", result);
167        uint32_t  num_bursts       = parse_int(mode, "count", result);
168        uint32_t  pkts_per_burst   = parse_int(mode, "pkts_per_burst", result);
169
170        stream.reset(new TrexStream(TrexStream::stMULTI_BURST,port_id, stream_id ));
171        stream->set_multi_burst(pkts_per_burst,num_bursts,ibg_usec);
172
173
174    } else {
175        generate_parse_err(result, "bad stream type provided: '" + type + "'");
176    }
177
178     /* parse the rate of the stream */
179    const Json::Value &rate =  parse_object(mode ,"rate", result);
180    parse_rate(rate, stream, result);
181
182    return (stream);
183
184}
185
186void
187TrexRpcCmdAddStream::parse_rate(const Json::Value &rate, std::unique_ptr<TrexStream> &stream, Json::Value &result) {
188
189    double value = parse_double(rate, "value", result);
190    if (value <= 0) {
191        std::stringstream ss;
192        ss << "rate value must be a positive number - got: '" << value << "'";
193        generate_parse_err(result, ss.str());
194    }
195
196    auto rate_types = {"pps", "bps_L1", "bps_L2", "percentage"};
197    std::string rate_type = parse_choice(rate, "type", rate_types, result);
198
199    if (rate_type == "pps") {
200        stream->set_rate(TrexStreamRate::RATE_PPS, value);
201    } else if (rate_type == "bps_L1") {
202        stream->set_rate(TrexStreamRate::RATE_BPS_L1, value);
203    } else if (rate_type == "bps_L2") {
204        stream->set_rate(TrexStreamRate::RATE_BPS_L2, value);
205    } else if (rate_type == "percentage") {
206        stream->set_rate(TrexStreamRate::RATE_PERCENTAGE, value);
207    } else {
208        /* impossible */
209        assert(0);
210    }
211
212}
213
214void
215TrexRpcCmdAddStream::parse_vm_instr_checksum(const Json::Value &inst, std::unique_ptr<TrexStream> &stream, Json::Value &result) {
216
217    uint16_t pkt_offset = parse_uint16(inst, "pkt_offset", result);
218    stream->m_vm.add_instruction(new StreamVmInstructionFixChecksumIpv4(pkt_offset));
219}
220
221
222void
223TrexRpcCmdAddStream::parse_vm_instr_trim_pkt_size(const Json::Value &inst, std::unique_ptr<TrexStream> &stream, Json::Value &result){
224
225    std::string  flow_var_name = parse_string(inst, "name", result);
226
227    stream->m_vm.add_instruction(new StreamVmInstructionChangePktSize(flow_var_name));
228}
229
230
231void
232TrexRpcCmdAddStream::parse_vm_instr_tuple_flow_var(const Json::Value &inst, std::unique_ptr<TrexStream> &stream, Json::Value &result){
233
234
235    std::string  flow_var_name = parse_string(inst, "name", result);
236
237    uint32_t ip_min       = parse_uint32(inst, "ip_min", result);
238    uint32_t ip_max       = parse_uint32(inst, "ip_max", result);
239    uint16_t port_min     = parse_uint16(inst, "port_min", result);
240    uint16_t port_max     = parse_uint16(inst, "port_max", result);
241    uint32_t limit_flows  = parse_uint32(inst, "limit_flows", result);
242    uint16_t flags        = parse_uint16(inst, "flags", result);
243
244    /* archiecture limitation - limit_flows must be greater or equal to DP core count */
245    if (limit_flows < get_stateless_obj()->get_dp_core_count()) {
246        std::stringstream ss;
247        ss << "cannot limit flows to less than " << (uint32_t)get_stateless_obj()->get_dp_core_count();
248        generate_execute_err(result, ss.str());
249    }
250
251    stream->m_vm.add_instruction(new StreamVmInstructionFlowClient(flow_var_name,
252                                                                   ip_min,
253                                                                   ip_max,
254                                                                   port_min,
255                                                                   port_max,
256                                                                   limit_flows,
257                                                                   flags
258                                                                   ));
259}
260
261
262/**
263 * if a user specify min_value and max_value with a step
264 * that does not create a full cycle - pad the values to allow
265 * a true cycle
266 *
267 */
268void
269TrexRpcCmdAddStream::handle_range_padding(uint64_t &max_value,
270                                          uint64_t &min_value,
271                                          uint64_t step,
272                                          int op,
273                                          Json::Value &result) {
274
275    /* pad for the step */
276    uint64_t pad = (max_value - min_value + 1) % step;
277    if (pad == 0) {
278        return;
279    }
280
281    /* the leftover rounded up */
282    uint64_t step_pad = step - pad;
283
284    switch (op) {
285    case StreamVmInstructionFlowMan::FLOW_VAR_OP_INC:
286
287        if ( (UINT64_MAX - max_value) < step_pad ) {
288            generate_parse_err(result, "VM: could not pad range to be a true cycle - '(max_value - min_value + 1) % step' should be zero");
289        }
290        max_value += step_pad;
291
292        break;
293
294    case StreamVmInstructionFlowMan::FLOW_VAR_OP_DEC:
295        if ( min_value < step_pad ) {
296            generate_parse_err(result, "VM: could not pad range to be a true cycle - '(max_value - min_value + 1) % step' should be zero");
297        }
298        min_value -= step_pad;
299
300        break;
301
302    default:
303        break;
304    }
305}
306
307void
308TrexRpcCmdAddStream::check_min_max(uint8_t flow_var_size,
309                                   uint64_t init_value,
310                                   uint64_t step,
311                                   uint64_t min_value,
312                                   uint64_t max_value,
313                                   Json::Value &result){
314
315    if (step == 0) {
316        generate_parse_err(result, "VM: step cannot be 0");
317    }
318
319    if (max_value < min_value ) {
320        std::stringstream ss;
321        ss << "VM: request flow var variable '" << max_value << "' is smaller than " << min_value;
322        generate_parse_err(result, ss.str());
323    }
324
325    if (flow_var_size == 1 ) {
326        if ( (init_value > UINT8_MAX) || (min_value > UINT8_MAX) || (max_value > UINT8_MAX) || (step >UINT8_MAX) )  {
327            std::stringstream ss;
328            ss << "VM: request val is bigger than " << UINT8_MAX;
329            generate_parse_err(result, ss.str());
330        }
331    }
332
333    if (flow_var_size == 2 ) {
334        if ( (init_value > UINT16_MAX) || (min_value > UINT16_MAX) || (max_value > UINT16_MAX) || (step > UINT16_MAX) )  {
335            std::stringstream ss;
336            ss << "VM: request val is bigger than " << UINT16_MAX;
337            generate_parse_err(result, ss.str());
338        }
339    }
340
341    if (flow_var_size == 4 ) {
342        if ( (init_value > UINT32_MAX) || (min_value > UINT32_MAX) || (max_value > UINT32_MAX) || (step > UINT32_MAX) )  {
343            std::stringstream ss;
344            ss << "VM: request val is bigger than " << UINT32_MAX;
345            generate_parse_err(result, ss.str());
346        }
347    }
348
349}
350
351void
352TrexRpcCmdAddStream::parse_vm_instr_flow_var_rand_limit(const Json::Value &inst, std::unique_ptr<TrexStream> &stream, Json::Value &result) {
353    std::string  flow_var_name = parse_string(inst, "name", result);
354
355    auto sizes = {1, 2, 4, 8};
356    uint8_t      flow_var_size = parse_choice(inst, "size", sizes, result);
357    uint64_t seed    = parse_uint64(inst, "seed", result);
358    uint64_t limit   = parse_uint64(inst, "limit", result);
359    uint64_t min_value   = parse_uint64(inst, "min_value", result);
360    uint64_t max_value   = parse_uint64(inst, "max_value", result);
361
362    if (limit < 1 ) {
363        std::stringstream ss;
364        ss << "VM: request random flow var variable with limit of zero '";
365        generate_parse_err(result, ss.str());
366    }
367
368    check_min_max(flow_var_size, 0, 1, min_value, max_value, result);
369
370    stream->m_vm.add_instruction(new StreamVmInstructionFlowRandLimit(flow_var_name,
371                                                                      flow_var_size,
372                                                                      limit,
373                                                                      min_value,
374                                                                      max_value,
375                                                                      seed)
376                                 );
377}
378
379void
380TrexRpcCmdAddStream::parse_vm_instr_flow_var(const Json::Value &inst, std::unique_ptr<TrexStream> &stream, Json::Value &result) {
381    std::string  flow_var_name = parse_string(inst, "name", result);
382
383    auto sizes = {1, 2, 4, 8};
384    uint8_t      flow_var_size = parse_choice(inst, "size", sizes, result);
385
386    auto ops = {"inc", "dec", "random"};
387    std::string  op_type_str = parse_choice(inst, "op", ops, result);
388
389    StreamVmInstructionFlowMan::flow_var_op_e op_type;
390
391    if (op_type_str == "inc") {
392        op_type = StreamVmInstructionFlowMan::FLOW_VAR_OP_INC;
393    } else if (op_type_str == "dec") {
394        op_type = StreamVmInstructionFlowMan::FLOW_VAR_OP_DEC;
395    } else if (op_type_str == "random") {
396        op_type = StreamVmInstructionFlowMan::FLOW_VAR_OP_RANDOM;
397    } else {
398        throw TrexRpcException("internal error");
399    }
400
401    uint64_t init_value  = parse_uint64(inst, "init_value", result);
402    uint64_t min_value   = parse_uint64(inst, "min_value", result);
403    uint64_t max_value   = parse_uint64(inst, "max_value", result);
404    uint64_t step        = parse_uint64(inst, "step", result);
405
406    check_min_max(flow_var_size, init_value, step, min_value, max_value, result);
407
408    /* implicit range padding if possible */
409    handle_range_padding(max_value,min_value,step, op_type, result);
410
411    stream->m_vm.add_instruction(new StreamVmInstructionFlowMan(flow_var_name,
412                                                                flow_var_size,
413                                                                op_type,
414                                                                init_value,
415                                                                min_value,
416                                                                max_value,
417                                                                step)
418                                 );
419}
420
421
422void
423TrexRpcCmdAddStream::parse_vm_instr_write_mask_flow_var(const Json::Value &inst, std::unique_ptr<TrexStream> &stream, Json::Value &result) {
424    std::string  flow_var_name = parse_string(inst, "name", result);
425    uint16_t     pkt_offset    = parse_uint16(inst, "pkt_offset", result);
426    uint16_t      pkt_cast_size = parse_uint16(inst, "pkt_cast_size", result);
427    uint32_t     mask          = parse_uint32(inst, "mask", result);
428    int          shift         = parse_int(inst, "shift", result);
429    int          add_value     = parse_int(inst, "add_value", result);
430    bool         is_big_endian = parse_bool(inst,   "is_big_endian", result);
431
432    stream->m_vm.add_instruction(new StreamVmInstructionWriteMaskToPkt(flow_var_name,
433                                                                       pkt_offset,
434                                                                       (uint8_t)pkt_cast_size,
435                                                                       mask,
436                                                                       shift,
437                                                                       add_value,
438                                                                       is_big_endian));
439}
440
441
442void
443TrexRpcCmdAddStream::parse_vm_instr_write_flow_var(const Json::Value &inst, std::unique_ptr<TrexStream> &stream, Json::Value &result) {
444    std::string  flow_var_name = parse_string(inst, "name", result);
445    uint16_t     pkt_offset    = parse_uint16(inst, "pkt_offset", result);
446    int          add_value     = parse_int(inst,    "add_value", result);
447    bool         is_big_endian = parse_bool(inst,   "is_big_endian", result);
448
449    stream->m_vm.add_instruction(new StreamVmInstructionWriteToPkt(flow_var_name,
450                                                                   pkt_offset,
451                                                                   add_value,
452                                                                   is_big_endian));
453}
454
455void
456TrexRpcCmdAddStream::parse_vm(const Json::Value &vm, std::unique_ptr<TrexStream> &stream, Json::Value &result) {
457
458    const Json::Value &instructions =  parse_array(vm ,"instructions", result);
459
460    /* array of VM instructions on vm */
461    for (int i = 0; i < instructions.size(); i++) {
462        const Json::Value & inst = parse_object(instructions, i, result);
463
464        auto vm_types = {"fix_checksum_ipv4", "flow_var", "write_flow_var","tuple_flow_var","trim_pkt_size","write_mask_flow_var","flow_var_rand_limit"};
465        std::string vm_type = parse_choice(inst, "type", vm_types, result);
466
467        // checksum instruction
468        if (vm_type == "fix_checksum_ipv4") {
469            parse_vm_instr_checksum(inst, stream, result);
470
471        } else if (vm_type == "flow_var") {
472            parse_vm_instr_flow_var(inst, stream, result);
473
474        } else if (vm_type == "flow_var_rand_limit") {
475            parse_vm_instr_flow_var_rand_limit(inst, stream, result);
476
477        } else if (vm_type == "write_flow_var") {
478            parse_vm_instr_write_flow_var(inst, stream, result);
479
480        } else if (vm_type == "tuple_flow_var") {
481           parse_vm_instr_tuple_flow_var(inst, stream, result);
482
483        } else if (vm_type == "trim_pkt_size") {
484            parse_vm_instr_trim_pkt_size(inst, stream, result);
485        }else if (vm_type == "write_mask_flow_var") {
486            parse_vm_instr_write_mask_flow_var(inst, stream, result);
487        } else {
488            /* internal error */
489            throw TrexRpcException("internal error");
490        }
491    }
492
493    stream->m_cache_size      = parse_uint16(vm, "cache", result,0); /* default is zero */
494
495}
496
497void
498TrexRpcCmdAddStream::validate_stream(const std::unique_ptr<TrexStream> &stream, Json::Value &result) {
499
500    /* add the stream to the port's stream table */
501    TrexStatelessPort * port = get_stateless_obj()->get_port_by_id(stream->m_port_id);
502
503    /* does such a stream exists ? */
504    if (port->get_stream_by_id(stream->m_stream_id)) {
505        std::stringstream ss;
506        ss << "stream " << stream->m_stream_id << " already exists";
507        generate_execute_err(result, ss.str());
508    }
509
510}
511
512/***************************
513 * remove stream
514 *
515 **************************/
516trex_rpc_cmd_rc_e
517TrexRpcCmdRemoveStream::_run(const Json::Value &params, Json::Value &result) {
518
519    uint8_t port_id = parse_port(params, result);
520    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
521
522    uint32_t stream_id = parse_int(params, "stream_id", result);
523    TrexStream *stream = port->get_stream_by_id(stream_id);
524
525    if (!stream) {
526        std::stringstream ss;
527        ss << "stream " << stream_id << " does not exists";
528        generate_execute_err(result, ss.str());
529    }
530
531    try {
532        port->remove_stream(stream);
533    } catch (const TrexException &ex) {
534        generate_execute_err(result, ex.what());
535    }
536
537    delete stream;
538
539    result["result"] = Json::objectValue;
540
541    return (TREX_RPC_CMD_OK);
542}
543
544/***************************
545 * remove all streams
546 * for a port
547 *
548 **************************/
549trex_rpc_cmd_rc_e
550TrexRpcCmdRemoveAllStreams::_run(const Json::Value &params, Json::Value &result) {
551
552    uint8_t port_id = parse_port(params, result);
553    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
554
555    try {
556        port->remove_and_delete_all_streams();
557    } catch (const TrexException &ex) {
558        generate_execute_err(result, ex.what());
559    }
560
561
562    result["result"] = Json::objectValue;
563
564    return (TREX_RPC_CMD_OK);
565}
566
567/***************************
568 * get all streams configured
569 * on a specific port
570 *
571 **************************/
572trex_rpc_cmd_rc_e
573TrexRpcCmdGetStreamList::_run(const Json::Value &params, Json::Value &result) {
574    std::vector<uint32_t> stream_list;
575
576    uint8_t port_id = parse_port(params, result);
577    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
578
579    port->get_id_list(stream_list);
580
581    Json::Value json_list = Json::arrayValue;
582
583    for (auto stream_id : stream_list) {
584        json_list.append(stream_id);
585    }
586
587    result["result"] = json_list;
588
589    return (TREX_RPC_CMD_OK);
590}
591
592/***************************
593 * get stream by id
594 * on a specific port
595 *
596 **************************/
597trex_rpc_cmd_rc_e
598TrexRpcCmdGetStream::_run(const Json::Value &params, Json::Value &result) {
599
600    uint8_t port_id = parse_port(params, result);
601    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
602
603    bool     get_pkt   = parse_bool(params, "get_pkt", result);
604    uint32_t stream_id = parse_int(params, "stream_id", result);
605
606    TrexStream *stream = port->get_stream_by_id(stream_id);
607
608    if (!stream) {
609        std::stringstream ss;
610        ss << "stream id " << stream_id << " on port " << (int)port_id << " does not exists";
611        generate_execute_err(result, ss.str());
612    }
613
614    /* return the stored stream json (instead of decoding it all over again) */
615    Json::Value j = stream->get_stream_json();
616    if (!get_pkt) {
617        j.removeMember("packet");
618    }
619
620    result["result"]["stream"] = j;
621
622    return (TREX_RPC_CMD_OK);
623
624}
625
626/***************************
627 * start traffic on port
628 *
629 **************************/
630trex_rpc_cmd_rc_e
631TrexRpcCmdStartTraffic::_run(const Json::Value &params, Json::Value &result) {
632
633    uint8_t port_id = parse_port(params, result);
634    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
635
636    double    duration    = parse_double(params, "duration", result);
637    bool      force       = parse_bool(params, "force", result);
638    uint64_t  core_mask   = parse_uint64(params, "core_mask", result, TrexDPCoreMask::MASK_ALL);
639
640    if (!TrexDPCoreMask::is_valid_mask(port->get_dp_core_count(), core_mask)) {
641        generate_parse_err(result, "invalid core mask provided");
642    }
643
644    /* multiplier */
645    const Json::Value &mul_obj  = parse_object(params, "mul", result);
646
647    std::string type   = parse_choice(mul_obj, "type", TrexPortMultiplier::g_types, result);
648    std::string op     = parse_string(mul_obj, "op", result);
649    double      value  = parse_double(mul_obj, "value", result);
650
651    if ( value <=0 ){
652        generate_parse_err(result, "multiplier can't be zero");
653    }
654
655    if (op != "abs") {
656        generate_parse_err(result, "start message can only specify absolute speed rate");
657    }
658
659    TrexPortMultiplier mul(type, op, value);
660
661    try {
662        port->start_traffic(mul, duration, force, core_mask);
663
664    } catch (const TrexException &ex) {
665        generate_execute_err(result, ex.what());
666    }
667
668    result["result"]["multiplier"] = port->get_multiplier();
669
670    return (TREX_RPC_CMD_OK);
671}
672
673/***************************
674 * stop traffic on port
675 *
676 **************************/
677trex_rpc_cmd_rc_e
678TrexRpcCmdStopTraffic::_run(const Json::Value &params, Json::Value &result) {
679
680    uint8_t port_id = parse_port(params, result);
681    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
682
683    try {
684        port->stop_traffic();
685    } catch (const TrexException &ex) {
686        generate_execute_err(result, ex.what());
687    }
688
689    result["result"] = Json::objectValue;
690
691    return (TREX_RPC_CMD_OK);
692}
693
694/***************************
695 * remove all hardware filters
696 *
697 **************************/
698trex_rpc_cmd_rc_e
699TrexRpcCmdRemoveRXFilters::_run(const Json::Value &params, Json::Value &result) {
700
701    uint8_t port_id = parse_port(params, result);
702    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
703
704    try {
705        port->remove_rx_filters();
706    } catch (const TrexException &ex) {
707        generate_execute_err(result, ex.what());
708    }
709
710    result["result"] = Json::objectValue;
711
712    return (TREX_RPC_CMD_OK);
713}
714
715/***************************
716 * get all streams
717 *
718 **************************/
719trex_rpc_cmd_rc_e
720TrexRpcCmdGetAllStreams::_run(const Json::Value &params, Json::Value &result) {
721
722    uint8_t port_id = parse_port(params, result);
723    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
724
725    std::vector <TrexStream *> streams;
726    port->get_object_list(streams);
727
728    Json::Value streams_json = Json::objectValue;
729    for (auto stream : streams) {
730
731        Json::Value j = stream->get_stream_json();
732
733        std::stringstream ss;
734        ss << stream->m_stream_id;
735
736        streams_json[ss.str()] = j;
737    }
738
739    result["result"]["streams"] = streams_json;
740
741    return (TREX_RPC_CMD_OK);
742}
743
744/***************************
745 * pause traffic
746 *
747 **************************/
748trex_rpc_cmd_rc_e
749TrexRpcCmdPauseTraffic::_run(const Json::Value &params, Json::Value &result) {
750
751    uint8_t port_id = parse_port(params, result);
752    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
753
754     try {
755        port->pause_traffic();
756    } catch (const TrexException &ex) {
757        generate_execute_err(result, ex.what());
758    }
759
760    result["result"] = Json::objectValue;
761
762    return (TREX_RPC_CMD_OK);
763}
764
765/***************************
766 * resume traffic
767 *
768 **************************/
769trex_rpc_cmd_rc_e
770TrexRpcCmdResumeTraffic::_run(const Json::Value &params, Json::Value &result) {
771
772    uint8_t port_id = parse_port(params, result);
773    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
774
775     try {
776        port->resume_traffic();
777    } catch (const TrexException &ex) {
778        generate_execute_err(result, ex.what());
779    }
780
781    result["result"] = Json::objectValue;
782
783    return (TREX_RPC_CMD_OK);
784}
785
786/***************************
787 * update traffic
788 *
789 **************************/
790trex_rpc_cmd_rc_e
791TrexRpcCmdUpdateTraffic::_run(const Json::Value &params, Json::Value &result) {
792
793    uint8_t port_id = parse_port(params, result);
794    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
795
796    bool force = parse_bool(params, "force", result);
797
798    /* multiplier */
799
800    const Json::Value &mul_obj  = parse_object(params, "mul", result);
801
802    std::string type   = parse_choice(mul_obj, "type", TrexPortMultiplier::g_types, result);
803    std::string op     = parse_choice(mul_obj, "op", TrexPortMultiplier::g_ops, result);
804    double      value  = parse_double(mul_obj, "value", result);
805
806    TrexPortMultiplier mul(type, op, value);
807
808
809    try {
810        port->update_traffic(mul, force);
811    } catch (const TrexException &ex) {
812        generate_execute_err(result, ex.what());
813    }
814
815    result["result"]["multiplier"] = port->get_multiplier();
816
817    return (TREX_RPC_CMD_OK);
818}
819
820/***************************
821 * validate
822 *
823 * checks that the port
824 * attached streams are
825 * valid as a program
826 **************************/
827trex_rpc_cmd_rc_e
828TrexRpcCmdValidate::_run(const Json::Value &params, Json::Value &result) {
829    uint8_t port_id = parse_port(params, result);
830    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
831
832    const TrexStreamsGraphObj *graph = NULL;
833
834    try {
835        graph = port->validate();
836    }
837    catch (const TrexException &ex) {
838        generate_execute_err(result, ex.what());
839    }
840
841    /* max values */
842    result["result"]["rate"]["max_bps_l2"]    = graph->get_max_bps_l2();
843    result["result"]["rate"]["max_bps_l1"]    = graph->get_max_bps_l1();
844    result["result"]["rate"]["max_pps"]       = graph->get_max_pps();
845    result["result"]["rate"]["max_line_util"] = (graph->get_max_bps_l1() / port->get_port_speed_bps()) * 100.0;
846
847    /* min values */
848    result["result"]["rate"]["min_bps_l2"]    = graph->get_max_bps_l2(0);
849    result["result"]["rate"]["min_bps_l1"]    = graph->get_max_bps_l1(0);
850    result["result"]["rate"]["min_pps"]       = graph->get_max_pps(0);
851    result["result"]["rate"]["min_line_util"] = (graph->get_max_bps_l1(0) / port->get_port_speed_bps()) * 100.0;
852
853    result["result"]["graph"]["expected_duration"] = graph->get_duration();
854    result["result"]["graph"]["events_count"] = (int)graph->get_events().size();
855
856    result["result"]["graph"]["events"] = Json::arrayValue;
857    Json::Value &events_json = result["result"]["graph"]["events"];
858
859    int index = 0;
860    for (const auto &ev : graph->get_events()) {
861        Json::Value ev_json;
862
863        ev_json["time_usec"]     = ev.time;
864        ev_json["diff_bps_l2"]   = ev.diff_bps_l2;
865        ev_json["diff_bps_l1"]   = ev.diff_bps_l1;
866        ev_json["diff_pps"]      = ev.diff_pps;
867        ev_json["stream_id"]     = ev.stream_id;
868
869        events_json.append(ev_json);
870
871        index++;
872        if (index >= 100) {
873            break;
874        }
875    }
876
877
878    return (TREX_RPC_CMD_OK);
879}
880