summaryrefslogtreecommitdiffstats
path: root/src/rpc-server/commands/trex_rpc_cmd_stream.cpp
diff options
context:
space:
mode:
authorHanoh Haim <hhaim@cisco.com>2015-09-10 07:54:05 +0300
committerHanoh Haim <hhaim@cisco.com>2015-09-10 07:54:05 +0300
commita360a1734c459d62bd4c204a6005214ce8944f85 (patch)
treee06cad6cf63a52701aff303c19024cde1d541ebd /src/rpc-server/commands/trex_rpc_cmd_stream.cpp
parent15b4f7cd7c3e9176c1f24fc632791e833cb588b8 (diff)
parente33befcf222fd2108d589dede11069d4256bb21a (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/commands/trex_rpc_cmd_stream.cpp')
-rw-r--r--src/rpc-server/commands/trex_rpc_cmd_stream.cpp326
1 files changed, 303 insertions, 23 deletions
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 &params, 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 &section = parse_object(params, "stream", result);
/* get the type of the stream */
@@ -41,32 +61,40 @@ TrexRpcCmdAddStream::_run(const Json::Value &params, 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 &params, 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 &params, Json::Value &result) {
TrexStream *
-TrexRpcCmdAddStream::allocate_new_stream(const Json::Value &section, 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 &section, uint8_t port_id, uint32_t stream_id, Json::Value &result) {
TrexStream *stream;
@@ -138,11 +163,114 @@ TrexRpcCmdAddStream::allocate_new_stream(const Json::Value &section, 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 &params, 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 &params, 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 &params, 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 &params, 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 &params, 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 &params, 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 &params, 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);
}