From e33befcf222fd2108d589dede11069d4256bb21a Mon Sep 17 00:00:00 2001 From: imarom Date: Mon, 7 Sep 2015 16:27:12 +0300 Subject: added VM support to the streams and RPC parser --- src/rpc-server/commands/trex_rpc_cmd_stream.cpp | 124 ++++++++++++++++++++++++ src/rpc-server/commands/trex_rpc_cmds.h | 5 +- src/rpc-server/trex_rpc_cmd.cpp | 20 ++++ src/rpc-server/trex_rpc_cmd_api.h | 36 +++++++ 4 files changed, 184 insertions(+), 1 deletion(-) (limited to 'src/rpc-server') diff --git a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp index 16889413..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 * @@ -74,6 +91,10 @@ TrexRpcCmdAddStream::_run(const Json::Value ¶ms, Json::Value &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); @@ -142,6 +163,109 @@ TrexRpcCmdAddStream::allocate_new_stream(const Json::Value §ion, uint8_t por } +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) { diff --git a/src/rpc-server/commands/trex_rpc_cmds.h b/src/rpc-server/commands/trex_rpc_cmds.h index 428d48c1..f88631bc 100644 --- a/src/rpc-server/commands/trex_rpc_cmds.h +++ b/src/rpc-server/commands/trex_rpc_cmds.h @@ -70,7 +70,10 @@ TREX_RPC_CMD_DEFINE_EXTENED(TrexRpcCmdAddStream, "add_stream", 3, /* extended part */ 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); ); 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); @@ -130,6 +133,39 @@ protected: const Json::Value & parse_object(const Json::Value &parent, int index, Json::Value &result); const Json::Value & parse_array(const Json::Value &parent, int index, Json::Value &result); + /** + * parse a field from choices + * + */ + template T parse_choice(const Json::Value ¶ms, const std::string &name, std::initializer_list 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 * -- cgit 1.2.3-korg