trex_rpc_cmd_general.cpp revision 234779fd
1/*
2 Itay Marom
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
22#include "trex_rpc_cmds.h"
23#include <trex_rpc_server_api.h>
24#include <trex_stateless.h>
25#include <trex_stateless_port.h>
26#include <trex_rpc_cmds_table.h>
27
28#include <internal_api/trex_platform_api.h>
29
30#include "trex_stateless_rx_core.h"
31
32#include <fstream>
33#include <iostream>
34#include <unistd.h>
35
36#ifdef RTE_DPDK
37    #include <../linux_dpdk/version.h>
38#endif
39
40using namespace std;
41
42/**
43 * API sync
44 */
45trex_rpc_cmd_rc_e
46TrexRpcCmdAPISync::_run(const Json::Value &params, Json::Value &result) {
47    const Json::Value &api_vers = parse_array(params, "api_vers", result);
48
49    Json::Value api_ver_rc = Json::arrayValue;
50
51    /* for every element in the list - generate the appropirate API handler */
52    for (const auto api_ver : api_vers) {
53        Json::Value single_rc;
54
55        /* only those are supported */
56        const std::string type = parse_choice(api_ver, "type", {"core"}, result);
57
58        int major = parse_int(api_ver, "major", result);
59        int minor = parse_int(api_ver, "minor", result);
60        APIClass::type_e api_type;
61
62        /* decode type of API */
63        if (type == "core") {
64            api_type = APIClass::API_CLASS_TYPE_CORE;
65        }
66
67        single_rc["type"]    = type;
68
69        /* this section might throw exception in case versions do not match */
70        try {
71            single_rc["api_h"] = get_stateless_obj()->verify_api(api_type, major, minor);
72
73        } catch (const TrexAPIException &e) {
74            generate_execute_err(result, e.what());
75        }
76
77        /* add to the response */
78        api_ver_rc.append(single_rc);
79    }
80
81    result["result"]["api_vers"] = api_ver_rc;
82
83    return (TREX_RPC_CMD_OK);
84}
85
86/**
87 * ping command
88 */
89trex_rpc_cmd_rc_e
90TrexRpcCmdPing::_run(const Json::Value &params, Json::Value &result) {
91
92    result["result"] = Json::objectValue;
93    return (TREX_RPC_CMD_OK);
94}
95
96/**
97 * shutdown command
98 */
99trex_rpc_cmd_rc_e
100TrexRpcCmdShutdown::_run(const Json::Value &params, Json::Value &result) {
101
102    const string &user = parse_string(params, "user", result);
103    bool force = parse_bool(params, "force", result);
104
105    /* verify every port is either free or owned by the issuer */
106    for (auto port : get_stateless_obj()->get_port_list()) {
107        TrexPortOwner &owner = port->get_owner();
108        if ( (!owner.is_free()) && (!owner.is_owned_by(user)) && !force) {
109            std::stringstream ss;
110            ss << "port " << int(port->get_port_id()) << " is owned by '" << owner.get_name() << "' - specify 'force' for override";
111            generate_execute_err(result, ss.str());
112        }
113    }
114
115    /* signal that we got a shutdown request */
116    get_stateless_obj()->get_platform_api()->mark_for_shutdown();
117
118    result["result"] = Json::objectValue;
119    return (TREX_RPC_CMD_OK);
120}
121
122/**
123 * query command
124 */
125trex_rpc_cmd_rc_e
126TrexRpcCmdGetCmds::_run(const Json::Value &params, Json::Value &result) {
127    vector<string> cmds;
128
129    TrexRpcCommandsTable::get_instance().query(cmds);
130
131    Json::Value test = Json::arrayValue;
132    for (auto cmd : cmds) {
133        test.append(cmd);
134    }
135
136    result["result"] = test;
137
138    return (TREX_RPC_CMD_OK);
139}
140
141/**
142 * get version
143 *
144 */
145trex_rpc_cmd_rc_e
146TrexRpcCmdGetVersion::_run(const Json::Value &params, Json::Value &result) {
147
148    Json::Value &section = result["result"];
149
150    #ifdef RTE_DPDK
151
152    section["version"]       = VERSION_BUILD_NUM;
153    section["build_date"]    = get_build_date();
154    section["build_time"]    = get_build_time();
155    section["built_by"]      = VERSION_USER;
156
157    #else
158
159    section["version"]       = "v1.75";
160    section["build_date"]    = __DATE__;
161    section["build_time"]    = __TIME__;
162    section["built_by"]      = "MOCK";
163
164    #endif
165
166    return (TREX_RPC_CMD_OK);
167}
168
169trex_rpc_cmd_rc_e
170TrexRpcCmdGetActivePGIds::_run(const Json::Value &params, Json::Value &result) {
171    flow_stat_active_t active_flow_stat;
172    flow_stat_active_it_t it;
173    int i = 0;
174
175    Json::Value &section = result["result"];
176    section["ids"] = Json::arrayValue;
177
178    if (get_stateless_obj()->get_platform_api()->get_active_pgids(active_flow_stat) < 0)
179        return TREX_RPC_CMD_INTERNAL_ERR;
180
181    for (it = active_flow_stat.begin(); it != active_flow_stat.end(); it++) {
182        section["ids"][i++] = *it;
183    }
184
185    return (TREX_RPC_CMD_OK);
186}
187
188// get utilization of CPU per thread with up to 20 latest values + mbufs per socket
189trex_rpc_cmd_rc_e
190TrexRpcCmdGetUtilization::_run(const Json::Value &params, Json::Value &result) {
191    cpu_util_full_t cpu_util_full;
192
193    Json::Value &section = result["result"];
194
195    if (get_stateless_obj()->get_platform_api()->get_mbuf_util(section) != 0) {
196        return TREX_RPC_CMD_INTERNAL_ERR;
197    }
198
199    if (get_stateless_obj()->get_platform_api()->get_cpu_util_full(cpu_util_full) != 0) {
200        return TREX_RPC_CMD_INTERNAL_ERR;
201    }
202
203    for (int thread_id = 0; thread_id < cpu_util_full.size(); thread_id++) {
204
205        /* history */
206        for (int history_id = 0; history_id < cpu_util_full[thread_id].m_history.size(); history_id++) {
207            section["cpu"][thread_id]["history"].append(cpu_util_full[thread_id].m_history[history_id]);
208        }
209
210        /* ports */
211        section["cpu"][thread_id]["ports"] = Json::arrayValue;
212        section["cpu"][thread_id]["ports"].append(cpu_util_full[thread_id].m_port1);
213        section["cpu"][thread_id]["ports"].append(cpu_util_full[thread_id].m_port2);
214    }
215
216    return (TREX_RPC_CMD_OK);
217}
218
219/**
220 * get the CPU model
221 *
222 */
223std::string
224TrexRpcCmdGetSysInfo::get_cpu_model() {
225
226    static const string cpu_prefix = "model name";
227    std::ifstream cpuinfo("/proc/cpuinfo");
228
229    if (cpuinfo.is_open()) {
230        while (cpuinfo.good()) {
231
232            std::string line;
233            getline(cpuinfo, line);
234
235            int pos = line.find(cpu_prefix);
236            if (pos == string::npos) {
237                continue;
238            }
239
240            /* trim it */
241            int index = cpu_prefix.size() + 1;
242            while ( (line[index] == ' ') || (line[index] == ':') ) {
243                index++;
244            }
245
246            return line.substr(index);
247        }
248    }
249
250    return "unknown";
251}
252
253void
254TrexRpcCmdGetSysInfo::get_hostname(string &hostname) {
255    char buffer[256];
256    buffer[0] = 0;
257
258    gethostname(buffer, sizeof(buffer));
259
260    /* write hostname */
261    hostname = buffer;
262}
263
264/**
265 * get system info
266 *
267 */
268trex_rpc_cmd_rc_e
269TrexRpcCmdGetSysInfo::_run(const Json::Value &params, Json::Value &result) {
270    string hostname;
271
272    TrexStateless * main = get_stateless_obj();
273
274    Json::Value &section = result["result"];
275
276    get_hostname(hostname);
277    section["hostname"]  = hostname;
278
279    section["uptime"] = TrexRpcServer::get_server_uptime();
280
281    /* FIXME: core count */
282    section["dp_core_count"] = main->get_dp_core_count();
283    section["dp_core_count_per_port"] = main->get_dp_core_count() / (main->get_port_count() / 2);
284    section["core_type"] = get_cpu_model();
285
286    /* ports */
287
288
289    section["port_count"] = main->get_port_count();
290
291    section["ports"] = Json::arrayValue;
292
293    for (int i = 0; i < main->get_port_count(); i++) {
294        string driver;
295        string hw_macaddr;
296        string src_macaddr;
297        string dst_macaddr;
298        string pci_addr;
299        string description;
300        supp_speeds_t supp_speeds;
301        int numa;
302
303        TrexStatelessPort *port = main->get_port_by_id(i);
304
305        port->get_properties(driver);
306        port->get_macaddr(hw_macaddr, src_macaddr, dst_macaddr);
307
308        port->get_pci_info(pci_addr, numa);
309        main->get_platform_api()->getPortAttrObj(i)->get_description(description);
310        main->get_platform_api()->getPortAttrObj(i)->get_supported_speeds(supp_speeds);
311
312        section["ports"][i]["index"]   = i;
313
314        section["ports"][i]["driver"]       = driver;
315        section["ports"][i]["description"]  = description;
316        section["ports"][i]["hw_macaddr"]   = hw_macaddr;
317        section["ports"][i]["src_macaddr"]  = src_macaddr;
318        section["ports"][i]["dst_macaddr"]  = dst_macaddr;
319
320        section["ports"][i]["pci_addr"]         = pci_addr;
321        section["ports"][i]["numa"]             = numa;
322
323        uint16_t caps = port->get_rx_caps();
324        section["ports"][i]["rx"]["caps"]      = Json::arrayValue;
325        if (caps & TrexPlatformApi::IF_STAT_IPV4_ID) {
326            section["ports"][i]["rx"]["caps"].append("flow_stats");
327        }
328        if (caps & TrexPlatformApi::IF_STAT_PAYLOAD) {
329            section["ports"][i]["rx"]["caps"].append("latency");
330        }
331        if (caps & TrexPlatformApi::IF_STAT_RX_BYTES_COUNT) {
332            section["ports"][i]["rx"]["caps"].append("rx_bytes");
333        }
334        section["ports"][i]["rx"]["counters"]  = port->get_rx_count_num();
335        section["ports"][i]["is_fc_supported"] = get_stateless_obj()->get_platform_api()->getPortAttrObj(i)->is_fc_change_supported();
336        section["ports"][i]["is_led_supported"] = get_stateless_obj()->get_platform_api()->getPortAttrObj(i)->is_led_change_supported();
337        section["ports"][i]["is_link_supported"] = get_stateless_obj()->get_platform_api()->getPortAttrObj(i)->is_link_change_supported();
338        section["ports"][i]["is_virtual"] = get_stateless_obj()->get_platform_api()->getPortAttrObj(i)->is_virtual();
339        section["ports"][i]["supp_speeds"] = Json::arrayValue;
340        for (int speed_id=0; speed_id<supp_speeds.size(); speed_id++) {
341            section["ports"][i]["supp_speeds"].append(supp_speeds[speed_id]);
342        }
343
344    }
345
346    return (TREX_RPC_CMD_OK);
347}
348
349
350int
351TrexRpcCmdSetPortAttr::parse_rx_filter_mode(const Json::Value &msg, uint8_t port_id, Json::Value &result) {
352    const std::string type = parse_choice(msg, "mode", {"hw", "all"}, result);
353
354    rx_filter_mode_e filter_mode;
355    if (type == "hw") {
356        filter_mode = RX_FILTER_MODE_HW;
357    } else if (type == "all") {
358        filter_mode = RX_FILTER_MODE_ALL;
359    } else {
360        assert(0);
361    }
362
363    return get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id)->set_rx_filter_mode(filter_mode);
364}
365
366/**
367 * set port commands
368 *
369 * @author imarom (24-Feb-16)
370 *
371 * @param params
372 * @param result
373 *
374 * @return trex_rpc_cmd_rc_e
375 */
376trex_rpc_cmd_rc_e
377TrexRpcCmdSetPortAttr::_run(const Json::Value &params, Json::Value &result) {
378
379    uint8_t port_id = parse_port(params, result);
380
381    const Json::Value &attr = parse_object(params, "attr", result);
382    int ret = 0;
383    bool changed = false;
384
385    /* iterate over all attributes in the dict */
386    for (const std::string &name : attr.getMemberNames()) {
387
388        if (name == "promiscuous") {
389            bool enabled = parse_bool(attr[name], "enabled", result);
390            ret = get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id)->set_promiscuous(enabled);
391        }
392
393        else if (name == "link_status") {
394            bool up = parse_bool(attr[name], "up", result);
395            ret = get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id)->set_link_up(up);
396        }
397
398        else if (name == "led_status") {
399            bool on = parse_bool(attr[name], "on", result);
400            ret = get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id)->set_led(on);
401        }
402
403        else if (name == "flow_ctrl_mode") {
404            int mode = parse_int(attr[name], "mode", result);
405            ret = get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id)->set_flow_ctrl(mode);
406        }
407
408        else if (name == "rx_filter_mode") {
409            ret = parse_rx_filter_mode(attr[name], port_id, result);
410        }
411
412        else {
413            generate_execute_err(result, "Not recognized attribute: " + name);
414            break;
415        }
416
417        if (ret != 0){
418            if ( ret == -ENOTSUP ) {
419                generate_execute_err(result, "Error applying " + name + ": operation is not supported for this NIC.");
420            }
421            else if (ret) {
422                generate_execute_err(result, "Error applying " + name + " attribute, return value: " + to_string(ret));
423            }
424            break;
425        } else {
426            changed = true;
427        }
428    }
429    if (changed) {
430        get_stateless_obj()->get_platform_api()->publish_async_port_attr_changed(port_id);
431    }
432
433    result["result"] = Json::objectValue;
434    return (TREX_RPC_CMD_OK);
435}
436
437
438/**
439 * returns the current owner of the device
440 *
441 * @author imarom (08-Sep-15)
442 *
443 * @param params
444 * @param result
445 *
446 * @return trex_rpc_cmd_rc_e
447 */
448trex_rpc_cmd_rc_e
449TrexRpcCmdGetOwner::_run(const Json::Value &params, Json::Value &result) {
450    Json::Value &section = result["result"];
451
452    uint8_t port_id = parse_port(params, result);
453
454    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
455    section["owner"] = port->get_owner().get_name();
456
457    return (TREX_RPC_CMD_OK);
458}
459
460/**
461 * acquire device
462 *
463 */
464trex_rpc_cmd_rc_e
465TrexRpcCmdAcquire::_run(const Json::Value &params, Json::Value &result) {
466
467    uint8_t port_id = parse_port(params, result);
468
469    const string  &new_owner  = parse_string(params, "user", result);
470    bool force = parse_bool(params, "force", result);
471    uint32_t session_id = parse_uint32(params, "session_id", result);
472
473    /* if not free and not you and not force - fail */
474    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
475
476    try {
477        port->acquire(new_owner, session_id, force);
478    } catch (const TrexException &ex) {
479        generate_execute_err(result, ex.what());
480    }
481
482    result["result"] = port->get_owner().get_handler();
483
484    return (TREX_RPC_CMD_OK);
485}
486
487/**
488 * release device
489 *
490 */
491trex_rpc_cmd_rc_e
492TrexRpcCmdRelease::_run(const Json::Value &params, Json::Value &result) {
493
494    uint8_t port_id = parse_port(params, result);
495
496    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
497
498    try {
499        port->release();
500    } catch (const TrexException &ex) {
501        generate_execute_err(result, ex.what());
502    }
503
504    result["result"] = Json::objectValue;
505
506    return (TREX_RPC_CMD_OK);
507}
508
509/**
510 * get port extended stats names (keys of dict)
511 *
512 */
513trex_rpc_cmd_rc_e
514TrexRpcCmdGetPortXStatsNames::_run(const Json::Value &params, Json::Value &result) {
515
516    uint8_t port_id = parse_port(params, result);
517    xstats_names_t xstats_names;
518
519    int ret = get_stateless_obj()->get_platform_api()->get_xstats_names(port_id, xstats_names);
520    if (ret < 0) {
521        if ( ret == -ENOTSUP ) {
522            generate_execute_err(result, "Operation not supported");
523        }
524        else if (ret) {
525            generate_execute_err(result, "Operation failed, error code: " + to_string(ret));
526        }
527    } else {
528        for (int i=0; i<xstats_names.size(); i++) {
529            result["result"]["xstats_names"].append(xstats_names[i]);
530        }
531    }
532
533    return (TREX_RPC_CMD_OK);
534}
535
536/**
537 * get port extended stats (values of dict)
538 *
539 */
540trex_rpc_cmd_rc_e
541TrexRpcCmdGetPortXStatsValues::_run(const Json::Value &params, Json::Value &result) {
542
543    uint8_t port_id = parse_port(params, result);
544    xstats_values_t xstats_values;
545
546    int ret = get_stateless_obj()->get_platform_api()->get_xstats_values(port_id, xstats_values);
547    if (ret < 0) {
548        if ( ret == -ENOTSUP ) {
549            generate_execute_err(result, "Operation not supported");
550        }
551        else if (ret) {
552            generate_execute_err(result, "Operation failed, error code: " + to_string(ret));
553        }
554    } else {
555        for (int i=0; i<xstats_values.size(); i++) {
556            result["result"]["xstats_values"].append((Json::Value::UInt64) xstats_values[i]);
557        }
558    }
559
560    return (TREX_RPC_CMD_OK);
561}
562
563/**
564 * get port stats
565 *
566 */
567trex_rpc_cmd_rc_e
568TrexRpcCmdGetPortStats::_run(const Json::Value &params, Json::Value &result) {
569
570    uint8_t port_id = parse_port(params, result);
571
572    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
573
574    try {
575        port->encode_stats(result["result"]);
576    } catch (const TrexException &ex) {
577        generate_execute_err(result, ex.what());
578    }
579
580    return (TREX_RPC_CMD_OK);
581}
582
583/**
584 * fetch the port status
585 *
586 * @author imarom (09-Dec-15)
587 *
588 * @param params
589 * @param result
590 *
591 * @return trex_rpc_cmd_rc_e
592 */
593trex_rpc_cmd_rc_e
594TrexRpcCmdGetPortStatus::_run(const Json::Value &params, Json::Value &result) {
595    uint8_t port_id = parse_port(params, result);
596
597    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
598
599    result["result"]["owner"]         = (port->get_owner().is_free() ? "" : port->get_owner().get_name());
600    result["result"]["state"]         = port->get_state_as_string();
601    result["result"]["max_stream_id"] = port->get_max_stream_id();
602
603    /* attributes */
604    result["result"]["attr"]["promiscuous"]["enabled"] = get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id)->get_promiscuous();
605    result["result"]["attr"]["link"]["up"] = get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id)->is_link_up();
606    result["result"]["attr"]["speed"]      = get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id)->get_link_speed();
607
608    int mode;
609    int ret = get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id)->get_flow_ctrl(mode);
610    if (ret != 0) {
611        mode = -1;
612    }
613    result["result"]["attr"]["fc"]["mode"] = mode;
614
615    /* RX data */
616    result["result"]["attr"]["rx_filter_mode"] = get_stateless_obj()->get_platform_api()->getPortAttrObj(port_id)->get_rx_filter_mode();
617
618    return (TREX_RPC_CMD_OK);
619}
620
621/**
622 * publish async data now (fast flush)
623 *
624 */
625trex_rpc_cmd_rc_e
626TrexRpcPublishNow::_run(const Json::Value &params, Json::Value &result) {
627    TrexStateless *main = get_stateless_obj();
628
629    uint32_t key  = parse_uint32(params, "key", result);
630    bool baseline = parse_bool(params, "baseline", result);
631
632    main->get_platform_api()->publish_async_data_now(key, baseline);
633
634    result["result"] = Json::objectValue;
635    return (TREX_RPC_CMD_OK);
636
637}
638
639
640/**
641 * push a remote PCAP on a port
642 *
643 */
644trex_rpc_cmd_rc_e
645TrexRpcCmdPushRemote::_run(const Json::Value &params, Json::Value &result) {
646
647    uint8_t port_id = parse_port(params, result);
648    std::string  pcap_filename  = parse_string(params, "pcap_filename", result);
649    double       ipg_usec       = parse_double(params, "ipg_usec", result);
650    double       speedup        = parse_double(params, "speedup", result);
651    uint32_t     count          = parse_uint32(params, "count", result);
652    double       duration       = parse_double(params, "duration", result);
653    bool         is_dual        = parse_bool(params,   "is_dual", result, false);
654    std::string  slave_handler  = parse_string(params, "slave_handler", result, "");
655
656    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
657
658    /* for dual mode - make sure slave_handler matches */
659    if (is_dual) {
660        TrexStatelessPort *slave = get_stateless_obj()->get_port_by_id(port_id ^ 0x1);
661        if (!slave->get_owner().verify(slave_handler)) {
662            generate_execute_err(result, "incorrect or missing slave port handler");
663        }
664    }
665
666
667    try {
668        port->push_remote(pcap_filename, ipg_usec, speedup, count, duration, is_dual);
669    } catch (const TrexException &ex) {
670        generate_execute_err(result, ex.what());
671    }
672
673    result["result"] = Json::objectValue;
674    return (TREX_RPC_CMD_OK);
675
676}
677
678/**
679 * set on/off RX software receive mode
680 *
681 */
682trex_rpc_cmd_rc_e
683TrexRpcCmdSetRxFeature::_run(const Json::Value &params, Json::Value &result) {
684
685    uint8_t port_id = parse_port(params, result);
686    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
687
688    /* decide which feature is being set */
689    const std::string type = parse_choice(params, "type", {"capture", "queue", "server"}, result);
690
691    if (type == "capture") {
692        parse_capture_msg(params, port, result);
693    } else if (type == "queue") {
694        parse_queue_msg(params, port, result);
695    } else if (type == "server") {
696        parse_server_msg(params, port, result);
697    } else {
698        assert(0);
699    }
700
701    result["result"] = Json::objectValue;
702    return (TREX_RPC_CMD_OK);
703
704}
705
706void
707TrexRpcCmdSetRxFeature::parse_capture_msg(const Json::Value &msg, TrexStatelessPort *port, Json::Value &result) {
708    std::string pcap_filename = parse_string(msg, "pcap_filename", result);
709    bool enabled = parse_bool(msg, "enabled", result);
710
711    if (enabled) {
712
713        uint64_t limit = parse_uint32(msg, "limit", result);
714        if (limit == 0) {
715            generate_parse_err(result, "limit cannot be zero");
716        }
717
718        try {
719            port->start_rx_capture(pcap_filename, limit);
720        } catch (const TrexException &ex) {
721            generate_execute_err(result, ex.what());
722        }
723
724    } else {
725
726        try {
727            port->stop_rx_capture();
728        } catch (const TrexException &ex) {
729            generate_execute_err(result, ex.what());
730        }
731
732    }
733
734}
735
736void
737TrexRpcCmdSetRxFeature::parse_queue_msg(const Json::Value &msg, TrexStatelessPort *port, Json::Value &result) {
738}
739
740void
741TrexRpcCmdSetRxFeature::parse_server_msg(const Json::Value &msg, TrexStatelessPort *port, Json::Value &result) {
742}
743
744
745trex_rpc_cmd_rc_e
746TrexRpcCmdGetRxSwPkts::_run(const Json::Value &params, Json::Value &result) {
747
748    uint8_t port_id = parse_port(params, result);
749
750    TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
751
752    try {
753        RxPacketBuffer *pkt_buffer = port->get_rx_sw_pkts();
754        result["result"]["pkts"] = pkt_buffer->to_json();
755
756    } catch (const TrexException &ex) {
757        generate_execute_err(result, ex.what());
758    }
759
760
761    return (TREX_RPC_CMD_OK);
762}
763