diff options
author | Hanoh Haim <hhaim@cisco.com> | 2015-09-10 07:54:05 +0300 |
---|---|---|
committer | Hanoh Haim <hhaim@cisco.com> | 2015-09-10 07:54:05 +0300 |
commit | a360a1734c459d62bd4c204a6005214ce8944f85 (patch) | |
tree | e06cad6cf63a52701aff303c19024cde1d541ebd /src/rpc-server | |
parent | 15b4f7cd7c3e9176c1f24fc632791e833cb588b8 (diff) | |
parent | e33befcf222fd2108d589dede11069d4256bb21a (diff) |
Merge branch 'master' of csi-sceasr-b45:/auto/proj-pcube-b/apps/PL-b/tools/repo//trex-core
Conflicts:
linux/ws_main.py
Diffstat (limited to 'src/rpc-server')
-rw-r--r-- | src/rpc-server/commands/trex_rpc_cmd_general.cpp | 12 | ||||
-rw-r--r-- | src/rpc-server/commands/trex_rpc_cmd_stream.cpp | 326 | ||||
-rw-r--r-- | src/rpc-server/commands/trex_rpc_cmds.h | 16 | ||||
-rw-r--r-- | src/rpc-server/trex_rpc_cmd.cpp | 20 | ||||
-rw-r--r-- | src/rpc-server/trex_rpc_cmd_api.h | 36 | ||||
-rw-r--r-- | src/rpc-server/trex_rpc_cmds_table.cpp | 4 | ||||
-rw-r--r-- | src/rpc-server/trex_rpc_jsonrpc_v2_parser.cpp | 25 | ||||
-rw-r--r-- | src/rpc-server/trex_rpc_jsonrpc_v2_parser.h | 8 | ||||
-rw-r--r-- | src/rpc-server/trex_rpc_req_resp_server.cpp | 5 | ||||
-rw-r--r-- | src/rpc-server/trex_rpc_server.cpp | 6 | ||||
-rw-r--r-- | src/rpc-server/trex_rpc_server_api.h | 31 | ||||
-rw-r--r-- | src/rpc-server/trex_rpc_server_mock.cpp | 5 |
12 files changed, 463 insertions, 31 deletions
diff --git a/src/rpc-server/commands/trex_rpc_cmd_general.cpp b/src/rpc-server/commands/trex_rpc_cmd_general.cpp index 6b765aca..32952b1a 100644 --- a/src/rpc-server/commands/trex_rpc_cmd_general.cpp +++ b/src/rpc-server/commands/trex_rpc_cmd_general.cpp @@ -20,6 +20,7 @@ limitations under the License. */ #include "trex_rpc_cmds.h" #include <trex_rpc_server_api.h> +#include <trex_stateless_api.h> #ifndef TREX_RPC_MOCK_SERVER #include <../linux_dpdk/version.h> @@ -41,8 +42,7 @@ TrexRpcCmdGetStatus::_run(const Json::Value ¶ms, Json::Value &result) { section["general"]["version"] = VERSION_BUILD_NUM; section["general"]["build_date"] = get_build_date(); section["general"]["build_time"] = get_build_time(); - section["general"]["version_user"] = VERSION_USER; - section["general"]["uptime"] = TrexRpcServer::get_server_uptime(); + section["general"]["built_by"] = VERSION_USER; #else @@ -50,10 +50,16 @@ TrexRpcCmdGetStatus::_run(const Json::Value ¶ms, Json::Value &result) { section["general"]["build_date"] = __DATE__; section["general"]["build_time"] = __TIME__; section["general"]["version_user"] = "MOCK"; - section["general"]["uptime"] = TrexRpcServer::get_server_uptime(); #endif + section["general"]["uptime"] = TrexRpcServer::get_server_uptime(); + section["general"]["owner"] = TrexRpcServer::get_owner(); + + // ports + + section["ports"]["count"] = TrexStateless::get_instance().get_port_count(); + return (TREX_RPC_CMD_OK); } diff --git a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp index d1dffc44..90b55ea8 100644 --- a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp +++ b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp @@ -27,6 +27,23 @@ limitations under the License. using namespace std; +/** + * simple parser of string to number + * only difference is that it enforces whole number + * and not partial + * + */ +static uint64_t str2num(const string &str) { + size_t index; + + uint64_t num = std::stoull(str, &index, 0); + if (index != str.size()) { + throw invalid_argument("could not parse string to number"); + } + + return (num); +} + /*************************** * add new stream * @@ -34,6 +51,9 @@ using namespace std; trex_rpc_cmd_rc_e TrexRpcCmdAddStream::_run(const Json::Value ¶ms, Json::Value &result) { + uint8_t port_id = parse_int(params, "port_id", result); + uint32_t stream_id = parse_int(params, "stream_id", result); + const Json::Value §ion = parse_object(params, "stream", result); /* get the type of the stream */ @@ -41,32 +61,40 @@ TrexRpcCmdAddStream::_run(const Json::Value ¶ms, Json::Value &result) { string type = parse_string(mode, "type", result); /* allocate a new stream based on the type */ - TrexStream *stream = allocate_new_stream(section, result); + TrexStream *stream = allocate_new_stream(section, port_id, stream_id, result); /* some fields */ stream->m_enabled = parse_bool(section, "enabled", result); stream->m_self_start = parse_bool(section, "self_start", result); /* inter stream gap */ - stream->m_isg_usec = parse_double(section, "Is", result); + stream->m_isg_usec = parse_double(section, "isg", result); stream->m_next_stream_id = parse_int(section, "next_stream_id", result); - const Json::Value &pkt = parse_array(section, "packet", result); + const Json::Value &pkt = parse_object(section, "packet", result); + const Json::Value &pkt_binary = parse_array(pkt, "binary", result); /* fetch the packet from the message */ - stream->m_pkt_len = pkt.size(); - stream->m_pkt = new uint8_t[pkt.size()]; - if (!stream->m_pkt) { + stream->m_pkt.len = pkt_binary.size(); + stream->m_pkt.binary = new uint8_t[pkt_binary.size()]; + if (!stream->m_pkt.binary) { generate_internal_err(result, "unable to allocate memory"); } /* parse the packet */ - for (int i = 0; i < pkt.size(); i++) { - stream->m_pkt[i] = parse_byte(pkt, i, result); + for (int i = 0; i < pkt_binary.size(); i++) { + stream->m_pkt.binary[i] = parse_byte(pkt_binary, i, result); } + /* meta data */ + stream->m_pkt.meta = parse_string(pkt, "meta", result); + + /* parse VM */ + const Json::Value &vm = parse_array(section ,"vm", result); + parse_vm(vm, stream, result); + /* parse RX info */ const Json::Value &rx = parse_object(section, "rx_stats", result); @@ -82,7 +110,7 @@ TrexRpcCmdAddStream::_run(const Json::Value ¶ms, Json::Value &result) { /* make sure this is a valid stream to add */ validate_stream(stream, result); - TrexStatelessPort *port = get_trex_stateless()->get_port_by_id(stream->m_port_id); + TrexStatelessPort *port = TrexStateless::get_instance().get_port_by_id(stream->m_port_id); port->get_stream_table()->add_stream(stream); result["result"] = "ACK"; @@ -93,10 +121,7 @@ TrexRpcCmdAddStream::_run(const Json::Value ¶ms, Json::Value &result) { TrexStream * -TrexRpcCmdAddStream::allocate_new_stream(const Json::Value §ion, Json::Value &result) { - - uint8_t port_id = parse_int(section, "port_id", result); - uint32_t stream_id = parse_int(section, "stream_id", result); +TrexRpcCmdAddStream::allocate_new_stream(const Json::Value §ion, uint8_t port_id, uint32_t stream_id, Json::Value &result) { TrexStream *stream; @@ -138,11 +163,114 @@ TrexRpcCmdAddStream::allocate_new_stream(const Json::Value §ion, Json::Value } +void +TrexRpcCmdAddStream::parse_vm_instr_checksum(const Json::Value &inst, TrexStream *stream, Json::Value &result) { + + uint16_t pkt_offset = parse_uint16(inst, "pkt_offset", result); + stream->m_vm.add_instruction(new StreamVmInstructionFixChecksumIpv4(pkt_offset)); +} + +void +TrexRpcCmdAddStream::parse_vm_instr_flow_var(const Json::Value &inst, TrexStream *stream, Json::Value &result) { + std::string flow_var_name = parse_string(inst, "name", result); + + auto sizes = {1, 2, 4, 8}; + uint8_t flow_var_size = parse_choice(inst, "size", sizes, result); + + auto ops = {"inc", "dec", "random"}; + std::string op_type_str = parse_choice(inst, "op", ops, result); + + StreamVmInstructionFlowMan::flow_var_op_e op_type; + + if (op_type_str == "inc") { + op_type = StreamVmInstructionFlowMan::FLOW_VAR_OP_INC; + } else if (op_type_str == "dec") { + op_type = StreamVmInstructionFlowMan::FLOW_VAR_OP_DEC; + } else if (op_type_str == "random") { + op_type = StreamVmInstructionFlowMan::FLOW_VAR_OP_RANDOM; + } else { + throw TrexRpcException("internal error"); + } + + std::string init_value_str = parse_string(inst, "init_value", result); + std::string min_value_str = parse_string(inst, "min_value", result); + std::string max_value_str = parse_string(inst, "max_value", result); + + uint64_t init_value; + uint64_t min_value; + uint64_t max_value; + + try { + init_value = str2num(init_value_str); + } catch (invalid_argument) { + generate_parse_err(result, "failed to parse 'init_value' as a number"); + } + + try { + min_value = str2num(min_value_str); + } catch (invalid_argument) { + generate_parse_err(result, "failed to parse 'min_value' as a number"); + } + + try { + max_value = str2num(max_value_str); + } catch (invalid_argument) { + generate_parse_err(result, "failed to parse 'max_value' as a number"); + } + + stream->m_vm.add_instruction(new StreamVmInstructionFlowMan(flow_var_name, + flow_var_size, + op_type, + init_value, + min_value, + max_value + )); +} + +void +TrexRpcCmdAddStream::parse_vm_instr_write_flow_var(const Json::Value &inst, TrexStream *stream, Json::Value &result) { + std::string flow_var_name = parse_string(inst, "flow_var_name", result); + uint16_t pkt_offset = parse_uint16(inst, "pkt_offset", result); + int add_value = parse_int(inst, "add_value", result); + bool is_big_endian = parse_bool(inst, "is_big_endian", result); + + stream->m_vm.add_instruction(new StreamVmInstructionWriteToPkt(flow_var_name, + pkt_offset, + add_value, + is_big_endian)); +} + +void +TrexRpcCmdAddStream::parse_vm(const Json::Value &vm, TrexStream *stream, Json::Value &result) { + /* array of VM instructions on vm */ + for (int i = 0; i < vm.size(); i++) { + const Json::Value & inst = vm[i]; + + auto vm_types = {"fix_checksum_ipv4", "flow_var", "write_flow_var"}; + std::string vm_type = parse_choice(inst, "type", vm_types, result); + + // checksum instruction + if (vm_type == "fix_checksum_ipv4") { + parse_vm_instr_checksum(inst, stream, result); + + } else if (vm_type == "flow_var") { + parse_vm_instr_flow_var(inst, stream, result); + + } else if (vm_type == "write_flow_var") { + parse_vm_instr_write_flow_var(inst, stream, result); + + } else { + /* internal error */ + throw TrexRpcException("internal error"); + } + } +} + void TrexRpcCmdAddStream::validate_stream(const TrexStream *stream, Json::Value &result) { /* check packet size */ - if ( (stream->m_pkt_len < TrexStream::MIN_PKT_SIZE_BYTES) || (stream->m_pkt_len > TrexStream::MAX_PKT_SIZE_BYTES) ) { + if ( (stream->m_pkt.len < TrexStream::MIN_PKT_SIZE_BYTES) || (stream->m_pkt.len > TrexStream::MAX_PKT_SIZE_BYTES) ) { std::stringstream ss; ss << "bad packet size provided: should be between " << TrexStream::MIN_PKT_SIZE_BYTES << " and " << TrexStream::MAX_PKT_SIZE_BYTES; delete stream; @@ -150,15 +278,15 @@ TrexRpcCmdAddStream::validate_stream(const TrexStream *stream, Json::Value &resu } /* port id should be between 0 and count - 1 */ - if (stream->m_port_id >= get_trex_stateless()->get_port_count()) { + if (stream->m_port_id >= TrexStateless::get_instance().get_port_count()) { std::stringstream ss; - ss << "invalid port id - should be between 0 and " << (int)get_trex_stateless()->get_port_count() - 1; + ss << "invalid port id - should be between 0 and " << (int)TrexStateless::get_instance().get_port_count() - 1; delete stream; generate_execute_err(result, ss.str()); } /* add the stream to the port's stream table */ - TrexStatelessPort * port = get_trex_stateless()->get_port_by_id(stream->m_port_id); + TrexStatelessPort * port = TrexStateless::get_instance().get_port_by_id(stream->m_port_id); /* does such a stream exists ? */ if (port->get_stream_table()->get_stream_by_id(stream->m_stream_id)) { @@ -180,13 +308,13 @@ TrexRpcCmdRemoveStream::_run(const Json::Value ¶ms, Json::Value &result) { uint32_t stream_id = parse_int(params, "stream_id", result); - if (port_id >= get_trex_stateless()->get_port_count()) { + if (port_id >= TrexStateless::get_instance().get_port_count()) { std::stringstream ss; - ss << "invalid port id - should be between 0 and " << (int)get_trex_stateless()->get_port_count() - 1; + ss << "invalid port id - should be between 0 and " << (int)TrexStateless::get_instance().get_port_count() - 1; generate_execute_err(result, ss.str()); } - TrexStatelessPort *port = get_trex_stateless()->get_port_by_id(port_id); + TrexStatelessPort *port = TrexStateless::get_instance().get_port_by_id(port_id); TrexStream *stream = port->get_stream_table()->get_stream_by_id(stream_id); if (!stream) { @@ -196,8 +324,11 @@ TrexRpcCmdRemoveStream::_run(const Json::Value ¶ms, Json::Value &result) { } port->get_stream_table()->remove_stream(stream); + delete stream; result["result"] = "ACK"; + + return (TREX_RPC_CMD_OK); } /*************************** @@ -209,15 +340,164 @@ trex_rpc_cmd_rc_e TrexRpcCmdRemoveAllStreams::_run(const Json::Value ¶ms, Json::Value &result) { uint8_t port_id = parse_byte(params, "port_id", result); - if (port_id >= get_trex_stateless()->get_port_count()) { + if (port_id >= TrexStateless::get_instance().get_port_count()) { std::stringstream ss; - ss << "invalid port id - should be between 0 and " << (int)get_trex_stateless()->get_port_count() - 1; + ss << "invalid port id - should be between 0 and " << (int)TrexStateless::get_instance().get_port_count() - 1; generate_execute_err(result, ss.str()); } - TrexStatelessPort *port = get_trex_stateless()->get_port_by_id(port_id); + TrexStatelessPort *port = TrexStateless::get_instance().get_port_by_id(port_id); port->get_stream_table()->remove_and_delete_all_streams(); result["result"] = "ACK"; + + return (TREX_RPC_CMD_OK); +} + +/*************************** + * get all streams configured + * on a specific port + * + **************************/ +trex_rpc_cmd_rc_e +TrexRpcCmdGetStreamList::_run(const Json::Value ¶ms, Json::Value &result) { + std::vector<uint32_t> stream_list; + + uint8_t port_id = parse_byte(params, "port_id", result); + + if (port_id >= TrexStateless::get_instance().get_port_count()) { + std::stringstream ss; + ss << "invalid port id - should be between 0 and " << (int)TrexStateless::get_instance().get_port_count() - 1; + generate_execute_err(result, ss.str()); + } + + TrexStatelessPort *port = TrexStateless::get_instance().get_port_by_id(port_id); + + port->get_stream_table()->get_stream_list(stream_list); + + Json::Value json_list = Json::arrayValue; + + for (auto stream_id : stream_list) { + json_list.append(stream_id); + } + + result["result"] = json_list; + + return (TREX_RPC_CMD_OK); +} + +/*************************** + * get stream by id + * on a specific port + * + **************************/ +trex_rpc_cmd_rc_e +TrexRpcCmdGetStream::_run(const Json::Value ¶ms, Json::Value &result) { + uint8_t port_id = parse_byte(params, "port_id", result); + + uint32_t stream_id = parse_int(params, "stream_id", result); + + if (port_id >= TrexStateless::get_instance().get_port_count()) { + std::stringstream ss; + ss << "invalid port id - should be between 0 and " << (int)TrexStateless::get_instance().get_port_count() - 1; + generate_execute_err(result, ss.str()); + } + + TrexStatelessPort *port = TrexStateless::get_instance().get_port_by_id(port_id); + + TrexStream *stream = port->get_stream_table()->get_stream_by_id(stream_id); + + if (!stream) { + std::stringstream ss; + ss << "stream id " << stream_id << " on port " << (int)port_id << " does not exists"; + generate_execute_err(result, ss.str()); + } + + Json::Value stream_json; + + stream_json["enabled"] = stream->m_enabled; + stream_json["self_start"] = stream->m_self_start; + + stream_json["isg"] = stream->m_isg_usec; + stream_json["next_stream_id"] = stream->m_next_stream_id; + + stream_json["packet"]["binary"] = Json::arrayValue; + for (int i = 0; i < stream->m_pkt.len; i++) { + stream_json["packet"]["binary"].append(stream->m_pkt.binary[i]); + } + + stream_json["packet"]["meta"] = stream->m_pkt.meta; + + if (TrexStreamContinuous *cont = dynamic_cast<TrexStreamContinuous *>(stream)) { + stream_json["mode"]["type"] = "continuous"; + stream_json["mode"]["pps"] = cont->get_pps(); + + } + + result["result"]["stream"] = stream_json; + + return (TREX_RPC_CMD_OK); +} + +/*************************** + * start traffic on port + * + **************************/ +trex_rpc_cmd_rc_e +TrexRpcCmdStartTraffic::_run(const Json::Value ¶ms, Json::Value &result) { + uint8_t port_id = parse_byte(params, "port_id", result); + + if (port_id >= TrexStateless::get_instance().get_port_count()) { + std::stringstream ss; + ss << "invalid port id - should be between 0 and " << (int)TrexStateless::get_instance().get_port_count() - 1; + generate_execute_err(result, ss.str()); + } + + TrexStatelessPort *port = TrexStateless::get_instance().get_port_by_id(port_id); + + TrexStatelessPort::traffic_rc_e rc = port->start_traffic(); + + if (rc == TrexStatelessPort::TRAFFIC_OK) { + result["result"] = "ACK"; + } else { + std::stringstream ss; + switch (rc) { + case TrexStatelessPort::TRAFFIC_ERR_ALREADY_STARTED: + ss << "traffic has already started on that port"; + break; + case TrexStatelessPort::TRAFFIC_ERR_NO_STREAMS: + ss << "no active streams on that port"; + break; + default: + ss << "failed to start traffic"; + break; + } + + generate_execute_err(result, ss.str()); + } + + return (TREX_RPC_CMD_OK); +} + +/*************************** + * start traffic on port + * + **************************/ +trex_rpc_cmd_rc_e +TrexRpcCmdStopTraffic::_run(const Json::Value ¶ms, Json::Value &result) { + uint8_t port_id = parse_byte(params, "port_id", result); + + if (port_id >= TrexStateless::get_instance().get_port_count()) { + std::stringstream ss; + ss << "invalid port id - should be between 0 and " << (int)TrexStateless::get_instance().get_port_count() - 1; + generate_execute_err(result, ss.str()); + } + + TrexStatelessPort *port = TrexStateless::get_instance().get_port_by_id(port_id); + + port->stop_traffic(); + result["result"] = "ACK"; + + return (TREX_RPC_CMD_OK); } diff --git a/src/rpc-server/commands/trex_rpc_cmds.h b/src/rpc-server/commands/trex_rpc_cmds.h index 64551fac..f88631bc 100644 --- a/src/rpc-server/commands/trex_rpc_cmds.h +++ b/src/rpc-server/commands/trex_rpc_cmds.h @@ -65,13 +65,23 @@ TREX_RPC_CMD_DEFINE(TrexRpcCmdGetStatus, "get_status", 0); TREX_RPC_CMD_DEFINE(TrexRpcCmdRemoveAllStreams, "remove_all_streams", 1); TREX_RPC_CMD_DEFINE(TrexRpcCmdRemoveStream, "remove_stream", 2); -TREX_RPC_CMD_DEFINE_EXTENED(TrexRpcCmdAddStream, "add_stream", 1, +TREX_RPC_CMD_DEFINE_EXTENED(TrexRpcCmdAddStream, "add_stream", 3, /* extended part */ -TrexStream * allocate_new_stream(const Json::Value §ion, Json::Value &result); +TrexStream * allocate_new_stream(const Json::Value §ion, uint8_t port_id, uint32_t stream_id, Json::Value &result); void validate_stream(const TrexStream *stream, Json::Value &result); - +void parse_vm(const Json::Value &vm, TrexStream *stream, Json::Value &result); +void parse_vm_instr_checksum(const Json::Value &inst, TrexStream *stream, Json::Value &result); +void parse_vm_instr_flow_var(const Json::Value &inst, TrexStream *stream, Json::Value &result); +void parse_vm_instr_write_flow_var(const Json::Value &inst, TrexStream *stream, Json::Value &result); ); +TREX_RPC_CMD_DEFINE(TrexRpcCmdGetStreamList, "get_stream_list", 1); + +TREX_RPC_CMD_DEFINE(TrexRpcCmdGetStream, "get_stream", 2); + +TREX_RPC_CMD_DEFINE(TrexRpcCmdStartTraffic, "start_traffic", 1); +TREX_RPC_CMD_DEFINE(TrexRpcCmdStopTraffic, "stop_traffic", 1); + #endif /* __TREX_RPC_CMD_H__ */ diff --git a/src/rpc-server/trex_rpc_cmd.cpp b/src/rpc-server/trex_rpc_cmd.cpp index 6988cba7..3fc77f71 100644 --- a/src/rpc-server/trex_rpc_cmd.cpp +++ b/src/rpc-server/trex_rpc_cmd.cpp @@ -50,6 +50,8 @@ TrexRpcCommand::type_to_str(field_type_e type) { switch (type) { case FIELD_TYPE_BYTE: return "byte"; + case FIELD_TYPE_UINT16: + return "uint16"; case FIELD_TYPE_BOOL: return "bool"; case FIELD_TYPE_INT: @@ -107,6 +109,18 @@ TrexRpcCommand::parse_byte(const Json::Value &parent, int index, Json::Value &re return parent[index].asUInt(); } +uint16_t +TrexRpcCommand::parse_uint16(const Json::Value &parent, const std::string &name, Json::Value &result) { + check_field_type(parent, name, FIELD_TYPE_UINT16, result); + return parent[name].asUInt(); +} + +uint16_t +TrexRpcCommand::parse_uint16(const Json::Value &parent, int index, Json::Value &result) { + check_field_type(parent, index, FIELD_TYPE_UINT16, result); + return parent[index].asUInt(); +} + int TrexRpcCommand::parse_int(const Json::Value &parent, const std::string &name, Json::Value &result) { check_field_type(parent, name, FIELD_TYPE_INT, result); @@ -190,6 +204,12 @@ TrexRpcCommand::check_field_type_common(const Json::Value &field, const std::str } break; + case FIELD_TYPE_UINT16: + if ( (!field.isUInt()) || (field.asInt() > 0xFFFF)) { + rc = false; + } + break; + case FIELD_TYPE_BOOL: if (!field.isBool()) { rc = false; diff --git a/src/rpc-server/trex_rpc_cmd_api.h b/src/rpc-server/trex_rpc_cmd_api.h index da895809..def52fca 100644 --- a/src/rpc-server/trex_rpc_cmd_api.h +++ b/src/rpc-server/trex_rpc_cmd_api.h @@ -91,6 +91,7 @@ protected: */ enum field_type_e { FIELD_TYPE_BYTE, + FIELD_TYPE_UINT16, FIELD_TYPE_INT, FIELD_TYPE_DOUBLE, FIELD_TYPE_BOOL, @@ -115,6 +116,7 @@ protected: * */ uint8_t parse_byte(const Json::Value &parent, const std::string &name, Json::Value &result); + uint16_t parse_uint16(const Json::Value &parent, const std::string &name, Json::Value &result); int parse_int(const Json::Value &parent, const std::string &name, Json::Value &result); double parse_double(const Json::Value &parent, const std::string &name, Json::Value &result); bool parse_bool(const Json::Value &parent, const std::string &name, Json::Value &result); @@ -123,6 +125,7 @@ protected: const Json::Value & parse_array(const Json::Value &parent, const std::string &name, Json::Value &result); uint8_t parse_byte(const Json::Value &parent, int index, Json::Value &result); + uint16_t parse_uint16(const Json::Value &parent, int index, Json::Value &result); int parse_int(const Json::Value &parent, int index, Json::Value &result); double parse_double(const Json::Value &parent, int index, Json::Value &result); bool parse_bool(const Json::Value &parent, int index, Json::Value &result); @@ -131,6 +134,39 @@ protected: const Json::Value & parse_array(const Json::Value &parent, int index, Json::Value &result); /** + * parse a field from choices + * + */ + template<typename T> T parse_choice(const Json::Value ¶ms, const std::string &name, std::initializer_list<T> choices, Json::Value &result) { + const Json::Value &field = params[name]; + + if (field == Json::Value::null) { + std::stringstream ss; + ss << "field '" << name << "' is missing"; + generate_parse_err(result, ss.str()); + } + + for (auto x : choices) { + if (field == x) { + return (x); + } + } + + std::stringstream ss; + + ss << "field '" << name << "' can only be one of ["; + for (auto x : choices) { + ss << "'" << x << "' ,"; + } + + std::string s = ss.str(); + s.pop_back(); + s.pop_back(); + s += "]"; + generate_parse_err(result, s); + } + + /** * check field type * */ diff --git a/src/rpc-server/trex_rpc_cmds_table.cpp b/src/rpc-server/trex_rpc_cmds_table.cpp index 7d5d49ae..71668994 100644 --- a/src/rpc-server/trex_rpc_cmds_table.cpp +++ b/src/rpc-server/trex_rpc_cmds_table.cpp @@ -38,6 +38,10 @@ TrexRpcCommandsTable::TrexRpcCommandsTable() { register_command(new TrexRpcCmdAddStream()); register_command(new TrexRpcCmdRemoveStream()); register_command(new TrexRpcCmdRemoveAllStreams()); + register_command(new TrexRpcCmdGetStreamList()); + register_command(new TrexRpcCmdGetStream()); + register_command(new TrexRpcCmdStartTraffic()); + register_command(new TrexRpcCmdStopTraffic()); } TrexRpcCommandsTable::~TrexRpcCommandsTable() { diff --git a/src/rpc-server/trex_rpc_jsonrpc_v2_parser.cpp b/src/rpc-server/trex_rpc_jsonrpc_v2_parser.cpp index 3831bb37..928baca6 100644 --- a/src/rpc-server/trex_rpc_jsonrpc_v2_parser.cpp +++ b/src/rpc-server/trex_rpc_jsonrpc_v2_parser.cpp @@ -200,3 +200,28 @@ void TrexJsonRpcV2Parser::parse_single_request(Json::Value &request, commands.push_back(new JsonRpcMethod(msg_id, rpc_cmd, request["params"])); } +/** + * tries to pretty a JSON str + * + * @author imarom (03-Sep-15) + * + * @param json_str + * + * @return std::string + */ +std::string TrexJsonRpcV2Parser::pretty_json_str(const std::string &json_str) { + Json::Reader reader; + Json::Value value; + + /* basic JSON parsing */ + bool rc = reader.parse(json_str, value, false); + if (!rc) { + /* duplicate the soruce */ + return json_str; + } + + /* successfully parsed */ + Json::StyledWriter writer; + return writer.write(value); +} + diff --git a/src/rpc-server/trex_rpc_jsonrpc_v2_parser.h b/src/rpc-server/trex_rpc_jsonrpc_v2_parser.h index 3367ad6a..ebffaeb7 100644 --- a/src/rpc-server/trex_rpc_jsonrpc_v2_parser.h +++ b/src/rpc-server/trex_rpc_jsonrpc_v2_parser.h @@ -79,6 +79,14 @@ public: */ void parse(std::vector<TrexJsonRpcV2ParsedObject *> &commands); + /** + * *tries* to generate a pretty string from JSON + * if json_str is not a valid JSON string + * it will duplicate the source + * + */ + static std::string pretty_json_str(const std::string &json_str); + private: /** diff --git a/src/rpc-server/trex_rpc_req_resp_server.cpp b/src/rpc-server/trex_rpc_req_resp_server.cpp index 7484758d..c4d9dfdb 100644 --- a/src/rpc-server/trex_rpc_req_resp_server.cpp +++ b/src/rpc-server/trex_rpc_req_resp_server.cpp @@ -85,7 +85,7 @@ void TrexRpcServerReqRes::_rpc_thread_cb() { /* transform it to a string */ std::string request((const char *)m_msg_buffer, msg_size); - verbose_msg("Server Received: " + request); + verbose_json("Server Received: ", TrexJsonRpcV2Parser::pretty_json_str(request)); handle_request(request); } @@ -110,6 +110,7 @@ void TrexRpcServerReqRes::_stop_rpc_thread() { */ void TrexRpcServerReqRes::handle_request(const std::string &request) { std::vector<TrexJsonRpcV2ParsedObject *> commands; + Json::FastWriter writer; Json::Value response; @@ -139,7 +140,7 @@ void TrexRpcServerReqRes::handle_request(const std::string &request) { response_str = writer.write(response); } - verbose_msg("Server Replied: " + response_str); + verbose_json("Server Replied: ", response_str); zmq_send(m_socket, response_str.c_str(), response_str.size(), 0); diff --git a/src/rpc-server/trex_rpc_server.cpp b/src/rpc-server/trex_rpc_server.cpp index 366bfc5b..149bb668 100644 --- a/src/rpc-server/trex_rpc_server.cpp +++ b/src/rpc-server/trex_rpc_server.cpp @@ -21,6 +21,7 @@ limitations under the License. #include <trex_rpc_server_api.h> #include <trex_rpc_req_resp_server.h> +#include <trex_rpc_jsonrpc_v2_parser.h> #include <unistd.h> #include <zmq.h> #include <sstream> @@ -47,6 +48,10 @@ void TrexRpcServerInterface::verbose_msg(const std::string &msg) { std::cout << "[verbose][" << m_name << "] " << msg << "\n"; } +void TrexRpcServerInterface::verbose_json(const std::string &msg, const std::string &json_str) { + verbose_msg(msg + "\n\n" + TrexJsonRpcV2Parser::pretty_json_str(json_str)); +} + /** * starts a RPC specific server * @@ -106,6 +111,7 @@ get_current_date_time() { } const std::string TrexRpcServer::s_server_uptime = get_current_date_time(); +std::string TrexRpcServer::s_owner = "none"; TrexRpcServer::TrexRpcServer(const TrexRpcServerConfig &req_resp_cfg) { diff --git a/src/rpc-server/trex_rpc_server_api.h b/src/rpc-server/trex_rpc_server_api.h index 6bb81c73..b4313670 100644 --- a/src/rpc-server/trex_rpc_server_api.h +++ b/src/rpc-server/trex_rpc_server_api.h @@ -115,6 +115,13 @@ protected: */ void verbose_msg(const std::string &msg); + /** + * prints a verbose message with a JSON to be converted to + * string + * + */ + void verbose_json(const std::string &msg, const std::string &json_str); + TrexRpcServerConfig m_cfg; bool m_is_running; bool m_is_verbose; @@ -156,10 +163,34 @@ public: return s_server_uptime; } + + /** + * query for ownership + * + */ + static const std::string &get_owner() { + return s_owner; + } + + /** + * take ownership of the server array + * this is static + * ownership is total + * + */ + static void set_owner(const std::string &owner) { + s_owner = owner; + } + + static void clear_owner() { + s_owner = "none"; + } + private: std::vector<TrexRpcServerInterface *> m_servers; bool m_verbose; static const std::string s_server_uptime; + static std::string s_owner; }; #endif /* __TREX_RPC_SERVER_API_H__ */ diff --git a/src/rpc-server/trex_rpc_server_mock.cpp b/src/rpc-server/trex_rpc_server_mock.cpp index 98d1f35d..835e28b8 100644 --- a/src/rpc-server/trex_rpc_server_mock.cpp +++ b/src/rpc-server/trex_rpc_server_mock.cpp @@ -20,6 +20,8 @@ limitations under the License. */ #include <trex_rpc_server_api.h> +#include <trex_stateless_api.h> + #include <iostream> #include <unistd.h> @@ -42,6 +44,9 @@ int gtest_main(int argc, char **argv); int main(int argc, char *argv[]) { + /* configure the stateless object with 4 ports */ + TrexStateless::configure(4); + // gtest ? if (argc > 1) { if (string(argv[1]) != "--ut") { |