trex_rpc_cmd_stream.cpp revision fa606839
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_uint32(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_udouble(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: " << pkt_binary.size() <<  ". 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_uint32(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_uint32(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_udouble(mode, "ibg", result);
167        uint32_t  num_bursts       = parse_uint32(mode, "count", result);
168        uint32_t  pkts_per_burst   = parse_uint32(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_udouble(rate, "value", result);
190
191    auto rate_types = {"pps", "bps_L1", "bps_L2", "percentage"};
192    std::string rate_type = parse_choice(rate, "type", rate_types, result);
193
194    if (rate_type == "pps") {
195        stream->set_rate(TrexStreamRate::RATE_PPS, value);
196    } else if (rate_type == "bps_L1") {
197        stream->set_rate(TrexStreamRate::RATE_BPS_L1, value);
198    } else if (rate_type == "bps_L2") {
199        stream->set_rate(TrexStreamRate::RATE_BPS_L2, value);
200    } else if (rate_type == "percentage") {
201        stream->set_rate(TrexStreamRate::RATE_PERCENTAGE, value);
202    } else {
203        /* impossible */
204        assert(0);
205    }
206
207}
208
209void
210TrexRpcCmdAddStream::parse_vm_instr_checksum_hw(const Json::Value &inst, std::unique_ptr<TrexStream> &stream, Json::Value &result) {
211    uint16_t l2_len = parse_uint16(inst, "l2_len", result);
212    uint16_t l3_len = parse_uint16(inst, "l3_len", result);
213    uint16_t l4_type = parse_uint16(inst, "l4_type", result);
214
215    stream->m_vm.add_instruction(new StreamVmInstructionFixHwChecksum(l2_len,l3_len,l4_type));
216}
217
218void
219TrexRpcCmdAddStream::parse_vm_instr_checksum(const Json::Value &inst, std::unique_ptr<TrexStream> &stream, Json::Value &result) {
220
221    uint16_t pkt_offset = parse_uint16(inst, "pkt_offset", result);
222    stream->m_vm.add_instruction(new StreamVmInstructionFixChecksumIpv4(pkt_offset));
223}
224
225
226void
227TrexRpcCmdAddStream::parse_vm_instr_trim_pkt_size(const Json::Value &inst, std::unique_ptr<TrexStream> &stream, Json::Value &result){
228
229    std::string  flow_var_name = parse_string(inst, "name", result);
230
231    stream->m_vm.add_instruction(new StreamVmInstructionChangePktSize(flow_var_name));
232}
233
234
235void
236TrexRpcCmdAddStream::parse_vm_instr_tuple_flow_var(const Json::Value &inst, std::unique_ptr<TrexStream> &stream, Json::Value &result){
237
238
239    std::string  flow_var_name = parse_string(inst, "name", result);
240
241    uint32_t ip_min       = parse_uint32(inst, "ip_min", result);
242    uint32_t ip_max       = parse_uint32(inst, "ip_max", result);
243    uint16_t port_min     = parse_uint16(inst, "port_min", result);
244    uint16_t port_max     = parse_uint16(inst, "port_max", result);
245    uint32_t limit_flows  = parse_uint32(inst, "limit_flows", result);
246    uint16_t flags        = parse_uint16(inst, "flags", result);
247
248    /* archiecture limitation - limit_flows must be greater or equal to DP core count */
249    if (limit_flows < get_stateless_obj()->get_dp_core_count()) {
250        std::stringstream ss;
251        ss << "cannot limit flows to less than " << (uint32_t)get_stateless_obj()->get_dp_core_count();
252        generate_execute_err(result, ss.str());
253    }
254
255    stream->m_vm.add_instruction(new StreamVmInstructionFlowClient(flow_var_name,
256                                                                   ip_min,
257                                                                   ip_max,
258                                                                   port_min,
259                                                                   port_max,
260                                                                   limit_flows,
261                                                                   flags
262                                                                   ));
263}
264
265
266/**
267 * if a user specify min_value and max_value with a step
268 * that does not create a full cycle - pad the values to allow
269 * a true cycle
270 *
271 */
272void
273TrexRpcCmdAddStream::handle_range_padding(uint64_t &max_value,
274                                          uint64_t &min_value,
275                                          uint64_t step,
276                                          int op,
277                                          Json::Value &result) {
278
279    /* pad for the step */
280    uint64_t pad = (max_value - min_value + 1) % step;
281    if (pad == 0) {
282        return;
283    }
284
285    /* the leftover rounded up */
286    uint64_t step_pad = step - pad;
287
288    switch (op) {
289    case StreamVmInstructionFlowMan::FLOW_VAR_OP_INC:
290
291        if ( (UINT64_MAX - max_value) < step_pad ) {
292            generate_parse_err(result, "VM: could not pad range to be a true cycle - '(max_value - min_value + 1) % step' should be zero");
293        }
294        max_value += step_pad;
295
296        break;
297
298    case StreamVmInstructionFlowMan::FLOW_VAR_OP_DEC:
299        if ( min_value < step_pad ) {
300            generate_parse_err(result, "VM: could not pad range to be a true cycle - '(max_value - min_value + 1) % step' should be zero");
301        }
302        min_value -= step_pad;
303
304        break;
305
306    default:
307        break;
308    }
309}
310
311void
312TrexRpcCmdAddStream::check_min_max(uint8_t flow_var_size,
313                                   uint64_t init_value,
314                                   uint64_t step,
315                                   uint64_t min_value,
316                                   uint64_t max_value,
317                                   Json::Value &result){
318
319    if (step == 0) {
320        generate_parse_err(result, "VM: step cannot be 0");
321    }
322
323    if (max_value < min_value ) {
324        std::stringstream ss;
325        ss << "VM: request flow var variable '" << max_value << "' is smaller than " << min_value;
326        generate_parse_err(result, ss.str());
327    }
328
329    if (flow_var_size == 1 ) {
330        if ( (init_value > UINT8_MAX) || (min_value > UINT8_MAX) || (max_value > UINT8_MAX) || (step >UINT8_MAX) )  {
331            std::stringstream ss;
332            ss << "VM: request val is bigger than " << UINT8_MAX;
333            generate_parse_err(result, ss.str());
334        }
335    }
336
337    if (flow_var_size == 2 ) {
338        if ( (init_value > UINT16_MAX) || (min_value > UINT16_MAX) || (max_value > UINT16_MAX) || (step > UINT16_MAX) )  {
339            std::stringstream ss;
340            ss << "VM: request val is bigger than " << UINT16_MAX;
341            generate_parse_err(result, ss.str());
342        }
343    }
344
345    if (flow_var_size == 4 ) {
346        if ( (init_value > UINT32_MAX) || (min_value > UINT32_MAX) || (max_value > UINT32_MAX) || (step > UINT32_MAX) )  {
347            std::stringstream ss;
348            ss << "VM: request val is bigger than " << UINT32_MAX;
349            generate_parse_err(result, ss.str());
350        }
351    }
352
353}
354
355void
356TrexRpcCmdAddStream::parse_vm_instr_flow_var_rand_limit(const Json::Value &inst, std::unique_ptr<TrexStream> &stream, Json::Value &result) {
357    std::string  flow_var_name = parse_string(inst, "name", result);
358
359    auto sizes = {1, 2, 4, 8};
360    uint8_t      flow_var_size = parse_choice(inst, "size", sizes, result);
361    uint64_t seed    = parse_uint64(inst, "seed", result);
362    uint64_t limit   = parse_uint64(inst, "limit", result);
363    uint64_t min_value   = parse_uint64(inst, "min_value", result);
364    uint64_t max_value   = parse_uint64(inst, "max_value", result);
365
366	/* archiecture limitation - limit_flows must be greater or equal to DP core count */
367	if (limit < 1) {
368		std::stringstream ss;
369        ss << "VM: request random flow var variable with limit of zero '";
370		generate_parse_err(result, ss.str());
371	}
372
373    check_min_max(flow_var_size, 0, 1, min_value, max_value, result);
374
375    stream->m_vm.add_instruction(new StreamVmInstructionFlowRandLimit(flow_var_name,
376                                                                      flow_var_size,
377                                                                      limit,
378                                                                      min_value,
379                                                                      max_value,
380                                                                      seed)
381                                 );
382}
383
384void
385TrexRpcCmdAddStream::parse_vm_instr_flow_var(const Json::Value &inst, std::unique_ptr<TrexStream> &stream, Json::Value &result) {
386    std::string  flow_var_name = parse_string(inst, "name", result);
387
388    auto sizes = {1, 2, 4, 8};
389    uint8_t      flow_var_size = parse_choice(inst, "size", sizes, result);
390
391    auto ops = {"inc", "dec", "random"};
392    std::string  op_type_str = parse_choice(inst, "op", ops, result);
393
394    StreamVmInstructionFlowMan::flow_var_op_e op_type;
395
396    if (op_type_str == "inc") {
397        op_type = StreamVmInstructionFlowMan::FLOW_VAR_OP_INC;
398    } else if (op_type_str == "dec") {
399        op_type = StreamVmInstructionFlowMan::FLOW_VAR_OP_DEC;
400    } else if (op_type_str == "random") {
401        op_type = StreamVmInstructionFlowMan::FLOW_VAR_OP_RANDOM;
402    } else {
403        throw TrexRpcException("internal error");
404    }
405
406    uint64_t init_value  = parse_uint64(inst, "init_value", result);
407    uint64_t min_value   = parse_uint64(inst, "min_value", result);
408    uint64_t max_value   = parse_uint64(inst, "max_value", result);
409    uint64_t step        = parse_uint64(inst, "step", result);
410
411    check_min_max(flow_var_size, init_value, step, min_value, max_value, result);
412
413    /* implicit range padding if possible */
414    handle_range_padding(max_value,min_value,step, op_type, result);
415
416    stream->m_vm.add_instruction(new StreamVmInstructionFlowMan(flow_var_name,
417                                                                flow_var_size,
418                                                                op_type,
419                                                                init_value,
420                                                                min_value,
421                                                                max_value,
422                                                                step)
423                                 );
424}
425
426
427void
428TrexRpcCmdAddStream::parse_vm_instr_write_mask_flow_var(const Json::Value &inst, std::unique_ptr<TrexStream> &stream, Json::Value &result) {
429    std::string  flow_var_name = parse_string(inst, "name", result);
430    uint16_t     pkt_offset    = parse_uint16(inst, "pkt_offset", result);
431    uint16_t      pkt_cast_size = parse_uint16(inst, "pkt_cast_size", result);
432    uint32_t     mask          = parse_uint32(inst, "mask", result);
433    int          shift         = parse_int(inst, "shift", result);
434    int          add_value     = parse_int(inst, "add_value", result);
435    bool         is_big_endian = parse_bool(inst,   "is_big_endian", result);
436
437    stream->m_vm.add_instruction(new StreamVmInstructionWriteMaskToPkt(flow_var_name,
438                                                                       pkt_offset,
439                                                                       (uint8_t)pkt_cast_size,
440                                                                       mask,
441                                                                       shift,
442                                                                       add_value,
443                                                                       is_big_endian));
444}
445
446
447void
448TrexRpcCmdAddStream::parse_vm_instr_write_flow_var(const Json::Value &inst, std::unique_ptr<TrexStream> &stream, Json::Value &result) {
449    std::string  flow_var_name = parse_string(inst, "name", result);
450    uint16_t     pkt_offset    = parse_uint16(inst, "pkt_offset", result);
451    int          add_value     = parse_int(inst,    "add_value", result);
452    bool         is_big_endian = parse_bool(inst,   "is_big_endian", result);
453
454    stream->m_vm.add_instruction(new StreamVmInstructionWriteToPkt(flow_var_name,
455                                                                   pkt_offset,
456                                                                   add_value,
457                                                                   is_big_endian));
458}
459
460void
461TrexRpcCmdAddStream::parse_vm(const Json::Value &vm, std::unique_ptr<TrexStream> &stream, Json::Value &result) {
462
463    const Json::Value &instructions =  parse_array(vm ,"instructions", result);
464
465    /* array of VM instructions on vm */
466    for (int i = 0; i < instructions.size(); i++) {
467        const Json::Value & inst = parse_object(instructions, i, result);
468
469        auto vm_types = {"fix_checksum_hw", "fix_checksum_ipv4", "flow_var", "write_flow_var","tuple_flow_var","trim_pkt_size","write_mask_flow_var","flow_var_rand_limit"};
470        std::string vm_type = parse_choice(inst, "type", vm_types, result);
471
472        // checksum instruction
473        if (vm_type == "fix_checksum_ipv4") {
474            parse_vm_instr_checksum(inst, stream, result);
475
476        } else if (vm_type == "fix_checksum_hw") {
477
478            parse_vm_instr_checksum_hw(inst, stream, result);
479
480        } else if (vm_type == "flow_var") {
481            parse_vm_instr_flow_var(inst, stream, result);
482
483        } else if (vm_type == "flow_var_rand_limit") {
484            parse_vm_instr_flow_var_rand_limit(inst, stream, result);
485
486        } else if (vm_type == "write_flow_var") {
487            parse_vm_instr_write_flow_var(inst, stream, result);
488
489        } else if (vm_type == "tuple_flow_var") {
490           parse_vm_instr_tuple_flow_var(inst, stream, result);
491
492        } else if (vm_type == "trim_pkt_size") {
493            parse_vm_instr_trim_pkt_size(inst, stream, result);
494        }else if (vm_type == "write_mask_flow_var") {
495            parse_vm_instr_write_mask_flow_var(inst, stream, result);
496        } else {
497            /* internal error */
498            throw TrexRpcException("internal error");
499        }
500    }
501
502    stream->m_cache_size      = parse_uint16(vm, "cache", result,0); /* default is zero */
503
504}
505
506void
507TrexRpcCmdAddStream::validate_stream(const std::unique_ptr<TrexStream> &stream, Json::Value &result) {
508
509    /* add the stream to the port's stream table */
510    TrexStatelessPort * port = get_stateless_obj()->get_port_by_id(stream->m_port_id);
511
512    /* does such a stream exists ? */
513    if (port->get_stream_by_id(stream->m_stream_id)) {
514        std::stringstream ss;
515        ss << "stream " << stream->m_stream_id << " already exists";
516        generate_execute_err(result, ss.str());
517    }
518
519}
520
521/***************************
522 * remove stream
523 *
524 **************************/
525trex_rpc_cmd_rc_e
526TrexRpcCmdRemoveStream::_run(const Json::Value &params, Json::Value &result) {
527
528    uint8_t port_id = parse_port(params, result);
529    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
530
531    uint32_t stream_id = parse_uint32(params, "stream_id", result);
532    TrexStream *stream = port->get_stream_by_id(stream_id);
533
534    if (!stream) {
535        std::stringstream ss;
536        ss << "stream " << stream_id << " does not exists";
537        generate_execute_err(result, ss.str());
538    }
539
540    try {
541        port->remove_stream(stream);
542    } catch (const TrexException &ex) {
543        generate_execute_err(result, ex.what());
544    }
545
546    delete stream;
547
548    result["result"] = Json::objectValue;
549
550    return (TREX_RPC_CMD_OK);
551}
552
553/***************************
554 * remove all streams
555 * for a port
556 *
557 **************************/
558trex_rpc_cmd_rc_e
559TrexRpcCmdRemoveAllStreams::_run(const Json::Value &params, Json::Value &result) {
560
561    uint8_t port_id = parse_port(params, result);
562    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
563
564    try {
565        port->remove_and_delete_all_streams();
566    } catch (const TrexException &ex) {
567        generate_execute_err(result, ex.what());
568    }
569
570
571    result["result"] = Json::objectValue;
572
573    return (TREX_RPC_CMD_OK);
574}
575
576/***************************
577 * get all streams configured
578 * on a specific port
579 *
580 **************************/
581trex_rpc_cmd_rc_e
582TrexRpcCmdGetStreamList::_run(const Json::Value &params, Json::Value &result) {
583    std::vector<uint32_t> stream_list;
584
585    uint8_t port_id = parse_port(params, result);
586    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
587
588    port->get_id_list(stream_list);
589
590    Json::Value json_list = Json::arrayValue;
591
592    for (auto stream_id : stream_list) {
593        json_list.append(stream_id);
594    }
595
596    result["result"] = json_list;
597
598    return (TREX_RPC_CMD_OK);
599}
600
601/***************************
602 * get stream by id
603 * on a specific port
604 *
605 **************************/
606trex_rpc_cmd_rc_e
607TrexRpcCmdGetStream::_run(const Json::Value &params, Json::Value &result) {
608
609    uint8_t port_id = parse_port(params, result);
610    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
611
612    bool     get_pkt   = parse_bool(params, "get_pkt", result);
613    uint32_t stream_id = parse_uint32(params, "stream_id", result);
614
615    TrexStream *stream = port->get_stream_by_id(stream_id);
616
617    if (!stream) {
618        std::stringstream ss;
619        ss << "stream id " << stream_id << " on port " << (int)port_id << " does not exists";
620        generate_execute_err(result, ss.str());
621    }
622
623    /* return the stored stream json (instead of decoding it all over again) */
624    Json::Value j = stream->get_stream_json();
625    if (!get_pkt) {
626        j.removeMember("packet");
627    }
628
629    result["result"]["stream"] = j;
630
631    return (TREX_RPC_CMD_OK);
632
633}
634
635/***************************
636 * start traffic on port
637 *
638 **************************/
639trex_rpc_cmd_rc_e
640TrexRpcCmdStartTraffic::_run(const Json::Value &params, Json::Value &result) {
641
642    uint8_t port_id = parse_port(params, result);
643    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
644
645    double    duration    = parse_double(params, "duration", result);
646    bool      force       = parse_bool(params, "force", result);
647    uint64_t  core_mask   = parse_uint64(params, "core_mask", result, TrexDPCoreMask::MASK_ALL);
648
649    if (!TrexDPCoreMask::is_valid_mask(port->get_dp_core_count(), core_mask)) {
650        generate_parse_err(result, "invalid core mask provided");
651    }
652
653    /* multiplier */
654    const Json::Value &mul_obj  = parse_object(params, "mul", result);
655
656    std::string type   = parse_choice(mul_obj, "type", TrexPortMultiplier::g_types, result);
657    std::string op     = parse_string(mul_obj, "op", result);
658    double      value  = parse_udouble(mul_obj, "value", result);
659
660    if ( value == 0 ){
661        generate_parse_err(result, "multiplier can't be zero");
662    }
663
664    if (op != "abs") {
665        generate_parse_err(result, "start message can only specify absolute speed rate");
666    }
667
668    dsec_t ts = now_sec();
669    TrexPortMultiplier mul(type, op, value);
670
671    try {
672        port->start_traffic(mul, duration, force, core_mask);
673
674    } catch (const TrexException &ex) {
675        generate_execute_err(result, ex.what());
676    }
677
678    result["result"]["multiplier"] = port->get_multiplier();
679    result["result"]["ts"]         = ts;
680
681    return (TREX_RPC_CMD_OK);
682}
683
684/***************************
685 * stop traffic on port
686 *
687 **************************/
688trex_rpc_cmd_rc_e
689TrexRpcCmdStopTraffic::_run(const Json::Value &params, Json::Value &result) {
690
691    uint8_t port_id = parse_port(params, result);
692    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
693
694    try {
695        port->stop_traffic();
696    } catch (const TrexException &ex) {
697        generate_execute_err(result, ex.what());
698    }
699
700    result["result"] = Json::objectValue;
701
702    return (TREX_RPC_CMD_OK);
703}
704
705/***************************
706 * remove all hardware filters
707 *
708 **************************/
709trex_rpc_cmd_rc_e
710TrexRpcCmdRemoveRXFilters::_run(const Json::Value &params, Json::Value &result) {
711
712    uint8_t port_id = parse_port(params, result);
713    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
714
715    try {
716        port->remove_rx_filters();
717    } catch (const TrexException &ex) {
718        generate_execute_err(result, ex.what());
719    }
720
721    result["result"] = Json::objectValue;
722
723    return (TREX_RPC_CMD_OK);
724}
725
726/***************************
727 * get all streams
728 *
729 **************************/
730trex_rpc_cmd_rc_e
731TrexRpcCmdGetAllStreams::_run(const Json::Value &params, Json::Value &result) {
732
733    uint8_t port_id = parse_port(params, result);
734    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
735
736    std::vector <TrexStream *> streams;
737    port->get_object_list(streams);
738
739    Json::Value streams_json = Json::objectValue;
740    for (auto stream : streams) {
741
742        Json::Value j = stream->get_stream_json();
743
744        std::stringstream ss;
745        ss << stream->m_stream_id;
746
747        streams_json[ss.str()] = j;
748    }
749
750    result["result"]["streams"] = streams_json;
751
752    return (TREX_RPC_CMD_OK);
753}
754
755/***************************
756 * pause traffic
757 *
758 **************************/
759trex_rpc_cmd_rc_e
760TrexRpcCmdPauseTraffic::_run(const Json::Value &params, Json::Value &result) {
761
762    uint8_t port_id = parse_port(params, result);
763    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
764
765     try {
766        port->pause_traffic();
767    } catch (const TrexException &ex) {
768        generate_execute_err(result, ex.what());
769    }
770
771    result["result"] = Json::objectValue;
772
773    return (TREX_RPC_CMD_OK);
774}
775
776/***************************
777 * resume traffic
778 *
779 **************************/
780trex_rpc_cmd_rc_e
781TrexRpcCmdResumeTraffic::_run(const Json::Value &params, Json::Value &result) {
782
783    uint8_t port_id = parse_port(params, result);
784    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
785
786     try {
787        port->resume_traffic();
788    } catch (const TrexException &ex) {
789        generate_execute_err(result, ex.what());
790    }
791
792    result["result"] = Json::objectValue;
793
794    return (TREX_RPC_CMD_OK);
795}
796
797/***************************
798 * update traffic
799 *
800 **************************/
801trex_rpc_cmd_rc_e
802TrexRpcCmdUpdateTraffic::_run(const Json::Value &params, Json::Value &result) {
803
804    uint8_t port_id = parse_port(params, result);
805    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
806
807    bool force = parse_bool(params, "force", result);
808
809    /* multiplier */
810
811    const Json::Value &mul_obj  = parse_object(params, "mul", result);
812
813    std::string type   = parse_choice(mul_obj, "type", TrexPortMultiplier::g_types, result);
814    std::string op     = parse_choice(mul_obj, "op", TrexPortMultiplier::g_ops, result);
815    double      value  = parse_double(mul_obj, "value", result);
816
817    TrexPortMultiplier mul(type, op, value);
818
819
820    try {
821        port->update_traffic(mul, force);
822    } catch (const TrexException &ex) {
823        generate_execute_err(result, ex.what());
824    }
825
826    result["result"]["multiplier"] = port->get_multiplier();
827
828    return (TREX_RPC_CMD_OK);
829}
830
831/***************************
832 * validate
833 *
834 * checks that the port
835 * attached streams are
836 * valid as a program
837 **************************/
838trex_rpc_cmd_rc_e
839TrexRpcCmdValidate::_run(const Json::Value &params, Json::Value &result) {
840    uint8_t port_id = parse_port(params, result);
841    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
842
843    const TrexStreamsGraphObj *graph = NULL;
844
845    try {
846        graph = port->validate();
847    }
848    catch (const TrexException &ex) {
849        generate_execute_err(result, ex.what());
850    }
851
852    /* max values */
853    result["result"]["rate"]["max_bps_l2"]    = graph->get_max_bps_l2();
854    result["result"]["rate"]["max_bps_l1"]    = graph->get_max_bps_l1();
855    result["result"]["rate"]["max_pps"]       = graph->get_max_pps();
856    result["result"]["rate"]["max_line_util"] = (graph->get_max_bps_l1() / port->get_port_speed_bps()) * 100.01;
857
858    /* min values */
859    result["result"]["rate"]["min_bps_l2"]    = graph->get_max_bps_l2(0);
860    result["result"]["rate"]["min_bps_l1"]    = graph->get_max_bps_l1(0);
861    result["result"]["rate"]["min_pps"]       = graph->get_max_pps(0);
862    result["result"]["rate"]["min_line_util"] = (graph->get_max_bps_l1(0) / port->get_port_speed_bps()) * 100.01;
863
864    result["result"]["graph"]["expected_duration"] = graph->get_duration();
865    result["result"]["graph"]["events_count"] = (int)graph->get_events().size();
866
867    result["result"]["graph"]["events"] = Json::arrayValue;
868    Json::Value &events_json = result["result"]["graph"]["events"];
869
870    int index = 0;
871    for (const auto &ev : graph->get_events()) {
872        Json::Value ev_json;
873
874        ev_json["time_usec"]     = ev.time;
875        ev_json["diff_bps_l2"]   = ev.diff_bps_l2;
876        ev_json["diff_bps_l1"]   = ev.diff_bps_l1;
877        ev_json["diff_pps"]      = ev.diff_pps;
878        ev_json["stream_id"]     = ev.stream_id;
879
880        events_json.append(ev_json);
881
882        index++;
883        if (index >= 100) {
884            break;
885        }
886    }
887
888
889    return (TREX_RPC_CMD_OK);
890}
891