summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/bp_gtest.cpp37
-rwxr-xr-xsrc/bp_sim.cpp48
-rwxr-xr-xsrc/bp_sim.h1
-rwxr-xr-xsrc/common/captureFile.cpp2
-rwxr-xr-xsrc/common/pcap.cpp3
-rw-r--r--src/gtest/rpc_test.cpp513
-rw-r--r--src/gtest/trex_stateless_gtest.cpp353
-rw-r--r--src/rpc-server/commands/trex_rpc_cmd_general.cpp267
-rw-r--r--src/rpc-server/commands/trex_rpc_cmd_stream.cpp488
-rw-r--r--src/rpc-server/commands/trex_rpc_cmd_test.cpp51
-rw-r--r--src/rpc-server/commands/trex_rpc_cmds.h104
-rw-r--r--src/rpc-server/include/trex_rpc_cmd_api.h90
-rw-r--r--src/rpc-server/src/commands/trex_rpc_cmd_general.cpp49
-rw-r--r--src/rpc-server/src/commands/trex_rpc_cmd_test.cpp126
-rw-r--r--src/rpc-server/src/commands/trex_rpc_cmds.h89
-rw-r--r--src/rpc-server/trex_rpc_cmd.cpp317
-rw-r--r--src/rpc-server/trex_rpc_cmd_api.h241
-rw-r--r--src/rpc-server/trex_rpc_cmds_table.cpp (renamed from src/rpc-server/src/trex_rpc_cmds_table.cpp)20
-rw-r--r--src/rpc-server/trex_rpc_cmds_table.h (renamed from src/rpc-server/include/trex_rpc_cmds_table.h)0
-rw-r--r--src/rpc-server/trex_rpc_exception_api.h (renamed from src/rpc-server/include/trex_rpc_exception_api.h)3
-rw-r--r--src/rpc-server/trex_rpc_jsonrpc_v2_parser.cpp (renamed from src/rpc-server/src/trex_rpc_jsonrpc_v2_parser.cpp)53
-rw-r--r--src/rpc-server/trex_rpc_jsonrpc_v2_parser.h (renamed from src/rpc-server/include/trex_rpc_jsonrpc_v2_parser.h)17
-rw-r--r--src/rpc-server/trex_rpc_req_resp_server.cpp (renamed from src/rpc-server/src/trex_rpc_req_resp_server.cpp)32
-rw-r--r--src/rpc-server/trex_rpc_req_resp_server.h (renamed from src/rpc-server/include/trex_rpc_req_resp_server.h)4
-rw-r--r--src/rpc-server/trex_rpc_server.cpp (renamed from src/rpc-server/src/trex_rpc_server.cpp)5
-rw-r--r--src/rpc-server/trex_rpc_server_api.h (renamed from src/rpc-server/include/trex_rpc_server_api.h)15
-rw-r--r--src/rpc-server/trex_rpc_server_mock.cpp (renamed from src/rpc-server/src/trex_rpc_server_mock.cpp)7
-rwxr-xr-xsrc/rx_check.cpp14
-rwxr-xr-xsrc/rx_check_header.h3
-rw-r--r--src/stateless/trex_stateless.cpp152
-rw-r--r--src/stateless/trex_stateless_api.h213
-rw-r--r--src/stateless/trex_stream.cpp116
-rw-r--r--src/stateless/trex_stream_api.h209
-rw-r--r--src/stateless/trex_stream_vm.cpp54
-rw-r--r--src/stateless/trex_stream_vm.h171
-rwxr-xr-xsrc/timer_wheel_pq.cpp7
36 files changed, 3437 insertions, 437 deletions
diff --git a/src/bp_gtest.cpp b/src/bp_gtest.cpp
index 020276cf..78efbecb 100755
--- a/src/bp_gtest.cpp
+++ b/src/bp_gtest.cpp
@@ -1426,6 +1426,8 @@ TEST_F(rx_check, rx_check_normal) {
for (i=0; i<10; i++) {
CRx_check_header rxh;
+ rxh.clean();
+
rxh.m_option_type=RX_CHECK_V4_OPT_TYPE;
rxh.m_option_len=RX_CHECK_V4_OPT_LEN;
rxh.m_time_stamp=0;
@@ -1454,6 +1456,8 @@ TEST_F(rx_check, rx_check_drop) {
for (i=0; i<10; i++) {
CRx_check_header rxh;
+ rxh.clean();
+
rxh.m_option_type=RX_CHECK_V4_OPT_TYPE;
rxh.m_option_len=RX_CHECK_V4_OPT_LEN;
rxh.m_time_stamp=0;
@@ -1490,8 +1494,10 @@ TEST_F(rx_check, rx_check_ooo) {
for (i=0; i<10; i++) {
CRx_check_header rxh;
- rxh.m_option_type=RX_CHECK_V4_OPT_TYPE;
- rxh.m_option_len=RX_CHECK_V4_OPT_LEN;
+ rxh.clean();
+
+ rxh.m_option_type=RX_CHECK_V4_OPT_TYPE;
+ rxh.m_option_len=RX_CHECK_V4_OPT_LEN;
rxh.m_time_stamp=0;
rxh.m_magic=RX_CHECK_MAGIC;
rxh.m_aging_sec=10;
@@ -1531,8 +1537,9 @@ TEST_F(rx_check, rx_check_ooo_1) {
for (i=0; i<10; i++) {
CRx_check_header rxh;
- rxh.m_option_type=RX_CHECK_V4_OPT_TYPE;
- rxh.m_option_len=RX_CHECK_V4_OPT_LEN;
+ rxh.clean();
+ rxh.m_option_type=RX_CHECK_V4_OPT_TYPE;
+ rxh.m_option_len=RX_CHECK_V4_OPT_LEN;
rxh.m_time_stamp=0;
rxh.set_dir(0);
rxh.set_both_dir(0);
@@ -1568,8 +1575,9 @@ TEST_F(rx_check, rx_check_ooo_2) {
for (i=0; i<10; i++) {
CRx_check_header rxh;
- rxh.m_option_type=RX_CHECK_V4_OPT_TYPE;
- rxh.m_option_len=RX_CHECK_V4_OPT_LEN;
+ rxh.clean();
+ rxh.m_option_type=RX_CHECK_V4_OPT_TYPE;
+ rxh.m_option_len=RX_CHECK_V4_OPT_LEN;
rxh.m_time_stamp=0;
rxh.m_magic=RX_CHECK_MAGIC;
rxh.m_aging_sec=10;
@@ -1606,6 +1614,7 @@ TEST_F(rx_check, rx_check_normal_two_dir) {
for (i=0; i<10; i++) {
CRx_check_header rxh;
+ rxh.clean();
rxh.m_option_type=RX_CHECK_V4_OPT_TYPE;
rxh.m_option_len=RX_CHECK_V4_OPT_LEN;
rxh.m_time_stamp=0;
@@ -1635,6 +1644,7 @@ TEST_F(rx_check, rx_check_normal_two_dir_fails) {
for (i=0; i<10; i++) {
CRx_check_header rxh;
+ rxh.clean();
rxh.m_option_type=RX_CHECK_V4_OPT_TYPE;
rxh.m_option_len=RX_CHECK_V4_OPT_LEN;
rxh.m_time_stamp=0;
@@ -1661,6 +1671,8 @@ TEST_F(rx_check, rx_check_normal_two_dir_ok) {
int i;
CRx_check_header rxh;
+ rxh.clean();
+
rxh.m_option_type=RX_CHECK_V4_OPT_TYPE;
rxh.m_option_len=RX_CHECK_V4_OPT_LEN;
rxh.m_time_stamp=0;
@@ -1695,6 +1707,8 @@ TEST_F(rx_check, rx_check_normal_one_pkt_one_dir) {
int i;
CRx_check_header rxh;
+ rxh.clean();
+
rxh.m_option_type=RX_CHECK_V4_OPT_TYPE;
rxh.m_option_len=RX_CHECK_V4_OPT_LEN;
rxh.m_time_stamp=0;
@@ -1721,6 +1735,8 @@ TEST_F(rx_check, rx_check_normal_one_pkt_one_dir_0) {
int i;
CRx_check_header rxh;
+ rxh.clean();
+
rxh.m_option_type=RX_CHECK_V4_OPT_TYPE;
rxh.m_option_len=RX_CHECK_V4_OPT_LEN;
rxh.m_time_stamp=0;
@@ -1746,6 +1762,8 @@ TEST_F(rx_check, rx_check_normal_one_pkt_two_dir_0) {
int i;
CRx_check_header rxh;
+ rxh.clean();
+
rxh.m_option_type=RX_CHECK_V4_OPT_TYPE;
rxh.m_option_len=RX_CHECK_V4_OPT_LEN;
rxh.m_time_stamp=0;
@@ -1778,6 +1796,8 @@ TEST_F(rx_check, rx_check_normal_one_pkt_two_dir_err1) {
int i;
CRx_check_header rxh;
+ rxh.clean();
+
rxh.m_option_type=RX_CHECK_V4_OPT_TYPE;
rxh.m_option_len=RX_CHECK_V4_OPT_LEN;
rxh.m_time_stamp=0;
@@ -1821,6 +1841,8 @@ TEST_F(rx_check, rx_check_normal_two_dir_oo) {
int i;
CRx_check_header rxh;
+ rxh.clean();
+
rxh.m_option_type=RX_CHECK_V4_OPT_TYPE;
rxh.m_option_len=RX_CHECK_V4_OPT_LEN;
rxh.m_time_stamp=0;
@@ -1865,6 +1887,8 @@ TEST_F(rx_check, rx_check_normal_aging) {
int i;
CRx_check_header rxh;
+ rxh.clean();
+
rxh.m_option_type=RX_CHECK_V4_OPT_TYPE;
rxh.m_option_len=RX_CHECK_V4_OPT_LEN;
rxh.m_magic=RX_CHECK_MAGIC;
@@ -1899,6 +1923,7 @@ TEST_F(rx_check, rx_check_normal_no_aging) {
int i;
CRx_check_header rxh;
+ rxh.clean();
rxh.m_option_type=RX_CHECK_V4_OPT_TYPE;
rxh.m_option_len=RX_CHECK_V4_OPT_LEN;
rxh.m_magic=RX_CHECK_MAGIC;
diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp
index f81ef446..8a8bc5f9 100755
--- a/src/bp_sim.cpp
+++ b/src/bp_sim.cpp
@@ -1148,13 +1148,6 @@ void CPacketIndication::ProcessIpPacket(CPacketParser *parser,
}
offset += ip_header_length;
- if (!l3.m_ipv4->isChecksumOK() ){
- m_cnt->m_ip_checksum_error++;
- }
- if( l3.m_ipv4->isMulticast() ){
- m_cnt->m_ip_multicast_error++;
- return;
- }
if( l3.m_ipv4->getTimeToLive() ==0 ){
m_cnt->m_ip_ttl_is_zero_error++;
@@ -1177,10 +1170,19 @@ void CPacketIndication::ProcessIpPacket(CPacketParser *parser,
return;
}
+ if ( m_packet->pkt_len > MAX_BUF_SIZE -FIRST_PKT_SIZE ){
+ m_cnt->m_tcp_udp_pkt_length_error++;
+ printf("ERROR packet is too big, not supported jumbo packets that larger than %d \n",MAX_BUF_SIZE);
+ return;
+ }
+
// Set packet length and include padding if needed
m_packet->pkt_len = l3.m_ipv4->getTotalLength() + getIpOffset();
if (m_packet->pkt_len < 60) { m_packet->pkt_len = 60; }
+
+
+
m_cnt->m_valid_udp_tcp++;
m_payload_len = l3.m_ipv4->getTotalLength() - (payload_offset_from_ip);
m_payload = (uint8_t *)(packetBase +offset);
@@ -1294,7 +1296,9 @@ bool CPacketIndication::ConvertPacketToIpv6InPlace(CCapPktRaw * pkt,
void CPacketIndication::ProcessPacket(CPacketParser *parser,
CCapPktRaw * pkt){
_ProcessPacket(parser,pkt);
- UpdateOffsets(); /* update fast offsets */
+ if ( m_desc.IsValidPkt() ){
+ UpdateOffsets(); /* update fast offsets */
+ }
}
@@ -2119,7 +2123,13 @@ int CCapFileFlowInfo::load_cap_file(std::string cap_file,uint16_t _id,uint8_t pl
}
}
+ }else{
+ printf("ERROR packet %d is not supported, should be IP(0x0800)/TCP/UDP format try to convert it using Wireshark !\n",cnt);
+ exit(-1);
}
+ }else{
+ printf("ERROR packet %d is not supported, should be IP(0x0800)/TCP/UDP format try to convert it using Wireshark !\n",cnt);
+ exit(-1);
}
}
@@ -4371,6 +4381,7 @@ int CErfIF::send_node(CGenNode * node){
CFlowPktInfo * lp=node->m_pkt_info;
rte_mbuf_t * m=lp->generate_new_mbuf(node);
+
fill_pkt(m_raw,m);
CPktNsecTimeStamp t_c(node->m_time);
m_raw->time_nsec = t_c.m_time_nsec;
@@ -4552,6 +4563,7 @@ void CCPortLatency::reset(){
m_tx_pkt_err=0;
m_tx_pkt_ok =0;
m_pkt_ok=0;
+ m_rx_check=0;
m_no_magic=0;
m_unsup_prot=0;
m_no_id=0;
@@ -5363,10 +5375,11 @@ void on_node_last(uint8_t plugin_id,CGenNode * node){
}
rte_mbuf_t * on_node_generate_mbuf(uint8_t plugin_id,CGenNode * node,CFlowPktInfo * pkt_info){
- if (CPluginCallback::callback) {
- CPluginCallback::callback->on_node_generate_mbuf(plugin_id,node,pkt_info);
- }
-
+ rte_mbuf_t * m;
+ assert(CPluginCallback::callback);
+ m=CPluginCallback::callback->on_node_generate_mbuf(plugin_id,node,pkt_info);
+ assert(m);
+ return(m);
}
@@ -6199,22 +6212,25 @@ rte_mbuf_t * CPluginCallbackSimple::rtsp_plugin(uint8_t plugin_id,CGenNode *
/* replace the tuples */
rte_mbuf_t * CPluginCallbackSimple::on_node_generate_mbuf(uint8_t plugin_id,CGenNode * node,CFlowPktInfo * pkt_info){
+
+ rte_mbuf_t * m=NULL;
switch (plugin_id) {
case mpRTSP:
- rtsp_plugin(plugin_id,node,pkt_info);
+ m=rtsp_plugin(plugin_id,node,pkt_info);
break;
case mpSIP_VOICE:
- sip_voice_plugin(plugin_id,node,pkt_info);
+ m=sip_voice_plugin(plugin_id,node,pkt_info);
break;
case mpDYN_PYLOAD:
- dyn_pyload_plugin(plugin_id,node,pkt_info);
+ m=dyn_pyload_plugin(plugin_id,node,pkt_info);
break;
case mpAVL_HTTP_BROWSIN:
- http_plugin(plugin_id,node,pkt_info);
+ m=http_plugin(plugin_id,node,pkt_info);
break;
default:
assert(0);
}
+ return (m);
}
diff --git a/src/bp_sim.h b/src/bp_sim.h
index 002c9d0a..7d659d1c 100755
--- a/src/bp_sim.h
+++ b/src/bp_sim.h
@@ -1249,6 +1249,7 @@ struct CFlowYamlInfo {
CFlowYamlInfo(){
m_dpPkt=0;
m_server_addr=0;
+ m_cap_mode=false;
}
std::string m_name;
diff --git a/src/common/captureFile.cpp b/src/common/captureFile.cpp
index a4fe78be..00625181 100755
--- a/src/common/captureFile.cpp
+++ b/src/common/captureFile.cpp
@@ -110,7 +110,7 @@ void CCapPktRaw::CloneShalow(CCapPktRaw *obj){
}
void CCapPktRaw::Dump(FILE *fd,int verbose){
- fprintf(fd," =>pkt (%p) %llu , len %d, time [%x:%x] \n",raw,pkt_cnt,pkt_len,time_sec,time_nsec);
+ fprintf(fd," =>pkt (%p) %llu , len %d, time [%x:%x] \n",raw, (unsigned long long)pkt_cnt,pkt_len,time_sec,time_nsec);
if (verbose) {
utl_DumpBuffer(fd,raw,pkt_len,0);
}
diff --git a/src/common/pcap.cpp b/src/common/pcap.cpp
index 6dd54514..9b360a3e 100755
--- a/src/common/pcap.cpp
+++ b/src/common/pcap.cpp
@@ -156,7 +156,8 @@ bool LibPCapReader::ReadPacket(CCapPktRaw *lpPacket)
}
if (pkt_header.len > READER_MAX_PACKET_SIZE) {
/* cannot read this packet */
- assert(0);
+ printf("ERROR packet is too big, bigger than %d \n",READER_MAX_PACKET_SIZE);
+ exit(-1);
return false;
}
diff --git a/src/gtest/rpc_test.cpp b/src/gtest/rpc_test.cpp
index 068457f3..168ee936 100644
--- a/src/gtest/rpc_test.cpp
+++ b/src/gtest/rpc_test.cpp
@@ -25,12 +25,23 @@ limitations under the License.
#include <zmq.h>
#include <json/json.h>
#include <sstream>
+#include <vector>
+#include <algorithm>
using namespace std;
class RpcTest : public testing::Test {
+protected:
+
+ void set_verbose(bool verbose) {
+ m_verbose = verbose;
+ }
+
virtual void SetUp() {
+
+ m_verbose = false;
+
TrexRpcServerConfig cfg = TrexRpcServerConfig(TrexRpcServerConfig::RPC_PROT_TCP, 5050);
m_rpc = new TrexRpcServer(cfg);
@@ -39,6 +50,7 @@ class RpcTest : public testing::Test {
m_context = zmq_ctx_new ();
m_socket = zmq_socket (m_context, ZMQ_REQ);
zmq_connect (m_socket, "tcp://localhost:5050");
+
}
virtual void TearDown() {
@@ -50,8 +62,41 @@ class RpcTest : public testing::Test {
}
public:
+
+ void create_request(Json::Value &request, const string &method, int id = 1) {
+ request.clear();
+
+ request["jsonrpc"] = "2.0";
+ request["id"] = id;
+ request["method"] = method;
+
+ }
+
+ void send_request(const Json::Value &request, Json::Value &response) {
+ Json::FastWriter writer;
+ Json::Reader reader;
+
+ response.clear();
+
+ string request_str = writer.write(request);
+
+ if (m_verbose) {
+ cout << "\n" << request_str << "\n";
+ }
+
+ string ret = send_msg(request_str);
+
+ if (m_verbose) {
+ cout << "\n" << ret << "\n";
+ }
+
+ EXPECT_TRUE(reader.parse(ret, response, false));
+ EXPECT_EQ(response["jsonrpc"], "2.0");
+ EXPECT_EQ(response["id"], request["id"]);
+ }
+
string send_msg(const string &msg) {
- char buffer[512];
+ char buffer[1024 * 20];
zmq_send (m_socket, msg.c_str(), msg.size(), 0);
int len = zmq_recv(m_socket, buffer, sizeof(buffer), 0);
@@ -62,9 +107,64 @@ public:
TrexRpcServer *m_rpc;
void *m_context;
void *m_socket;
+ bool m_verbose;
};
-TEST_F(RpcTest, basic_rpc_test) {
+class RpcTestOwned : public RpcTest {
+public:
+
+ void create_request(Json::Value &request, const string &method, int id = 1, int port_id = 1, bool owned = true) {
+ RpcTest::create_request(request, method, id);
+ if (owned) {
+ request["params"]["port_id"] = port_id;
+ request["params"]["handler"] = m_ownership_handler[port_id];
+ }
+ }
+
+protected:
+
+ virtual void SetUp() {
+ RpcTest::SetUp();
+
+ for (int i = 0 ; i < 4; i++) {
+ m_ownership_handler[i] = take_ownership(i);
+ }
+ }
+
+
+ string take_ownership(uint8_t port_id) {
+ Json::Value request;
+ Json::Value response;
+
+ RpcTest::create_request(request, "acquire", 1);
+
+ request["params"]["port_id"] = port_id;
+ request["params"]["user"] = "test";
+ request["params"]["force"] = true;
+
+ send_request(request, response);
+
+ EXPECT_TRUE(response["result"] != Json::nullValue);
+ return response["result"].asString();
+ }
+
+ void release_ownership(uint8_t port_id) {
+ Json::Value request;
+ Json::Value response;
+
+ RpcTest::create_request(request, "release", 1);
+
+ request["params"]["handler"] = m_ownership_handler;
+ request["params"]["port_id"] = port_id;
+
+ send_request(request, response);
+ EXPECT_TRUE(response["result"] == "ACK");
+ }
+
+ string m_ownership_handler[4];
+};
+
+TEST_F(RpcTest, basic_rpc_negative_cases) {
Json::Value request;
Json::Value response;
Json::Reader reader;
@@ -121,55 +221,39 @@ TEST_F(RpcTest, basic_rpc_test) {
TEST_F(RpcTest, test_add_command) {
Json::Value request;
Json::Value response;
- Json::Reader reader;
-
- string req_str;
- string resp_str;
- /* simple add - missing paramters */
- req_str = "{\"jsonrpc\": \"2.0\", \"method\": \"rpc_test_add\", \"id\": 488}";
- resp_str = send_msg(req_str);
+ /* missing parameters */
+ create_request(request, "test_add");
+ send_request(request, response);
- EXPECT_TRUE(reader.parse(resp_str, response, false));
EXPECT_EQ(response["jsonrpc"], "2.0");
- EXPECT_EQ(response["id"], 488);
EXPECT_EQ(response["error"]["code"], -32602);
- /* simple add that works */
- req_str = "{\"jsonrpc\": \"2.0\", \"method\": \"rpc_test_add\", \"params\": {\"x\": 17, \"y\": -13} , \"id\": \"itay\"}";
- resp_str = send_msg(req_str);
+ /* bad paramters */
+ create_request(request, "test_add");
+ request["params"]["x"] = 5;
+ request["params"]["y"] = "itay";
+ send_request(request, response);
- EXPECT_TRUE(reader.parse(resp_str, response, false));
- EXPECT_EQ(response["jsonrpc"], "2.0");
- EXPECT_EQ(response["id"], "itay");
- EXPECT_EQ(response["result"], 4);
-
- /* add with bad paratemers types */
- req_str = "{\"jsonrpc\": \"2.0\", \"method\": \"rpc_test_add\", \"params\": {\"x\": \"blah\", \"y\": -13} , \"id\": 17}";
- resp_str = send_msg(req_str);
-
- EXPECT_TRUE(reader.parse(resp_str, response, false));
EXPECT_EQ(response["jsonrpc"], "2.0");
- EXPECT_EQ(response["id"], 17);
EXPECT_EQ(response["error"]["code"], -32602);
- /* add with invalid count of parameters */
- req_str = "{\"jsonrpc\": \"2.0\", \"method\": \"rpc_test_add\", \"params\": {\"y\": -13} , \"id\": 17}";
- resp_str = send_msg(req_str);
+ /* simple add that works */
+ create_request(request, "test_add");
+ request["params"]["x"] = 5;
+ request["params"]["y"] = -13;
+ send_request(request, response);
- EXPECT_TRUE(reader.parse(resp_str, response, false));
EXPECT_EQ(response["jsonrpc"], "2.0");
- EXPECT_EQ(response["id"], 17);
- EXPECT_EQ(response["error"]["code"], -32602);
-
+ EXPECT_EQ(response["result"], -8);
/* big numbers */
- req_str = "{\"jsonrpc\": \"2.0\", \"method\": \"rpc_test_add\", \"params\": {\"x\": 4827371, \"y\": -39181273} , \"id\": \"itay\"}";
- resp_str = send_msg(req_str);
+ create_request(request, "test_add");
+ request["params"]["x"] = 4827371;
+ request["params"]["y"] = -39181273;
+ send_request(request, response);
- EXPECT_TRUE(reader.parse(resp_str, response, false));
EXPECT_EQ(response["jsonrpc"], "2.0");
- EXPECT_EQ(response["id"], "itay");
EXPECT_EQ(response["result"], -34353902);
}
@@ -183,12 +267,12 @@ TEST_F(RpcTest, batch_rpc_test) {
string resp_str;
req_str = "[ \
- {\"jsonrpc\": \"2.0\", \"method\": \"rpc_test_add\", \"params\": {\"x\": 22, \"y\": 17}, \"id\": \"1\"}, \
- {\"jsonrpc\": \"2.0\", \"method\": \"rpc_test_sub\", \"params\": {\"x\": 22, \"y\": 17}, \"id\": \"2\"}, \
- {\"jsonrpc\": \"2.0\", \"method\": \"rpc_test_add\", \"params\": {\"x\": 22, \"y\": \"itay\"}, \"id\": \"2\"}, \
+ {\"jsonrpc\": \"2.0\", \"method\": \"test_add\", \"params\": {\"x\": 22, \"y\": 17}, \"id\": \"1\"}, \
+ {\"jsonrpc\": \"2.0\", \"method\": \"test_sub\", \"params\": {\"x\": 22, \"y\": 17}, \"id\": \"2\"}, \
+ {\"jsonrpc\": \"2.0\", \"method\": \"test_add\", \"params\": {\"x\": 22, \"y\": \"itay\"}, \"id\": \"2\"}, \
{\"foo\": \"boo\"}, \
{\"jsonrpc\": \"2.0\", \"method\": \"test_rpc_sheker\", \"params\": {\"name\": \"myself\"}, \"id\": 5}, \
- {\"jsonrpc\": \"2.0\", \"method\": \"rpc_test_add\", \"params\": {\"x\": 22, \"y\": 17} } \
+ {\"jsonrpc\": \"2.0\", \"method\": \"test_add\", \"params\": {\"x\": 22, \"y\": 17} } \
]";
resp_str = send_msg(req_str);
@@ -224,3 +308,352 @@ TEST_F(RpcTest, batch_rpc_test) {
return;
}
+
+/* ping command */
+TEST_F(RpcTest, ping) {
+ Json::Value request;
+ Json::Value response;
+
+ create_request(request, "ping");
+ send_request(request, response);
+ EXPECT_TRUE(response["result"] == "ACK");
+}
+
+static bool
+find_member_in_array(const Json::Value &array, const string &member) {
+ for (auto x : array) {
+ if (x == member) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* get registered commands */
+TEST_F(RpcTest, get_supported_cmds) {
+ Json::Value request;
+ Json::Value response;
+
+ create_request(request, "get_supported_cmds");
+ send_request(request, response);
+ EXPECT_TRUE(response["result"].size() > 0);
+
+ EXPECT_TRUE(find_member_in_array(response["result"], "ping"));
+ EXPECT_TRUE(find_member_in_array(response["result"], "get_supported_cmds"));
+}
+
+/* get version */
+TEST_F(RpcTest, get_version) {
+ Json::Value request;
+ Json::Value response;
+
+ create_request(request, "get_version");
+ send_request(request, response);
+
+ EXPECT_TRUE(response["result"] != Json::nullValue);
+ EXPECT_TRUE(response["result"]["built_by"] == "MOCK");
+ EXPECT_TRUE(response["result"]["version"] == "v0.0");
+}
+
+/* get system info */
+TEST_F(RpcTest, get_system_info) {
+ Json::Value request;
+ Json::Value response;
+
+ create_request(request, "get_system_info");
+ send_request(request, response);
+
+ EXPECT_TRUE(response["result"] != Json::nullValue);
+ EXPECT_TRUE(response["result"]["core_type"].isString());
+ EXPECT_TRUE(response["result"]["hostname"].isString());
+ EXPECT_TRUE(response["result"]["uptime"].isString());
+ EXPECT_TRUE(response["result"]["dp_core_count"] > 0);
+ EXPECT_TRUE(response["result"]["port_count"] > 0);
+
+ EXPECT_TRUE(response["result"]["ports"].isArray());
+
+ const Json::Value &ports = response["result"]["ports"];
+
+
+ for (int i = 0; i < ports.size(); i++) {
+ EXPECT_TRUE(ports[i]["index"] == i);
+ EXPECT_TRUE(ports[i]["driver"].isString());
+ EXPECT_TRUE(ports[i]["speed"].isString());
+ }
+}
+
+/* get owner, acquire and release */
+TEST_F(RpcTest, get_owner_acquire_release) {
+ Json::Value request;
+ Json::Value response;
+
+ /* no user before acquring */
+ create_request(request, "get_owner");
+ request["params"]["port_id"] = 1;
+ send_request(request, response);
+ EXPECT_TRUE(response["result"] != Json::nullValue);
+
+ EXPECT_TRUE(response["result"]["owner"] == "none");
+
+ /* soft acquire */
+ create_request(request, "acquire");
+ request["params"]["port_id"] = 1;
+ request["params"]["user"] = "itay";
+ request["params"]["force"] = false;
+
+ send_request(request, response);
+ EXPECT_TRUE(response["result"] != Json::nullValue);
+
+ create_request(request, "get_owner");
+ request["params"]["port_id"] = 1;
+ send_request(request, response);
+ EXPECT_TRUE(response["result"] != Json::nullValue);
+
+ EXPECT_TRUE(response["result"]["owner"] == "itay");
+
+ /* hard acquire */
+ create_request(request, "acquire");
+ request["params"]["port_id"] = 1;
+ request["params"]["user"] = "moshe";
+ request["params"]["force"] = false;
+
+ send_request(request, response);
+ EXPECT_TRUE(response["result"] == Json::nullValue);
+
+ request["params"]["force"] = true;
+
+ send_request(request, response);
+ EXPECT_TRUE(response["result"] != Json::nullValue);
+
+ string handler = response["result"].asString();
+
+ /* make sure */
+ create_request(request, "get_owner");
+ request["params"]["port_id"] = 1;
+ send_request(request, response);
+ EXPECT_TRUE(response["result"] != Json::nullValue);
+
+ EXPECT_TRUE(response["result"]["owner"] == "moshe");
+
+ /* release */
+ create_request(request, "release");
+ request["params"]["port_id"] = 1;
+ request["params"]["handler"] = handler;
+ send_request(request, response);
+
+ EXPECT_TRUE(response["result"] == "ACK");
+}
+
+
+static void
+create_simple_stream(Json::Value &obj) {
+ obj["mode"]["type"] = "continuous";
+ obj["mode"]["pps"] = (rand() % 1000 + 1) * 0.99;
+ obj["isg"] = (rand() % 100 + 1) * 0.99;;
+ obj["enabled"] = true;
+ obj["self_start"] = true;
+ obj["next_stream_id"] = -1;
+
+ obj["packet"]["meta"] = "dummy";
+
+ int packet_size = (rand() % 1500 + 1);
+ for (int i = 0; i < packet_size; i++) {
+ obj["packet"]["binary"][i] = (rand() % 0xff);
+ }
+
+ obj["vm"] = Json::arrayValue;
+ obj["rx_stats"]["enabled"] = false;
+}
+
+static bool
+compare_streams(const Json::Value &s1, const Json::Value &s2) {
+ return s1 == s2;
+}
+
+TEST_F(RpcTestOwned, add_remove_stream) {
+ Json::Value request;
+ Json::Value response;
+
+ /* verify no such stream */
+ create_request(request, "get_stream", 1, 1);
+
+ request["params"]["stream_id"] = 5;
+
+ send_request(request, response);
+
+ EXPECT_EQ(response["jsonrpc"], "2.0");
+ EXPECT_EQ(response["id"], 1);
+ EXPECT_EQ(response["error"]["code"], -32000);
+
+ /* add it */
+ create_request(request, "add_stream", 1, 1);
+ request["params"]["stream_id"] = 5;
+
+ Json::Value stream;
+ create_simple_stream(stream);
+
+ request["params"]["stream"] = stream;
+ send_request(request, response);
+
+ EXPECT_EQ(response["result"], "ACK");
+
+ /* get it */
+ create_request(request, "get_stream", 1, 1);
+
+ request["params"]["stream_id"] = 5;
+
+ send_request(request, response);
+
+ EXPECT_TRUE(compare_streams(stream, response["result"]["stream"]));
+
+ // remove it
+ create_request(request, "remove_stream", 1, 1);
+
+ request["params"]["stream_id"] = 5;
+
+ send_request(request, response);
+
+ EXPECT_EQ(response["result"], "ACK");
+
+ // should not be present anymore
+ send_request(request, response);
+
+ EXPECT_EQ(response["error"]["code"], -32000);
+
+}
+
+
+TEST_F(RpcTestOwned, get_stream_id_list) {
+ Json::Value request;
+ Json::Value response;
+
+ /* add stream 1 */
+ create_request(request, "add_stream", 1);
+ request["params"]["port_id"] = 1;
+
+ Json::Value stream;
+ create_simple_stream(stream);
+
+ request["params"]["stream"] = stream;
+
+ request["params"]["stream_id"] = 5;
+ send_request(request, response);
+ EXPECT_EQ(response["result"], "ACK");
+
+ request["params"]["stream_id"] = 12;
+ send_request(request, response);
+ EXPECT_EQ(response["result"], "ACK");
+
+ request["params"]["stream_id"] = 19;
+ send_request(request, response);
+ EXPECT_EQ(response["result"], "ACK");
+
+
+ create_request(request, "get_stream_list");
+ request["params"]["port_id"] = 1;
+ send_request(request, response);
+
+ EXPECT_TRUE(response["result"].isArray());
+ vector<int> vec;
+ for (auto x : response["result"]) {
+ vec.push_back(x.asInt());
+ }
+
+ sort(vec.begin(), vec.end());
+
+ EXPECT_EQ(vec[0], 5);
+ EXPECT_EQ(vec[1], 12);
+ EXPECT_EQ(vec[2], 19);
+
+ create_request(request, "remove_all_streams");
+ request["params"]["port_id"] = 1;
+ send_request(request, response);
+
+ EXPECT_TRUE(response["result"] == "ACK");
+
+ /* make sure the lights are off ... */
+ create_request(request, "get_stream_list");
+ request["params"]["port_id"] = 1;
+ send_request(request, response);
+
+ EXPECT_TRUE(response["result"].isArray());
+ EXPECT_TRUE(response["result"].size() == 0);
+}
+
+
+TEST_F(RpcTestOwned, start_stop_traffic) {
+ Json::Value request;
+ Json::Value response;
+
+ /* add stream #1 */
+ create_request(request, "add_stream", 1, 1);
+ request["params"]["stream_id"] = 5;
+
+ Json::Value stream;
+ create_simple_stream(stream);
+
+ request["params"]["stream"] = stream;
+
+ send_request(request, response);
+ EXPECT_EQ(response["result"], "ACK");
+
+ /* add stream #1 */
+ create_request(request, "add_stream", 1, 3);
+ request["params"]["stream_id"] = 12;
+ request["params"]["stream"] = stream;
+
+ send_request(request, response);
+ EXPECT_EQ(response["result"], "ACK");
+
+ /* start port 1 */
+ create_request(request, "start_traffic", 1, 1);
+ send_request(request, response);
+ EXPECT_EQ(response["result"], "ACK");
+
+
+ /* start port 3 */
+ create_request(request, "start_traffic", 1, 3);
+ send_request(request, response);
+ EXPECT_EQ(response["result"], "ACK");
+
+ /* start not configured port */
+ create_request(request, "start_traffic", 1, 2);
+ send_request(request, response);
+ EXPECT_EQ(response["error"]["code"], -32000);
+
+ /* stop port 1 */
+ create_request(request, "stop_traffic", 1, 1);
+ send_request(request, response);
+ EXPECT_EQ(response["result"], "ACK");
+
+ /* stop port 3 */
+ create_request(request, "stop_traffic", 1, 3);
+ send_request(request, response);
+ EXPECT_EQ(response["result"], "ACK");
+
+ /* start 1 again */
+ create_request(request, "start_traffic", 1, 1);
+ send_request(request, response);
+ EXPECT_EQ(response["result"], "ACK");
+
+ /* start 1 twice (error) */
+ create_request(request, "start_traffic", 1, 1);
+ send_request(request, response);
+ EXPECT_EQ(response["error"]["code"], -32000);
+
+ /* make sure you cannot release while traffic is active */
+ create_request(request, "release", 1, 1);
+ send_request(request, response);
+ EXPECT_EQ(response["error"]["code"], -32000);
+
+ /* stop traffic on port #1 */
+ create_request(request, "stop_traffic",1 ,1);
+ send_request(request, response);
+ EXPECT_EQ(response["result"], "ACK");
+
+ /* release */
+ create_request(request, "release", 1, 1);
+ send_request(request, response);
+ EXPECT_EQ(response["result"], "ACK");
+}
diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp
new file mode 100644
index 00000000..0341516c
--- /dev/null
+++ b/src/gtest/trex_stateless_gtest.cpp
@@ -0,0 +1,353 @@
+/*
+ Hanoh Haim
+ Cisco Systems, Inc.
+*/
+
+/*
+Copyright (c) 2015-2015 Cisco Systems, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+#include "bp_sim.h"
+#include <common/gtest.h>
+#include <common/basic_utils.h>
+
+
+#define EXPECT_EQ_UINT32(a,b) EXPECT_EQ((uint32_t)(a),(uint32_t)(b))
+
+// one stream info with const packet , no VM
+class CTRexDpStatelessVM {
+
+};
+
+//- add dump function
+// - check one object
+// create frame work
+
+class CTRexDpStreamModeContinues{
+public:
+ void set_pps(double pps){
+ m_pps=pps;
+ }
+ double get_pps(){
+ return (m_pps);
+ }
+
+ void dump(FILE *fd);
+private:
+ double m_pps;
+};
+
+
+void CTRexDpStreamModeContinues::dump(FILE *fd){
+ fprintf (fd," pps : %f \n",m_pps);
+}
+
+
+class CTRexDpStreamModeSingleBurst{
+public:
+ void set_pps(double pps){
+ m_pps=pps;
+ }
+ double get_pps(){
+ return (m_pps);
+ }
+
+ void set_total_packets(uint64_t total_packets){
+ m_total_packets =total_packets;
+ }
+
+ uint64_t get_total_packets(){
+ return (m_total_packets);
+ }
+
+ void dump(FILE *fd);
+
+private:
+ double m_pps;
+ uint64_t m_total_packets;
+};
+
+
+void CTRexDpStreamModeSingleBurst::dump(FILE *fd){
+ fprintf (fd," pps : %f \n",m_pps);
+ fprintf (fd," total_packets : %llu \n",m_total_packets);
+}
+
+
+class CTRexDpStreamModeMultiBurst{
+public:
+ void set_pps(double pps){
+ m_pps=pps;
+ }
+ double get_pps(){
+ return (m_pps);
+ }
+
+ void set_pkts_per_burst(uint64_t pkts_per_burst){
+ m_pkts_per_burst =pkts_per_burst;
+ }
+
+ uint64_t get_pkts_per_burst(){
+ return (m_pkts_per_burst);
+ }
+
+ void set_ibg(double ibg){
+ m_ibg = ibg;
+ }
+
+ double get_ibg(){
+ return ( m_ibg );
+ }
+
+ void set_number_of_bursts(uint32_t number_of_bursts){
+ m_number_of_bursts = number_of_bursts;
+ }
+
+ uint32_t get_number_of_bursts(){
+ return (m_number_of_bursts);
+ }
+
+ void dump(FILE *fd);
+
+private:
+ double m_pps;
+ double m_ibg; // inter burst gap
+ uint64_t m_pkts_per_burst;
+ uint32_t m_number_of_bursts;
+};
+
+void CTRexDpStreamModeMultiBurst::dump(FILE *fd){
+ fprintf (fd," pps : %f \n",m_pps);
+ fprintf (fd," total_packets : %llu \n",m_pkts_per_burst);
+ fprintf (fd," ibg : %f \n",m_ibg);
+ fprintf (fd," num_of_bursts : %llu \n",m_number_of_bursts);
+}
+
+
+
+class CTRexDpStreamMode {
+public:
+ enum MODES {
+ moCONTINUES = 0x0,
+ moSINGLE_BURST = 0x1,
+ moMULTI_BURST = 0x2
+ } ;
+ typedef uint8_t MODE_TYPE_t;
+
+ void reset();
+
+ void set_mode(MODE_TYPE_t mode ){
+ m_type = mode;
+ }
+
+ MODE_TYPE_t get_mode(){
+ return (m_type);
+ }
+
+
+ CTRexDpStreamModeContinues & cont(void){
+ return (m_data.m_cont);
+ }
+ CTRexDpStreamModeSingleBurst & single_burst(void){
+ return (m_data.m_signle_burst);
+ }
+
+ CTRexDpStreamModeMultiBurst & multi_burst(void){
+ return (m_data.m_multi_burst);
+ }
+
+ void dump(FILE *fd);
+
+private:
+ uint8_t m_type;
+ union Data {
+ CTRexDpStreamModeContinues m_cont;
+ CTRexDpStreamModeSingleBurst m_signle_burst;
+ CTRexDpStreamModeMultiBurst m_multi_burst;
+ } m_data;
+};
+
+
+void CTRexDpStreamMode::reset(){
+ m_type =CTRexDpStreamMode::moCONTINUES;
+ memset(&m_data,0,sizeof(m_data));
+}
+
+void CTRexDpStreamMode::dump(FILE *fd){
+ const char * table[3] = {"CONTINUES","SINGLE_BURST","MULTI_BURST"};
+
+ fprintf(fd," mode : %s \n", (char*)table[m_type]);
+ switch (m_type) {
+ case CTRexDpStreamMode::moCONTINUES :
+ cont().dump(fd);
+ break;
+ case CTRexDpStreamMode::moSINGLE_BURST :
+ single_burst().dump(fd);
+ break;
+ case CTRexDpStreamMode::moMULTI_BURST :
+ multi_burst().dump(fd);
+ break;
+ default:
+ fprintf(fd," ERROR type if not valid %d \n",m_type);
+ break;
+ }
+}
+
+
+
+
+class CTRexDpStatelessStream {
+
+public:
+ enum FLAGS_0{
+ _ENABLE = 0,
+ _SELF_START = 1,
+ _VM_ENABLE =2,
+ _END_STREAM =-1
+ };
+
+ CTRexDpStatelessStream(){
+ reset();
+ }
+
+ void reset(){
+ m_packet =0;
+ m_vm=0;
+ m_flags=0;
+ m_isg_sec=0.0;
+ m_next_stream = CTRexDpStatelessStream::_END_STREAM ; // END
+ m_mode.reset();
+ }
+
+ void set_enable(bool enable){
+ btSetMaskBit32(m_flags,_ENABLE,_ENABLE,enable?1:0);
+ }
+
+ bool get_enabled(){
+ return (btGetMaskBit32(m_flags,_ENABLE,_ENABLE)?true:false);
+ }
+
+ void set_self_start(bool enable){
+ btSetMaskBit32(m_flags,_SELF_START,_SELF_START,enable?1:0);
+ }
+
+ bool get_self_start(bool enable){
+ return (btGetMaskBit32(m_flags,_SELF_START,_SELF_START)?true:false);
+ }
+
+
+ /* if we don't have VM we could just replicate the mbuf and allocate it once */
+ void set_vm_enable(bool enable){
+ btSetMaskBit32(m_flags,_VM_ENABLE,_VM_ENABLE,enable?1:0);
+ }
+
+ bool get_vm_enabled(bool enable){
+ return (btGetMaskBit32(m_flags,_VM_ENABLE,_VM_ENABLE)?true:false);
+ }
+
+ void set_inter_stream_gap(double isg_sec){
+ m_isg_sec =isg_sec;
+ }
+
+ double get_inter_stream_gap(){
+ return (m_isg_sec);
+ }
+
+ CTRexDpStreamMode & get_mode();
+
+
+ // CTRexDpStatelessStream::_END_STREAM for END
+ void set_next_stream(int32_t next_stream){
+ m_next_stream =next_stream;
+ }
+
+ int32_t get_next_stream(void){
+ return ( m_next_stream );
+ }
+
+ void dump(FILE *fd);
+
+private:
+ char * m_packet;
+ CTRexDpStatelessVM * m_vm;
+ uint32_t m_flags;
+ double m_isg_sec; // in second
+ CTRexDpStreamMode m_mode;
+ int32_t m_next_stream; // next stream id
+};
+
+//- list of streams info with const packet , no VM
+// - object that include the stream /scheduler/ packet allocation / need to create an object for one thread that works for test
+// generate pcap file and compare it
+
+#if 0
+void CTRexDpStatelessStream::dump(FILE *fd){
+
+ fprintf(fd," enabled : %d \n",get_enabled()?1:0);
+ fprintf(fd," self_start : %d \n",get_self_start()?1:0);
+ fprintf(fd," vm : %d \n",get_vm_enabled()?1:0);
+ fprintf(" isg : %f \n",m_isg_sec);
+ m_mode.dump(fd);
+ if (m_next_stream == CTRexDpStatelessStream::_END_STREAM ) {
+ fprintf(fd," action : End of Stream \n");
+ }else{
+ fprintf(" next : %d \n",m_next_stream);
+ }
+}
+
+
+
+class CTRexStatelessBasic {
+
+public:
+ CTRexStatelessBasic(){
+ m_threads=1;
+ }
+
+ bool init(void){
+ return (true);
+ }
+
+public:
+ bool m_threads;
+};
+
+
+/* stateless basic */
+class dp_sl_basic : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ }
+ virtual void TearDown() {
+ }
+public:
+};
+
+
+
+TEST_F(dp_sl_basic, test1) {
+ CTRexDpStatelessStream s1;
+ s1.set_enable(true);
+ s1.set_self_start(true);
+ s1.set_inter_stream_gap(0.77);
+ s1.get_mode().set_mode(CTRexDpStreamMode::moCONTINUES);
+ s1.get_mode().cont().set_pps(100.2);
+ s1.dump(stdout);
+}
+
+
+
+
+#endif
diff --git a/src/rpc-server/commands/trex_rpc_cmd_general.cpp b/src/rpc-server/commands/trex_rpc_cmd_general.cpp
new file mode 100644
index 00000000..106a167a
--- /dev/null
+++ b/src/rpc-server/commands/trex_rpc_cmd_general.cpp
@@ -0,0 +1,267 @@
+/*
+ Itay Marom
+ Cisco Systems, Inc.
+*/
+
+/*
+Copyright (c) 2015-2015 Cisco Systems, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+#include "trex_rpc_cmds.h"
+#include <trex_rpc_server_api.h>
+#include <trex_stateless_api.h>
+#include <trex_rpc_cmds_table.h>
+
+#include <fstream>
+#include <iostream>
+#include <unistd.h>
+
+#ifndef TREX_RPC_MOCK_SERVER
+ #include <../linux_dpdk/version.h>
+#endif
+
+using namespace std;
+
+/**
+ * ping command
+ */
+trex_rpc_cmd_rc_e
+TrexRpcCmdPing::_run(const Json::Value &params, Json::Value &result) {
+
+ result["result"] = "ACK";
+ return (TREX_RPC_CMD_OK);
+}
+
+/**
+ * query command
+ */
+trex_rpc_cmd_rc_e
+TrexRpcCmdGetCmds::_run(const Json::Value &params, Json::Value &result) {
+ vector<string> cmds;
+
+ TrexRpcCommandsTable::get_instance().query(cmds);
+
+ Json::Value test = Json::arrayValue;
+ for (auto cmd : cmds) {
+ test.append(cmd);
+ }
+
+ result["result"] = test;
+
+ return (TREX_RPC_CMD_OK);
+}
+
+/**
+ * get version
+ *
+ */
+trex_rpc_cmd_rc_e
+TrexRpcCmdGetVersion::_run(const Json::Value &params, Json::Value &result) {
+
+ Json::Value &section = result["result"];
+
+ #ifndef TREX_RPC_MOCK_SERVER
+
+ section["version"] = VERSION_BUILD_NUM;
+ section["build_date"] = get_build_date();
+ section["build_time"] = get_build_time();
+ section["built_by"] = VERSION_USER;
+
+ #else
+
+ section["version"] = "v0.0";
+ section["build_date"] = __DATE__;
+ section["build_time"] = __TIME__;
+ section["built_by"] = "MOCK";
+
+ #endif
+
+ return (TREX_RPC_CMD_OK);
+}
+
+/**
+ * get the CPU model
+ *
+ */
+std::string
+TrexRpcCmdGetSysInfo::get_cpu_model() {
+
+ static const string cpu_prefix = "model name";
+ std::ifstream cpuinfo("/proc/cpuinfo");
+
+ if (cpuinfo.is_open()) {
+ while (cpuinfo.good()) {
+
+ std::string line;
+ getline(cpuinfo, line);
+
+ int pos = line.find(cpu_prefix);
+ if (pos == string::npos) {
+ continue;
+ }
+
+ /* trim it */
+ int index = cpu_prefix.size() + 1;
+ while ( (line[index] == ' ') || (line[index] == ':') ) {
+ index++;
+ }
+
+ return line.substr(index);
+ }
+ }
+
+ return "unknown";
+}
+
+void
+TrexRpcCmdGetSysInfo::get_hostname(string &hostname) {
+ char buffer[256];
+ buffer[0] = 0;
+
+ gethostname(buffer, sizeof(buffer));
+
+ /* write hostname */
+ hostname = buffer;
+}
+
+/**
+ * get system info
+ *
+ */
+trex_rpc_cmd_rc_e
+TrexRpcCmdGetSysInfo::_run(const Json::Value &params, Json::Value &result) {
+ string hostname;
+
+ TrexStateless & instance = TrexStateless::get_instance();
+
+ Json::Value &section = result["result"];
+
+ get_hostname(hostname);
+ section["hostname"] = hostname;
+
+ section["uptime"] = TrexRpcServer::get_server_uptime();
+
+ /* FIXME: core count */
+ section["dp_core_count"] = 1;
+ section["core_type"] = get_cpu_model();
+
+ /* ports */
+
+
+ section["port_count"] = instance.get_port_count();
+
+ section["ports"] = Json::arrayValue;
+
+ for (int i = 0; i < instance.get_port_count(); i++) {
+ string driver;
+ string speed;
+
+ TrexStatelessPort *port = instance.get_port_by_id(i);
+ port->get_properties(driver, speed);
+
+ section["ports"][i]["index"] = i;
+ section["ports"][i]["driver"] = driver;
+ section["ports"][i]["speed"] = speed;
+
+ section["ports"][i]["owner"] = port->get_owner();
+
+ switch (port->get_state()) {
+ case TrexStatelessPort::PORT_STATE_DOWN:
+ section["ports"][i]["status"] = "down";
+ break;
+
+ case TrexStatelessPort::PORT_STATE_UP_IDLE:
+ section["ports"][i]["status"] = "idle";
+ break;
+
+ case TrexStatelessPort::PORT_STATE_TRANSMITTING:
+ section["ports"][i]["status"] = "transmitting";
+ break;
+ }
+
+ }
+
+ return (TREX_RPC_CMD_OK);
+}
+
+/**
+ * returns the current owner of the device
+ *
+ * @author imarom (08-Sep-15)
+ *
+ * @param params
+ * @param result
+ *
+ * @return trex_rpc_cmd_rc_e
+ */
+trex_rpc_cmd_rc_e
+TrexRpcCmdGetOwner::_run(const Json::Value &params, Json::Value &result) {
+ Json::Value &section = result["result"];
+
+ uint8_t port_id = parse_port(params, result);
+
+ TrexStatelessPort *port = TrexStateless::get_instance().get_port_by_id(port_id);
+ section["owner"] = port->get_owner();
+
+ return (TREX_RPC_CMD_OK);
+}
+
+/**
+ * acquire device
+ *
+ */
+trex_rpc_cmd_rc_e
+TrexRpcCmdAcquire::_run(const Json::Value &params, Json::Value &result) {
+
+ uint8_t port_id = parse_port(params, result);
+
+ const string &new_owner = parse_string(params, "user", result);
+ bool force = parse_bool(params, "force", result);
+
+ /* if not free and not you and not force - fail */
+ TrexStatelessPort *port = TrexStateless::get_instance().get_port_by_id(port_id);
+
+ if ( (!port->is_free_to_aquire()) && (port->get_owner() != new_owner) && (!force)) {
+ generate_execute_err(result, "device is already taken by '" + port->get_owner() + "'");
+ }
+
+ port->set_owner(new_owner);
+
+ result["result"] = port->get_owner_handler();
+
+ return (TREX_RPC_CMD_OK);
+}
+
+/**
+ * release device
+ *
+ */
+trex_rpc_cmd_rc_e
+TrexRpcCmdRelease::_run(const Json::Value &params, Json::Value &result) {
+
+ uint8_t port_id = parse_port(params, result);
+
+ TrexStatelessPort *port = TrexStateless::get_instance().get_port_by_id(port_id);
+
+ if (port->get_state() == TrexStatelessPort::PORT_STATE_TRANSMITTING) {
+ generate_execute_err(result, "cannot release a port during transmission");
+ }
+
+ port->clear_owner();
+
+ result["result"] = "ACK";
+
+ 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
new file mode 100644
index 00000000..1450e1a9
--- /dev/null
+++ b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp
@@ -0,0 +1,488 @@
+/*
+ Itay Marom
+ Cisco Systems, Inc.
+*/
+
+/*
+Copyright (c) 2015-2015 Cisco Systems, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+#include "trex_rpc_cmds.h"
+#include <trex_rpc_server_api.h>
+#include <trex_stream_api.h>
+#include <trex_stateless_api.h>
+
+#include <iostream>
+
+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
+ *
+ **************************/
+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 */
+ const Json::Value &mode = parse_object(section, "mode", result);
+ string type = parse_string(mode, "type", result);
+
+ /* allocate a new stream based on the type */
+ TrexStream *stream = allocate_new_stream(section, port_id, stream_id, result);
+
+ /* save this for future queries */
+ stream->store_stream_json(section);
+
+ /* 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, "isg", result);
+
+ stream->m_next_stream_id = parse_int(section, "next_stream_id", 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_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_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);
+
+ stream->m_rx_check.m_enable = parse_bool(rx, "enabled", result);
+
+ /* if it is enabled - we need more fields */
+ if (stream->m_rx_check.m_enable) {
+ stream->m_rx_check.m_stream_id = parse_int(rx, "stream_id", result);
+ stream->m_rx_check.m_seq_enabled = parse_bool(rx, "seq_enabled", result);
+ stream->m_rx_check.m_latency = parse_bool(rx, "latency", result);
+ }
+
+ /* make sure this is a valid stream to add */
+ validate_stream(stream, result);
+
+ TrexStatelessPort *port = TrexStateless::get_instance().get_port_by_id(stream->m_port_id);
+ port->get_stream_table()->add_stream(stream);
+
+ result["result"] = "ACK";
+
+ return (TREX_RPC_CMD_OK);
+}
+
+
+
+TrexStream *
+TrexRpcCmdAddStream::allocate_new_stream(const Json::Value &section, uint8_t port_id, uint32_t stream_id, Json::Value &result) {
+
+ TrexStream *stream;
+
+ const Json::Value &mode = parse_object(section, "mode", result);
+ std::string type = parse_string(mode, "type", result);
+
+ if (type == "continuous") {
+
+ double pps = parse_double(mode, "pps", result);
+ stream = new TrexStreamContinuous(port_id, stream_id, pps);
+
+ } else if (type == "single_burst") {
+
+ uint32_t total_pkts = parse_int(mode, "total_pkts", result);
+ double pps = parse_double(mode, "pps", result);
+
+ stream = new TrexStreamBurst(port_id, stream_id, total_pkts, pps);
+
+ } else if (type == "multi_burst") {
+
+ double pps = parse_double(mode, "pps", result);
+ double ibg_usec = parse_double(mode, "ibg", result);
+ uint32_t num_bursts = parse_int(mode, "number_of_bursts", result);
+ uint32_t pkts_per_burst = parse_int(mode, "pkts_per_burst", result);
+
+ stream = new TrexStreamMultiBurst(port_id, stream_id, pkts_per_burst, pps, num_bursts, ibg_usec);
+
+
+ } else {
+ generate_parse_err(result, "bad stream type provided: '" + type + "'");
+ }
+
+ /* make sure we were able to allocate the memory */
+ if (!stream) {
+ generate_internal_err(result, "unable to allocate memory");
+ }
+
+ return (stream);
+
+}
+
+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) ) {
+ std::stringstream ss;
+ ss << "bad packet size provided: should be between " << TrexStream::MIN_PKT_SIZE_BYTES << " and " << TrexStream::MAX_PKT_SIZE_BYTES;
+ delete stream;
+ generate_execute_err(result, ss.str());
+ }
+
+ /* port id should be between 0 and count - 1 */
+ if (stream->m_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;
+ delete stream;
+ generate_execute_err(result, ss.str());
+ }
+
+ /* add the stream to the port's stream table */
+ 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)) {
+ std::stringstream ss;
+ ss << "stream " << stream->m_stream_id << " already exists";
+ delete stream;
+ generate_execute_err(result, ss.str());
+ }
+
+}
+
+/***************************
+ * remove stream
+ *
+ **************************/
+trex_rpc_cmd_rc_e
+TrexRpcCmdRemoveStream::_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 " << stream_id << " does not exists";
+ generate_execute_err(result, ss.str());
+ }
+
+ port->get_stream_table()->remove_stream(stream);
+ delete stream;
+
+ result["result"] = "ACK";
+
+ return (TREX_RPC_CMD_OK);
+}
+
+/***************************
+ * remove all streams
+ * for a port
+ *
+ **************************/
+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 >= 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()->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());
+ }
+
+ /* return the stored stream json (instead of decoding it all over again) */
+ result["result"]["stream"] = stream->get_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::rc_e rc = port->start_traffic();
+
+ if (rc == TrexStatelessPort::RC_OK) {
+ result["result"] = "ACK";
+ } else {
+ std::stringstream ss;
+ switch (rc) {
+ case TrexStatelessPort::RC_ERR_BAD_STATE_FOR_OP:
+ ss << "bad state for operations: port is either transmitting traffic or down";
+ break;
+ case TrexStatelessPort::RC_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);
+}
+
diff --git a/src/rpc-server/commands/trex_rpc_cmd_test.cpp b/src/rpc-server/commands/trex_rpc_cmd_test.cpp
new file mode 100644
index 00000000..3cdddd31
--- /dev/null
+++ b/src/rpc-server/commands/trex_rpc_cmd_test.cpp
@@ -0,0 +1,51 @@
+/*
+ Itay Marom
+ Cisco Systems, Inc.
+*/
+
+/*
+Copyright (c) 2015-2015 Cisco Systems, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+#include "trex_rpc_cmds.h"
+#include <iostream>
+#include <sstream>
+
+using namespace std;
+
+/**
+ * add command
+ *
+ */
+trex_rpc_cmd_rc_e
+TrexRpcCmdTestAdd::_run(const Json::Value &params, Json::Value &result) {
+
+ result["result"] = parse_int(params, "x", result) + parse_int(params, "y", result);
+
+ return (TREX_RPC_CMD_OK);
+}
+
+/**
+ * sub command
+ *
+ * @author imarom (16-Aug-15)
+ */
+trex_rpc_cmd_rc_e
+TrexRpcCmdTestSub::_run(const Json::Value &params, Json::Value &result) {
+
+ result["result"] = parse_int(params, "x", result) - parse_int(params, "y", result);
+
+ 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
new file mode 100644
index 00000000..e261d1c6
--- /dev/null
+++ b/src/rpc-server/commands/trex_rpc_cmds.h
@@ -0,0 +1,104 @@
+/*
+ Itay Marom
+ Cisco Systems, Inc.
+*/
+
+/*
+Copyright (c) 2015-2015 Cisco Systems, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+#ifndef __TREX_RPC_CMD_H__
+#define __TREX_RPC_CMD_H__
+
+#include <trex_rpc_cmd_api.h>
+#include <json/json.h>
+
+class TrexStream;
+
+/* all the RPC commands decl. goes here */
+
+/******************* test section ************/
+
+/**
+ * syntactic sugar for creating a simple command
+ */
+
+#define TREX_RPC_CMD_DEFINE_EXTENDED(class_name, cmd_name, param_count, needs_ownership, ext) \
+ class class_name : public TrexRpcCommand { \
+ public: \
+ class_name () : TrexRpcCommand(cmd_name, param_count, needs_ownership) {} \
+ protected: \
+ virtual trex_rpc_cmd_rc_e _run(const Json::Value &params, Json::Value &result); \
+ ext \
+ }
+
+#define TREX_RPC_CMD_DEFINE(class_name, cmd_name, param_count, needs_ownership) TREX_RPC_CMD_DEFINE_EXTENDED(class_name, cmd_name, param_count, needs_ownership, ;)
+
+/**
+ * test cmds
+ */
+TREX_RPC_CMD_DEFINE(TrexRpcCmdTestAdd, "test_add", 2, false);
+TREX_RPC_CMD_DEFINE(TrexRpcCmdTestSub, "test_sub", 2, false);
+
+/**
+ * general cmds
+ */
+TREX_RPC_CMD_DEFINE(TrexRpcCmdPing, "ping", 0, false);
+TREX_RPC_CMD_DEFINE(TrexRpcCmdGetCmds, "get_supported_cmds", 0, false);
+TREX_RPC_CMD_DEFINE(TrexRpcCmdGetVersion, "get_version", 0, false);
+
+TREX_RPC_CMD_DEFINE_EXTENDED(TrexRpcCmdGetSysInfo, "get_system_info", 0, false,
+
+std::string get_cpu_model();
+void get_hostname(std::string &hostname);
+
+);
+
+/**
+ * ownership
+ */
+TREX_RPC_CMD_DEFINE(TrexRpcCmdGetOwner, "get_owner", 1, false);
+TREX_RPC_CMD_DEFINE(TrexRpcCmdAcquire, "acquire", 3, false);
+TREX_RPC_CMD_DEFINE(TrexRpcCmdRelease, "release", 1, true);
+
+
+/**
+ * stream cmds
+ */
+TREX_RPC_CMD_DEFINE(TrexRpcCmdRemoveAllStreams, "remove_all_streams", 1, true);
+TREX_RPC_CMD_DEFINE(TrexRpcCmdRemoveStream, "remove_stream", 2, true);
+
+TREX_RPC_CMD_DEFINE_EXTENDED(TrexRpcCmdAddStream, "add_stream", 3, true,
+
+/* extended part */
+TrexStream * allocate_new_stream(const Json::Value &section, 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, true);
+
+TREX_RPC_CMD_DEFINE(TrexRpcCmdGetStream, "get_stream", 2, true);
+
+TREX_RPC_CMD_DEFINE(TrexRpcCmdStartTraffic, "start_traffic", 1, true);
+TREX_RPC_CMD_DEFINE(TrexRpcCmdStopTraffic, "stop_traffic", 1, true);
+
+
+
+#endif /* __TREX_RPC_CMD_H__ */
diff --git a/src/rpc-server/include/trex_rpc_cmd_api.h b/src/rpc-server/include/trex_rpc_cmd_api.h
deleted file mode 100644
index c773b15f..00000000
--- a/src/rpc-server/include/trex_rpc_cmd_api.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- Itay Marom
- Cisco Systems, Inc.
-*/
-
-/*
-Copyright (c) 2015-2015 Cisco Systems, Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-#ifndef __TREX_RPC_CMD_API_H__
-#define __TREX_RPC_CMD_API_H__
-
-#include <string>
-#include <vector>
-#include <json/json.h>
-
-/**
- * interface for RPC command
- *
- * @author imarom (13-Aug-15)
- */
-class TrexRpcCommand {
-public:
-
- /**
- * describe different types of rc for run()
- */
- enum rpc_cmd_rc_e {
- RPC_CMD_OK,
- RPC_CMD_PARAM_COUNT_ERR = 1,
- RPC_CMD_PARAM_PARSE_ERR,
- RPC_CMD_INTERNAL_ERR
- };
-
- /**
- * method name and params
- */
- TrexRpcCommand(const std::string &method_name) : m_name(method_name) {
-
- }
-
- rpc_cmd_rc_e run(const Json::Value &params, Json::Value &result) {
- return _run(params, result);
- }
-
- const std::string &get_name() {
- return m_name;
- }
-
- virtual ~TrexRpcCommand() {}
-
-protected:
-
- /**
- * implemented by the dervied class
- *
- */
- virtual rpc_cmd_rc_e _run(const Json::Value &params, Json::Value &result) = 0;
-
- /**
- * error generating functions
- *
- */
- void genernate_err(Json::Value &result, const std::string &msg) {
- result["specific_err"] = msg;
- }
-
- void generate_err_param_count(Json::Value &result, int expected, int provided) {
- std::stringstream ss;
- ss << "method expects '" << expected << "' paramteres, '" << provided << "' provided";
- genernate_err(result, ss.str());
- }
-
- std::string m_name;
-};
-
-#endif /* __TREX_RPC_CMD_API_H__ */
-
diff --git a/src/rpc-server/src/commands/trex_rpc_cmd_general.cpp b/src/rpc-server/src/commands/trex_rpc_cmd_general.cpp
deleted file mode 100644
index 193ce8db..00000000
--- a/src/rpc-server/src/commands/trex_rpc_cmd_general.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- Itay Marom
- Cisco Systems, Inc.
-*/
-
-/*
-Copyright (c) 2015-2015 Cisco Systems, Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-#include "trex_rpc_cmds.h"
-#include <../linux_dpdk/version.h>
-#include <trex_rpc_server_api.h>
-
-using namespace std;
-
-/**
- * get status
- *
- */
-TrexRpcCommand::rpc_cmd_rc_e
-TrexRpcCmdGetStatus::_run(const Json::Value &params, Json::Value &result) {
-
- /* validate count */
- if (params.size() != 0) {
- generate_err_param_count(result, 0, params.size());
- return (TrexRpcCommand::RPC_CMD_PARAM_COUNT_ERR);
- }
-
- Json::Value &section = result["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();
- return (RPC_CMD_OK);
-}
-
diff --git a/src/rpc-server/src/commands/trex_rpc_cmd_test.cpp b/src/rpc-server/src/commands/trex_rpc_cmd_test.cpp
deleted file mode 100644
index e2dc8959..00000000
--- a/src/rpc-server/src/commands/trex_rpc_cmd_test.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- Itay Marom
- Cisco Systems, Inc.
-*/
-
-/*
-Copyright (c) 2015-2015 Cisco Systems, Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-#include "trex_rpc_cmds.h"
-#include <iostream>
-#include <sstream>
-#include <trex_rpc_cmds_table.h>
-
-using namespace std;
-
-/**
- * add command
- *
- */
-TrexRpcCommand::rpc_cmd_rc_e
-TrexRpcCmdTestAdd::_run(const Json::Value &params, Json::Value &result) {
-
- const Json::Value &x = params["x"];
- const Json::Value &y = params["y"];
-
- /* validate count */
- if (params.size() != 2) {
- generate_err_param_count(result, 2, params.size());
- return (TrexRpcCommand::RPC_CMD_PARAM_COUNT_ERR);
- }
-
- /* check we have all the required paramters */
- if (!x.isInt()) {
- genernate_err(result, "'x' is either missing or not an integer");
- return (TrexRpcCommand::RPC_CMD_PARAM_PARSE_ERR);
- }
-
- if (!y.isInt()) {
- genernate_err(result, "'y' is either missing or not an integer");
- return (TrexRpcCommand::RPC_CMD_PARAM_PARSE_ERR);
- }
-
- result["result"] = x.asInt() + y.asInt();
- return (RPC_CMD_OK);
-}
-
-/**
- * sub command
- *
- * @author imarom (16-Aug-15)
- */
-TrexRpcCommand::rpc_cmd_rc_e
-TrexRpcCmdTestSub::_run(const Json::Value &params, Json::Value &result) {
-
- const Json::Value &x = params["x"];
- const Json::Value &y = params["y"];
-
- /* validate count */
- if (params.size() != 2) {
- generate_err_param_count(result, 2, params.size());
- return (TrexRpcCommand::RPC_CMD_PARAM_COUNT_ERR);
- }
-
- /* check we have all the required paramters */
- if (!x.isInt() || !y.isInt()) {
- return (TrexRpcCommand::RPC_CMD_PARAM_PARSE_ERR);
- }
-
- result["result"] = x.asInt() - y.asInt();
- return (RPC_CMD_OK);
-}
-
-/**
- * ping command
- */
-TrexRpcCommand::rpc_cmd_rc_e
-TrexRpcCmdPing::_run(const Json::Value &params, Json::Value &result) {
-
- /* validate count */
- if (params.size() != 0) {
- generate_err_param_count(result, 0, params.size());
- return (TrexRpcCommand::RPC_CMD_PARAM_COUNT_ERR);
- }
-
- result["result"] = "ACK";
- return (RPC_CMD_OK);
-}
-
-/**
- * query command
- */
-TrexRpcCommand::rpc_cmd_rc_e
-TrexRpcCmdGetReg::_run(const Json::Value &params, Json::Value &result) {
- vector<string> cmds;
-
- /* validate count */
- if (params.size() != 0) {
- generate_err_param_count(result, 0, params.size());
- return (TrexRpcCommand::RPC_CMD_PARAM_COUNT_ERR);
- }
-
-
- TrexRpcCommandsTable::get_instance().query(cmds);
-
- Json::Value test = Json::arrayValue;
- for (auto cmd : cmds) {
- test.append(cmd);
- }
-
- result["result"] = test;
-
- return (RPC_CMD_OK);
-}
-
diff --git a/src/rpc-server/src/commands/trex_rpc_cmds.h b/src/rpc-server/src/commands/trex_rpc_cmds.h
deleted file mode 100644
index e37e1cda..00000000
--- a/src/rpc-server/src/commands/trex_rpc_cmds.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- Itay Marom
- Cisco Systems, Inc.
-*/
-
-/*
-Copyright (c) 2015-2015 Cisco Systems, Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-#ifndef __TREX_RPC_CMD_H__
-#define __TREX_RPC_CMD_H__
-
-#include <trex_rpc_cmd_api.h>
-#include <json/json.h>
-
-/* all the RPC commands decl. goes here */
-
-/******************* test section ************/
-
-/**
- * add
- *
- */
-class TrexRpcCmdTestAdd : public TrexRpcCommand {
-public:
- TrexRpcCmdTestAdd() : TrexRpcCommand("test_add") {}
-protected:
- virtual rpc_cmd_rc_e _run(const Json::Value &params, Json::Value &result);
-};
-
-/**
- * sub
- *
- */
-class TrexRpcCmdTestSub : public TrexRpcCommand {
-public:
- TrexRpcCmdTestSub() : TrexRpcCommand("test_sub") {} ;
-protected:
- virtual rpc_cmd_rc_e _run(const Json::Value &params, Json::Value &result);
-};
-
-/**
- * ping
- *
- */
-class TrexRpcCmdPing : public TrexRpcCommand {
-public:
- TrexRpcCmdPing() : TrexRpcCommand("ping") {};
-protected:
- virtual rpc_cmd_rc_e _run(const Json::Value &params, Json::Value &result);
-};
-
-/**
- * get all registered commands
- *
- */
-class TrexRpcCmdGetReg : public TrexRpcCommand {
-public:
- TrexRpcCmdGetReg() : TrexRpcCommand("get_reg_cmds") {};
-protected:
- virtual rpc_cmd_rc_e _run(const Json::Value &params, Json::Value &result);
-};
-
-/**
- * get status
- *
- */
-class TrexRpcCmdGetStatus : public TrexRpcCommand {
-public:
- TrexRpcCmdGetStatus() : TrexRpcCommand("get_status") {};
-protected:
- virtual rpc_cmd_rc_e _run(const Json::Value &params, Json::Value &result);
-};
-
-
-/**************** test section end *************/
-#endif /* __TREX_RPC_CMD_H__ */
diff --git a/src/rpc-server/trex_rpc_cmd.cpp b/src/rpc-server/trex_rpc_cmd.cpp
new file mode 100644
index 00000000..6c355e70
--- /dev/null
+++ b/src/rpc-server/trex_rpc_cmd.cpp
@@ -0,0 +1,317 @@
+/*
+ Itay Marom
+ Cisco Systems, Inc.
+*/
+
+/*
+Copyright (c) 2015-2015 Cisco Systems, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+#include <trex_rpc_cmd_api.h>
+#include <trex_rpc_server_api.h>
+#include <trex_stateless_api.h>
+
+trex_rpc_cmd_rc_e
+TrexRpcCommand::run(const Json::Value &params, Json::Value &result) {
+ trex_rpc_cmd_rc_e rc;
+
+ /* the internal run can throw a parser error / other error */
+ try {
+
+ check_param_count(params, m_param_count, result);
+
+ if (m_needs_ownership) {
+ verify_ownership(params, result);
+ }
+
+ /* run the command itself*/
+ rc = _run(params, result);
+
+ } catch (TrexRpcCommandException &e) {
+ return e.get_rc();
+ }
+
+ return (rc);
+}
+
+void
+TrexRpcCommand::check_param_count(const Json::Value &params, int expected, Json::Value &result) {
+
+ if (params.size() != expected) {
+ std::stringstream ss;
+ ss << "method expects '" << expected << "' paramteres, '" << params.size() << "' provided";
+ generate_parse_err(result, ss.str());
+ }
+}
+
+void
+TrexRpcCommand::verify_ownership(const Json::Value &params, Json::Value &result) {
+ std::string handler = parse_string(params, "handler", result);
+ uint8_t port_id = parse_port(params, result);
+
+ TrexStatelessPort *port = TrexStateless::get_instance().get_port_by_id(port_id);
+
+ if (!port->verify_owner_handler(handler)) {
+ generate_execute_err(result, "invalid handler provided. please pass the handler given when calling 'acquire' or take ownership");
+ }
+}
+
+uint8_t
+TrexRpcCommand::parse_port(const Json::Value &params, Json::Value &result) {
+ uint8_t port_id = parse_byte(params, "port_id", result);
+ validate_port_id(port_id, result);
+
+ return (port_id);
+}
+
+void
+TrexRpcCommand::validate_port_id(uint8_t port_id, Json::Value &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());
+ }
+}
+
+const char *
+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:
+ return "int";
+ case FIELD_TYPE_DOUBLE:
+ return "double";
+ case FIELD_TYPE_OBJ:
+ return "object";
+ case FIELD_TYPE_STR:
+ return "string";
+ case FIELD_TYPE_ARRAY:
+ return "array";
+
+ default:
+ return "UNKNOWN";
+ }
+}
+
+const char *
+TrexRpcCommand::json_type_to_name(const Json::Value &value) {
+
+ switch(value.type()) {
+ case Json::nullValue:
+ return "null";
+ case Json::intValue:
+ return "int";
+ case Json::uintValue:
+ return "uint";
+ case Json::realValue:
+ return "real";
+ case Json::stringValue:
+ return "string";
+ case Json::booleanValue:
+ return "boolean";
+ case Json::arrayValue:
+ return "array";
+ case Json::objectValue:
+ return "object";
+
+ default:
+ return "UNKNOWN";
+ }
+
+}
+
+uint8_t
+TrexRpcCommand::parse_byte(const Json::Value &parent, const std::string &name, Json::Value &result) {
+ check_field_type(parent, name, FIELD_TYPE_BYTE, result);
+ return parent[name].asUInt();
+}
+
+uint8_t
+TrexRpcCommand::parse_byte(const Json::Value &parent, int index, Json::Value &result) {
+ check_field_type(parent, index, FIELD_TYPE_BYTE, result);
+ 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);
+ return parent[name].asInt();
+}
+
+bool
+TrexRpcCommand::parse_bool(const Json::Value &parent, const std::string &name, Json::Value &result) {
+ check_field_type(parent, name, FIELD_TYPE_BOOL, result);
+ return parent[name].asBool();
+}
+
+double
+TrexRpcCommand::parse_double(const Json::Value &parent, const std::string &name, Json::Value &result) {
+ check_field_type(parent, name, FIELD_TYPE_DOUBLE, result);
+ return parent[name].asDouble();
+}
+
+const std::string
+TrexRpcCommand::parse_string(const Json::Value &parent, const std::string &name, Json::Value &result) {
+ check_field_type(parent, name, FIELD_TYPE_STR, result);
+ return parent[name].asString();
+}
+
+const Json::Value &
+TrexRpcCommand::parse_object(const Json::Value &parent, const std::string &name, Json::Value &result) {
+ check_field_type(parent, name, FIELD_TYPE_OBJ, result);
+ return parent[name];
+}
+
+const Json::Value &
+TrexRpcCommand::parse_array(const Json::Value &parent, const std::string &name, Json::Value &result) {
+ check_field_type(parent, name, FIELD_TYPE_ARRAY, result);
+ return parent[name];
+}
+
+/**
+ * for index element (array)
+ */
+void
+TrexRpcCommand::check_field_type(const Json::Value &parent, int index, field_type_e type, Json::Value &result) {
+
+ /* should never get here without parent being array */
+ if (!parent.isArray()) {
+ throw TrexRpcException("internal parsing error");
+ }
+
+ const Json::Value &field = parent[index];
+
+ std::stringstream ss;
+ ss << "array element: " << (index + 1) << " ";
+ check_field_type_common(field, ss.str(), type, result);
+}
+
+void
+TrexRpcCommand::check_field_type(const Json::Value &parent, const std::string &name, field_type_e type, Json::Value &result) {
+ /* should never get here without parent being object */
+ if (!parent.isObject()) {
+ throw TrexRpcException("internal parsing error");
+ }
+
+ const Json::Value &field = parent[name];
+ check_field_type_common(field, name, type, result);
+}
+void
+TrexRpcCommand::check_field_type_common(const Json::Value &field, const std::string &name, field_type_e type, Json::Value &result) {
+ std::stringstream ss;
+
+ /* first check if field exists */
+ if (field == Json::Value::null) {
+ ss << "field '" << name << "' is missing";
+ generate_parse_err(result, ss.str());
+ }
+
+ bool rc = true;
+
+ switch (type) {
+ case FIELD_TYPE_BYTE:
+ if ( (!field.isUInt()) || (field.asInt() > 0xFF)) {
+ rc = false;
+ }
+ break;
+
+ case FIELD_TYPE_UINT16:
+ if ( (!field.isUInt()) || (field.asInt() > 0xFFFF)) {
+ rc = false;
+ }
+ break;
+
+ case FIELD_TYPE_BOOL:
+ if (!field.isBool()) {
+ rc = false;
+ }
+ break;
+
+ case FIELD_TYPE_INT:
+ if (!field.isInt()) {
+ rc = false;
+ }
+ break;
+
+ case FIELD_TYPE_DOUBLE:
+ if (!field.isDouble()) {
+ rc = false;
+ }
+ break;
+
+ case FIELD_TYPE_OBJ:
+ if (!field.isObject()) {
+ rc = false;
+ }
+ break;
+
+ case FIELD_TYPE_STR:
+ if (!field.isString()) {
+ rc = false;
+ }
+ break;
+
+ case FIELD_TYPE_ARRAY:
+ if (!field.isArray()) {
+ rc = false;
+ }
+ break;
+
+ default:
+ throw TrexRpcException("unhandled type");
+ break;
+
+ }
+ if (!rc) {
+ ss << "error at offset: " << field.getOffsetStart() << " - '" << name << "' is '" << json_type_to_name(field) << "', expecting '" << type_to_str(type) << "'";
+ generate_parse_err(result, ss.str());
+ }
+
+}
+
+void
+TrexRpcCommand::generate_parse_err(Json::Value &result, const std::string &msg) {
+ result["specific_err"] = msg;
+ throw (TrexRpcCommandException(TREX_RPC_CMD_PARSE_ERR));
+}
+
+void
+TrexRpcCommand::generate_internal_err(Json::Value &result, const std::string &msg) {
+ result["specific_err"] = msg;
+ throw (TrexRpcCommandException(TREX_RPC_CMD_INTERNAL_ERR));
+}
+
+void
+TrexRpcCommand::generate_execute_err(Json::Value &result, const std::string &msg) {
+ result["specific_err"] = msg;
+ throw (TrexRpcCommandException(TREX_RPC_CMD_EXECUTE_ERR));
+}
+
diff --git a/src/rpc-server/trex_rpc_cmd_api.h b/src/rpc-server/trex_rpc_cmd_api.h
new file mode 100644
index 00000000..3c718eaa
--- /dev/null
+++ b/src/rpc-server/trex_rpc_cmd_api.h
@@ -0,0 +1,241 @@
+/*
+ Itay Marom
+ Cisco Systems, Inc.
+*/
+
+/*
+Copyright (c) 2015-2015 Cisco Systems, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+#ifndef __TREX_RPC_CMD_API_H__
+#define __TREX_RPC_CMD_API_H__
+
+#include <string>
+#include <vector>
+#include <json/json.h>
+#include <trex_rpc_exception_api.h>
+
+/**
+ * describe different types of rc for run()
+ */
+typedef enum trex_rpc_cmd_rc_ {
+ TREX_RPC_CMD_OK,
+ TREX_RPC_CMD_PARSE_ERR,
+ TREX_RPC_CMD_EXECUTE_ERR,
+ TREX_RPC_CMD_INTERNAL_ERR
+} trex_rpc_cmd_rc_e;
+
+/**
+ * simple exception for RPC command processing
+ *
+ * @author imarom (23-Aug-15)
+ */
+class TrexRpcCommandException : TrexRpcException {
+public:
+ TrexRpcCommandException(trex_rpc_cmd_rc_e rc) : m_rc(rc) {
+
+ }
+
+ trex_rpc_cmd_rc_e get_rc() {
+ return m_rc;
+
+ }
+
+protected:
+ trex_rpc_cmd_rc_e m_rc;
+};
+
+/**
+ * interface for RPC command
+ *
+ * @author imarom (13-Aug-15)
+ */
+class TrexRpcCommand {
+public:
+
+ /**
+ * method name and params
+ */
+ TrexRpcCommand(const std::string &method_name, int param_count, bool needs_ownership) :
+ m_name(method_name),
+ m_param_count(param_count),
+ m_needs_ownership(needs_ownership) {
+
+ /* if needs ownership - another field is needed (handler) */
+ if (m_needs_ownership) {
+ m_param_count++;
+ }
+ }
+
+ /**
+ * entry point for executing RPC command
+ *
+ */
+ trex_rpc_cmd_rc_e run(const Json::Value &params, Json::Value &result);
+
+ const std::string &get_name() {
+ return m_name;
+ }
+
+ virtual ~TrexRpcCommand() {}
+
+protected:
+
+ /**
+ * different types of fields
+ */
+ enum field_type_e {
+ FIELD_TYPE_BYTE,
+ FIELD_TYPE_UINT16,
+ FIELD_TYPE_INT,
+ FIELD_TYPE_DOUBLE,
+ FIELD_TYPE_BOOL,
+ FIELD_TYPE_STR,
+ FIELD_TYPE_OBJ,
+ FIELD_TYPE_ARRAY
+ };
+
+ /**
+ * implemented by the dervied class
+ *
+ */
+ virtual trex_rpc_cmd_rc_e _run(const Json::Value &params, Json::Value &result) = 0;
+
+ /**
+ * check param count
+ */
+ void check_param_count(const Json::Value &params, int expected, Json::Value &result);
+
+ /**
+ * verify ownership
+ *
+ */
+ void verify_ownership(const Json::Value &params, Json::Value &result);
+
+ /**
+ * validate port id
+ *
+ */
+ void validate_port_id(uint8_t port_id, Json::Value &result);
+
+ /**
+ * parse functions
+ *
+ */
+ 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);
+ const std::string parse_string(const Json::Value &parent, const std::string &name, Json::Value &result);
+ const Json::Value & parse_object(const Json::Value &parent, const std::string &name, Json::Value &result);
+ 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);
+ const std::string parse_string(const Json::Value &parent, int index, Json::Value &result);
+ 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);
+
+ /* shortcut for parsing port id */
+ uint8_t parse_port(const Json::Value &params, Json::Value &result);
+
+ /**
+ * parse a field from choices
+ *
+ */
+ template<typename T> T parse_choice(const Json::Value &params, 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);
+
+ /* dummy return value - does not matter, the above will throw exception */
+ return (*choices.begin());
+ }
+
+ /**
+ * check field type
+ *
+ */
+ void check_field_type(const Json::Value &parent, const std::string &name, field_type_e type, Json::Value &result);
+ void check_field_type(const Json::Value &parent, int index, field_type_e type, Json::Value &result);
+ void check_field_type_common(const Json::Value &field, const std::string &name, field_type_e type, Json::Value &result);
+
+ /**
+ * error generating functions
+ *
+ */
+ void generate_parse_err(Json::Value &result, const std::string &msg);
+
+
+ /**
+ * method execute error
+ *
+ */
+ void generate_execute_err(Json::Value &result, const std::string &msg);
+
+ /**
+ * internal error
+ *
+ */
+ void generate_internal_err(Json::Value &result, const std::string &msg);
+
+
+ /**
+ * translate enum to string
+ *
+ */
+ const char * type_to_str(field_type_e type);
+
+ /**
+ * translate JSON values to string
+ *
+ */
+ const char * json_type_to_name(const Json::Value &value);
+
+ /* RPC command name */
+ std::string m_name;
+ int m_param_count;
+ bool m_needs_ownership;
+};
+
+#endif /* __TREX_RPC_CMD_API_H__ */
+
diff --git a/src/rpc-server/src/trex_rpc_cmds_table.cpp b/src/rpc-server/trex_rpc_cmds_table.cpp
index 04a56389..170f0de1 100644
--- a/src/rpc-server/src/trex_rpc_cmds_table.cpp
+++ b/src/rpc-server/trex_rpc_cmds_table.cpp
@@ -30,9 +30,25 @@ TrexRpcCommandsTable::TrexRpcCommandsTable() {
/* add the test command (for gtest) */
register_command(new TrexRpcCmdTestAdd());
register_command(new TrexRpcCmdTestSub());
+
+
+ /* general */
register_command(new TrexRpcCmdPing());
- register_command(new TrexRpcCmdGetReg());
- register_command(new TrexRpcCmdGetStatus());
+ register_command(new TrexRpcCmdGetCmds());
+ register_command(new TrexRpcCmdGetVersion());
+ register_command(new TrexRpcCmdGetSysInfo());
+ register_command(new TrexRpcCmdGetOwner());
+ register_command(new TrexRpcCmdAcquire());
+ register_command(new TrexRpcCmdRelease());
+
+ /* stream commands */
+ 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/include/trex_rpc_cmds_table.h b/src/rpc-server/trex_rpc_cmds_table.h
index a41944f1..a41944f1 100644
--- a/src/rpc-server/include/trex_rpc_cmds_table.h
+++ b/src/rpc-server/trex_rpc_cmds_table.h
diff --git a/src/rpc-server/include/trex_rpc_exception_api.h b/src/rpc-server/trex_rpc_exception_api.h
index 8783c219..e349b980 100644
--- a/src/rpc-server/include/trex_rpc_exception_api.h
+++ b/src/rpc-server/trex_rpc_exception_api.h
@@ -32,6 +32,9 @@ limitations under the License.
class TrexRpcException : public std::runtime_error
{
public:
+ TrexRpcException() : std::runtime_error("") {
+
+ }
TrexRpcException(const std::string &what) : std::runtime_error(what) {
}
};
diff --git a/src/rpc-server/src/trex_rpc_jsonrpc_v2_parser.cpp b/src/rpc-server/trex_rpc_jsonrpc_v2_parser.cpp
index be1eb2f8..9d9de53a 100644
--- a/src/rpc-server/src/trex_rpc_jsonrpc_v2_parser.cpp
+++ b/src/rpc-server/trex_rpc_jsonrpc_v2_parser.cpp
@@ -37,7 +37,10 @@ enum {
JSONRPC_V2_ERR_INVALID_REQ = -32600,
JSONRPC_V2_ERR_METHOD_NOT_FOUND = -32601,
JSONRPC_V2_ERR_INVALID_PARAMS = -32602,
- JSONRPC_V2_ERR_INTERNAL_ERROR = -32603
+ JSONRPC_V2_ERR_INTERNAL_ERROR = -32603,
+
+ /* specific server errors */
+ JSONRPC_V2_ERR_EXECUTE_ERROR = -32000,
};
@@ -71,21 +74,26 @@ public:
virtual void _execute(Json::Value &response) {
Json::Value result;
- TrexRpcCommand::rpc_cmd_rc_e rc = m_cmd->run(m_params, result);
+ trex_rpc_cmd_rc_e rc = m_cmd->run(m_params, result);
switch (rc) {
- case TrexRpcCommand::RPC_CMD_OK:
+ case TREX_RPC_CMD_OK:
response["result"] = result["result"];
break;
- case TrexRpcCommand::RPC_CMD_PARAM_COUNT_ERR:
- case TrexRpcCommand::RPC_CMD_PARAM_PARSE_ERR:
+ case TREX_RPC_CMD_PARSE_ERR:
response["error"]["code"] = JSONRPC_V2_ERR_INVALID_PARAMS;
response["error"]["message"] = "Bad paramters for method";
response["error"]["specific_err"] = result["specific_err"];
break;
- case TrexRpcCommand::RPC_CMD_INTERNAL_ERR:
+ case TREX_RPC_CMD_EXECUTE_ERR:
+ response["error"]["code"] = JSONRPC_V2_ERR_EXECUTE_ERROR;
+ response["error"]["message"] = "Failed To Execute Method";
+ response["error"]["specific_err"] = result["specific_err"];
+ break;
+
+ case TREX_RPC_CMD_INTERNAL_ERR:
response["error"]["code"] = JSONRPC_V2_ERR_INTERNAL_ERROR;
response["error"]["message"] = "Internal Server Error";
response["error"]["specific_err"] = result["specific_err"];
@@ -192,3 +200,36 @@ 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);
+}
+
+void
+TrexJsonRpcV2Parser::generate_common_error(Json::Value &json, const std::string &specific_err) {
+ JsonRpcError err(Json::Value::null, JSONRPC_V2_ERR_INTERNAL_ERROR, specific_err, true);
+
+ err.execute(json);
+
+}
+
diff --git a/src/rpc-server/include/trex_rpc_jsonrpc_v2_parser.h b/src/rpc-server/trex_rpc_jsonrpc_v2_parser.h
index 3367ad6a..0563f21d 100644
--- a/src/rpc-server/include/trex_rpc_jsonrpc_v2_parser.h
+++ b/src/rpc-server/trex_rpc_jsonrpc_v2_parser.h
@@ -79,6 +79,23 @@ public:
*/
void parse(std::vector<TrexJsonRpcV2ParsedObject *> &commands);
+ /**
+ * will generate a valid JSON RPC v2 error message with
+ * generic error code and message
+ *
+ * @author imarom (16-Sep-15)
+ *
+ */
+ static void generate_common_error(Json::Value &json, const std::string &specific_err);
+
+ /**
+ * *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/src/trex_rpc_req_resp_server.cpp b/src/rpc-server/trex_rpc_req_resp_server.cpp
index 7484758d..3d52686c 100644
--- a/src/rpc-server/src/trex_rpc_req_resp_server.cpp
+++ b/src/rpc-server/trex_rpc_req_resp_server.cpp
@@ -82,10 +82,17 @@ void TrexRpcServerReqRes::_rpc_thread_cb() {
}
}
+ if (msg_size >= sizeof(m_msg_buffer)) {
+ std::stringstream ss;
+ ss << "RPC request of '" << msg_size << "' exceeds maximum message size which is '" << sizeof(m_msg_buffer) << "'";
+ handle_server_error(ss.str());
+ continue;
+ }
+
/* 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 +117,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,8 +147,28 @@ 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);
}
+
+/**
+ * handles a server error
+ *
+ */
+void
+TrexRpcServerReqRes::handle_server_error(const std::string &specific_err) {
+ Json::FastWriter writer;
+ Json::Value response;
+
+ /* generate error */
+ TrexJsonRpcV2Parser::generate_common_error(response, specific_err);
+
+ /* write the JSON to string and sever on ZMQ */
+ std::string response_str = writer.write(response);
+
+ verbose_json("Server Replied: ", response_str);
+
+ zmq_send(m_socket, response_str.c_str(), response_str.size(), 0);
+}
diff --git a/src/rpc-server/include/trex_rpc_req_resp_server.h b/src/rpc-server/trex_rpc_req_resp_server.h
index f12d0540..7c1d66d1 100644
--- a/src/rpc-server/include/trex_rpc_req_resp_server.h
+++ b/src/rpc-server/trex_rpc_req_resp_server.h
@@ -39,9 +39,11 @@ protected:
void _stop_rpc_thread();
private:
+
void handle_request(const std::string &request);
+ void handle_server_error(const std::string &specific_err);
- static const int RPC_MAX_MSG_SIZE = 2048;
+ static const int RPC_MAX_MSG_SIZE = (20 * 1024);
void *m_context;
void *m_socket;
uint8_t m_msg_buffer[RPC_MAX_MSG_SIZE];
diff --git a/src/rpc-server/src/trex_rpc_server.cpp b/src/rpc-server/trex_rpc_server.cpp
index 366bfc5b..6b8c200d 100644
--- a/src/rpc-server/src/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
*
diff --git a/src/rpc-server/include/trex_rpc_server_api.h b/src/rpc-server/trex_rpc_server_api.h
index 6bb81c73..06bbe10c 100644
--- a/src/rpc-server/include/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,18 @@ public:
return s_server_uptime;
}
+
+
+
private:
+ static std::string generate_handler();
+
std::vector<TrexRpcServerInterface *> m_servers;
bool m_verbose;
static const std::string s_server_uptime;
+
+ static std::string s_owner;
+ static std::string s_owner_handler;
};
#endif /* __TREX_RPC_SERVER_API_H__ */
diff --git a/src/rpc-server/src/trex_rpc_server_mock.cpp b/src/rpc-server/trex_rpc_server_mock.cpp
index fd4f051c..835e28b8 100644
--- a/src/rpc-server/src/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,9 +44,12 @@ 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") || (argc != 2) ) {
+ if (string(argv[1]) != "--ut") {
cout << "\n[Usage] " << argv[0] << ": " << " [--ut]\n\n";
exit(-1);
}
diff --git a/src/rx_check.cpp b/src/rx_check.cpp
index 67ce89e1..3a67ca23 100755
--- a/src/rx_check.cpp
+++ b/src/rx_check.cpp
@@ -243,6 +243,11 @@ bool RxCheckManager::Create(){
m_hist.Create();
m_cur_time=0.00000001;
m_on_drain=false;
+
+ int i;
+ for (i=0; i<MAX_TEMPLATES_STATS;i++ ) {
+ m_template_info[i].reset();
+ }
return (true);
}
@@ -277,11 +282,6 @@ void RxCheckManager::handle_packet(CRx_check_header * rxh){
lf=m_ft.lookup(rxh->m_flow_id);
m_stats.m_lookup++;
- if ((m_stats.m_lookup & 0xff)==0) {
- /* handle aging from time to time */
-
- tw_handle() ;
- }
bool any_err=false;
if ( rxh->is_fif_dir() ) {
@@ -393,6 +393,10 @@ void RxCheckManager::handle_packet(CRx_check_header * rxh){
on_flow_end(lf);
}
+ if ((m_stats.m_lookup & 0xff)==0) {
+ /* handle aging from time to time */
+ tw_handle() ;
+ }
}
void RxCheckManager::update_template_err(uint8_t template_id){
diff --git a/src/rx_check_header.h b/src/rx_check_header.h
index 3ac5dd1f..54af2451 100755
--- a/src/rx_check_header.h
+++ b/src/rx_check_header.h
@@ -85,6 +85,9 @@ public:
int get_dir(void){
return (btGetMaskBit8(m_flags,0,0) ? 1:0);
}
+ void clean(){
+ memset(this,0,sizeof(CRx_check_header));
+ }
/* need to mark if we expect to see both sides of the flow, this is know offline */
void set_both_dir(int both){
diff --git a/src/stateless/trex_stateless.cpp b/src/stateless/trex_stateless.cpp
new file mode 100644
index 00000000..6a3169d4
--- /dev/null
+++ b/src/stateless/trex_stateless.cpp
@@ -0,0 +1,152 @@
+/*
+ Itay Marom
+ Cisco Systems, Inc.
+*/
+
+/*
+Copyright (c) 2015-2015 Cisco Systems, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+#include <trex_stateless_api.h>
+
+using namespace std;
+
+/***********************************************************
+ * Trex stateless object
+ *
+ **********************************************************/
+TrexStateless::TrexStateless() {
+ m_is_configured = false;
+}
+
+/**
+ * one time configuration of the stateless object
+ *
+ */
+void TrexStateless::configure(uint8_t port_count) {
+
+ TrexStateless& instance = get_instance_internal();
+
+ if (instance.m_is_configured) {
+ throw TrexException("re-configuration of stateless object is not allowed");
+ }
+
+ instance.m_port_count = port_count;
+ instance.m_ports = new TrexStatelessPort*[port_count];
+
+ for (int i = 0; i < instance.m_port_count; i++) {
+ instance.m_ports[i] = new TrexStatelessPort(i);
+ }
+
+ instance.m_is_configured = true;
+}
+
+TrexStateless::~TrexStateless() {
+ for (int i = 0; i < m_port_count; i++) {
+ delete m_ports[i];
+ }
+
+ delete [] m_ports;
+}
+
+TrexStatelessPort * TrexStateless::get_port_by_id(uint8_t port_id) {
+ if (port_id >= m_port_count) {
+ throw TrexException("index out of range");
+ }
+
+ return m_ports[port_id];
+
+}
+
+uint8_t TrexStateless::get_port_count() {
+ return m_port_count;
+}
+
+/***************************
+ * trex stateless port
+ *
+ **************************/
+TrexStatelessPort::TrexStatelessPort(uint8_t port_id) : m_port_id(port_id) {
+ m_port_state = PORT_STATE_UP_IDLE;
+ clear_owner();
+}
+
+
+/**
+ * starts the traffic on the port
+ *
+ */
+TrexStatelessPort::rc_e
+TrexStatelessPort::start_traffic(void) {
+
+ if (m_port_state != PORT_STATE_UP_IDLE) {
+ return (RC_ERR_BAD_STATE_FOR_OP);
+ }
+
+ if (get_stream_table()->size() == 0) {
+ return (RC_ERR_NO_STREAMS);
+ }
+
+ m_port_state = PORT_STATE_TRANSMITTING;
+
+ /* real code goes here */
+ return (RC_OK);
+}
+
+void
+TrexStatelessPort::stop_traffic(void) {
+
+ /* real code goes here */
+ if (m_port_state == PORT_STATE_TRANSMITTING) {
+ m_port_state = PORT_STATE_UP_IDLE;
+ }
+}
+
+/**
+* access the stream table
+*
+*/
+TrexStreamTable * TrexStatelessPort::get_stream_table() {
+ return &m_stream_table;
+}
+
+void
+TrexStatelessPort::get_properties(string &driver, string &speed) {
+
+ /* take this from DPDK */
+ driver = "Unknown Driver";
+ speed = "Unknown Speed";
+}
+
+
+/**
+ * generate a random connection handler
+ *
+ */
+std::string
+TrexStatelessPort::generate_handler() {
+ std::stringstream ss;
+
+ static const char alphanum[] =
+ "0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz";
+
+ /* generate 8 bytes of random handler */
+ for (int i = 0; i < 8; ++i) {
+ ss << alphanum[rand() % (sizeof(alphanum) - 1)];
+ }
+
+ return (ss.str());
+}
diff --git a/src/stateless/trex_stateless_api.h b/src/stateless/trex_stateless_api.h
new file mode 100644
index 00000000..e02e93da
--- /dev/null
+++ b/src/stateless/trex_stateless_api.h
@@ -0,0 +1,213 @@
+/*
+ Itay Marom
+ Cisco Systems, Inc.
+*/
+
+/*
+Copyright (c) 2015-2015 Cisco Systems, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+#ifndef __TREX_STATELESS_API_H__
+#define __TREX_STATELESS_API_H__
+
+#include <stdint.h>
+#include <string>
+#include <stdexcept>
+
+#include <trex_stream_api.h>
+
+/**
+ * generic exception for errors
+ * TODO: move this to a better place
+ */
+class TrexException : public std::runtime_error
+{
+public:
+ TrexException() : std::runtime_error("") {
+
+ }
+ TrexException(const std::string &what) : std::runtime_error(what) {
+ }
+};
+
+/**
+ * describes a stateless port
+ *
+ * @author imarom (31-Aug-15)
+ */
+class TrexStatelessPort {
+public:
+
+ /**
+ * port state
+ */
+ enum port_state_e {
+ PORT_STATE_DOWN,
+ PORT_STATE_UP_IDLE,
+ PORT_STATE_TRANSMITTING
+ };
+
+ /**
+ * describess different error codes for port operations
+ */
+ enum rc_e {
+ RC_OK,
+ RC_ERR_BAD_STATE_FOR_OP,
+ RC_ERR_NO_STREAMS,
+ RC_ERR_FAILED_TO_COMPILE_STREAMS
+ };
+
+ TrexStatelessPort(uint8_t port_id);
+
+ /**
+ * start traffic
+ *
+ */
+ rc_e start_traffic(void);
+
+ /**
+ * stop traffic
+ *
+ */
+ void stop_traffic(void);
+
+ /**
+ * access the stream table
+ *
+ */
+ TrexStreamTable *get_stream_table();
+
+ /**
+ * get the port state
+ *
+ */
+ port_state_e get_state() {
+ return m_port_state;
+ }
+
+ /**
+ * fill up properties of the port
+ *
+ * @author imarom (16-Sep-15)
+ *
+ * @param driver
+ * @param speed
+ */
+ void get_properties(std::string &driver, std::string &speed);
+
+ /**
+ * query for ownership
+ *
+ */
+ const std::string &get_owner() {
+ return m_owner;
+ }
+
+ /**
+ * owner handler
+ * for the connection
+ *
+ */
+ const std::string &get_owner_handler() {
+ return m_owner_handler;
+ }
+
+ bool is_free_to_aquire() {
+ return (m_owner == "none");
+ }
+
+ /**
+ * take ownership of the server array
+ * this is static
+ * ownership is total
+ *
+ */
+ void set_owner(const std::string &owner) {
+ m_owner = owner;
+ m_owner_handler = generate_handler();
+ }
+
+ void clear_owner() {
+ m_owner = "none";
+ m_owner_handler = "";
+ }
+
+ bool verify_owner_handler(const std::string &handler) {
+
+ return ( (m_owner != "none") && (m_owner_handler == handler) );
+
+ }
+
+private:
+
+ std::string generate_handler();
+
+ TrexStreamTable m_stream_table;
+ uint8_t m_port_id;
+ port_state_e m_port_state;
+ std::string m_owner;
+ std::string m_owner_handler;
+};
+
+/**
+ * defines the T-Rex stateless operation mode
+ *
+ */
+class TrexStateless {
+public:
+
+ /**
+ * configure the stateless object singelton
+ * reconfiguration is not allowed
+ * an exception will be thrown
+ */
+ static void configure(uint8_t port_count);
+
+ /**
+ * singleton public get instance
+ *
+ */
+ static TrexStateless& get_instance() {
+ TrexStateless& instance = get_instance_internal();
+
+ if (!instance.m_is_configured) {
+ throw TrexException("object is not configured");
+ }
+
+ return instance;
+ }
+
+ TrexStatelessPort *get_port_by_id(uint8_t port_id);
+ uint8_t get_port_count();
+
+protected:
+ TrexStateless();
+ ~TrexStateless();
+
+ static TrexStateless& get_instance_internal () {
+ static TrexStateless instance;
+ return instance;
+ }
+
+ /* c++ 2011 style singleton */
+ TrexStateless(TrexStateless const&) = delete;
+ void operator=(TrexStateless const&) = delete;
+
+ bool m_is_configured;
+ TrexStatelessPort **m_ports;
+ uint8_t m_port_count;
+};
+
+#endif /* __TREX_STATELESS_API_H__ */
+
diff --git a/src/stateless/trex_stream.cpp b/src/stateless/trex_stream.cpp
new file mode 100644
index 00000000..8bf04748
--- /dev/null
+++ b/src/stateless/trex_stream.cpp
@@ -0,0 +1,116 @@
+/*
+ Itay Marom
+ Cisco Systems, Inc.
+*/
+
+/*
+Copyright (c) 2015-2015 Cisco Systems, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+#include <trex_stream_api.h>
+#include <cstddef>
+
+/**************************************
+ * stream
+ *************************************/
+TrexStream::TrexStream(uint8_t port_id, uint32_t stream_id) : m_port_id(port_id), m_stream_id(stream_id) {
+
+ /* default values */
+ m_isg_usec = 0;
+ m_next_stream_id = -1;
+ m_enabled = false;
+ m_self_start = false;
+
+ m_pkt.binary = NULL;
+ m_pkt.len = 0;
+
+ m_rx_check.m_enable = false;
+
+}
+
+TrexStream::~TrexStream() {
+ if (m_pkt.binary) {
+ delete [] m_pkt.binary;
+ }
+}
+
+void
+TrexStream::store_stream_json(const Json::Value &stream_json) {
+ /* deep copy */
+ m_stream_json = stream_json;
+}
+
+const Json::Value &
+TrexStream::get_stream_json() {
+ return m_stream_json;
+}
+
+/**************************************
+ * stream table
+ *************************************/
+TrexStreamTable::TrexStreamTable() {
+
+}
+
+TrexStreamTable::~TrexStreamTable() {
+ for (auto stream : m_stream_table) {
+ delete stream.second;
+ }
+}
+
+void TrexStreamTable::add_stream(TrexStream *stream) {
+ TrexStream *old_stream = get_stream_by_id(stream->m_stream_id);
+ if (old_stream) {
+ remove_stream(old_stream);
+ delete old_stream;
+ }
+
+ m_stream_table[stream->m_stream_id] = stream;
+}
+
+void TrexStreamTable::remove_stream(TrexStream *stream) {
+ m_stream_table.erase(stream->m_stream_id);
+}
+
+
+void TrexStreamTable::remove_and_delete_all_streams() {
+
+ for (auto stream : m_stream_table) {
+ delete stream.second;
+ }
+
+ m_stream_table.clear();
+}
+
+TrexStream * TrexStreamTable::get_stream_by_id(uint32_t stream_id) {
+ auto search = m_stream_table.find(stream_id);
+
+ if (search != m_stream_table.end()) {
+ return search->second;
+ } else {
+ return NULL;
+ }
+}
+
+void TrexStreamTable::get_stream_list(std::vector<uint32_t> &stream_list) {
+ stream_list.clear();
+
+ for (auto stream : m_stream_table) {
+ stream_list.push_back(stream.first);
+ }
+}
+
+int TrexStreamTable::size() {
+ return m_stream_table.size();
+}
diff --git a/src/stateless/trex_stream_api.h b/src/stateless/trex_stream_api.h
new file mode 100644
index 00000000..d3c0fb29
--- /dev/null
+++ b/src/stateless/trex_stream_api.h
@@ -0,0 +1,209 @@
+/*
+ Itay Marom
+ Cisco Systems, Inc.
+*/
+
+/*
+Copyright (c) 2015-2015 Cisco Systems, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+#ifndef __TREX_STREAM_API_H__
+#define __TREX_STREAM_API_H__
+
+#include <unordered_map>
+#include <vector>
+#include <stdint.h>
+#include <string>
+
+#include <json/json.h>
+
+#include <trex_stream_vm.h>
+
+class TrexRpcCmdAddStream;
+
+/**
+ * Stateless Stream
+ *
+ */
+class TrexStream {
+ /* provide the RPC parser a way to access private fields */
+ friend class TrexRpcCmdAddStream;
+ friend class TrexRpcCmdGetStream;
+ friend class TrexStreamTable;
+
+public:
+ TrexStream(uint8_t port_id, uint32_t stream_id);
+ virtual ~TrexStream() = 0;
+
+ /* defines the min max per packet supported */
+ static const uint32_t MIN_PKT_SIZE_BYTES = 1;
+ static const uint32_t MAX_PKT_SIZE_BYTES = 9000;
+
+ /* provides storage for the stream json*/
+ void store_stream_json(const Json::Value &stream_json);
+
+ /* access the stream json */
+ const Json::Value & get_stream_json();
+
+protected:
+ /* basic */
+ uint8_t m_port_id;
+ uint32_t m_stream_id;
+
+
+ /* config fields */
+ double m_isg_usec;
+ int m_next_stream_id;
+
+ /* indicators */
+ bool m_enabled;
+ bool m_self_start;
+
+ /* pkt */
+ struct {
+ uint8_t *binary;
+ uint16_t len;
+ std::string meta;
+ } m_pkt;
+
+ /* VM */
+ StreamVm m_vm;
+
+ /* RX check */
+ struct {
+ bool m_enable;
+ bool m_seq_enabled;
+ bool m_latency;
+ uint32_t m_stream_id;
+
+ } m_rx_check;
+
+
+ /* original template provided by requester */
+ Json::Value m_stream_json;
+};
+
+/**
+ * continuous stream
+ *
+ */
+class TrexStreamContinuous : public TrexStream {
+public:
+ TrexStreamContinuous(uint8_t port_id, uint32_t stream_id, double pps) : TrexStream(port_id, stream_id), m_pps(pps) {
+ }
+
+ double get_pps() {
+ return m_pps;
+ }
+
+protected:
+ double m_pps;
+};
+
+/**
+ * single burst
+ *
+ */
+class TrexStreamBurst : public TrexStream {
+public:
+ TrexStreamBurst(uint8_t port_id, uint32_t stream_id, uint32_t total_pkts, double pps) :
+ TrexStream(port_id, stream_id),
+ m_total_pkts(total_pkts),
+ m_pps(pps) {
+ }
+
+protected:
+ uint32_t m_total_pkts;
+ double m_pps;
+};
+
+/**
+ * multi burst
+ *
+ */
+class TrexStreamMultiBurst : public TrexStreamBurst {
+public:
+ TrexStreamMultiBurst(uint8_t port_id,
+ uint32_t stream_id,
+ uint32_t pkts_per_burst,
+ double pps,
+ uint32_t num_bursts,
+ double ibg_usec) : TrexStreamBurst(port_id, stream_id, pkts_per_burst, pps), m_num_bursts(num_bursts), m_ibg_usec(ibg_usec) {
+
+ }
+protected:
+ uint32_t m_num_bursts;
+ double m_ibg_usec;
+
+};
+
+/**
+ * holds all the streams
+ *
+ */
+class TrexStreamTable {
+public:
+
+ TrexStreamTable();
+ ~TrexStreamTable();
+
+ /**
+ * add a stream
+ * if a previous one exists, the old one will be deleted
+ */
+ void add_stream(TrexStream *stream);
+
+ /**
+ * remove a stream
+ */
+ void remove_stream(TrexStream *stream);
+
+ /**
+ * remove all streams on the table
+ * memory will be deleted
+ */
+ void remove_and_delete_all_streams();
+
+ /**
+ * fetch a stream if exists
+ * o.w NULL
+ *
+ */
+ TrexStream * get_stream_by_id(uint32_t stream_id);
+
+ /**
+ * populate a list with all the stream IDs
+ *
+ * @author imarom (06-Sep-15)
+ *
+ * @param stream_list
+ */
+ void get_stream_list(std::vector<uint32_t> &stream_list);
+
+ /**
+ * get the table size
+ *
+ */
+ int size();
+
+private:
+ /**
+ * holds all the stream in a hash table by stream id
+ *
+ */
+ std::unordered_map<int, TrexStream *> m_stream_table;
+};
+
+#endif /* __TREX_STREAM_API_H__ */
+
diff --git a/src/stateless/trex_stream_vm.cpp b/src/stateless/trex_stream_vm.cpp
new file mode 100644
index 00000000..2e760ae9
--- /dev/null
+++ b/src/stateless/trex_stream_vm.cpp
@@ -0,0 +1,54 @@
+/*
+ Itay Marom
+ Cisco Systems, Inc.
+*/
+
+/*
+Copyright (c) 2015-2015 Cisco Systems, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+#include <trex_stream_vm.h>
+
+/***************************
+ * StreamVmInstruction
+ *
+ **************************/
+StreamVmInstruction::~StreamVmInstruction() {
+
+}
+
+/***************************
+ * StreamVm
+ *
+ **************************/
+void StreamVm::add_instruction(StreamVmInstruction *inst) {
+ m_inst_list.push_back(inst);
+}
+
+const std::vector<StreamVmInstruction *> &
+StreamVm::get_instruction_list() {
+ return m_inst_list;
+}
+
+bool StreamVm::compile() {
+ /* implement me */
+ return (false);
+}
+
+StreamVm::~StreamVm() {
+ for (auto inst : m_inst_list) {
+ delete inst;
+ }
+}
+
diff --git a/src/stateless/trex_stream_vm.h b/src/stateless/trex_stream_vm.h
new file mode 100644
index 00000000..56edbcaf
--- /dev/null
+++ b/src/stateless/trex_stream_vm.h
@@ -0,0 +1,171 @@
+/*
+ Itay Marom
+ Cisco Systems, Inc.
+*/
+
+/*
+Copyright (c) 2015-2015 Cisco Systems, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+#ifndef __TREX_STREAM_VM_API_H__
+#define __TREX_STREAM_VM_API_H__
+
+#include <string>
+#include <stdint.h>
+#include <vector>
+
+/**
+ * interface for stream VM instruction
+ *
+ */
+class StreamVmInstruction {
+public:
+
+ virtual ~StreamVmInstruction();
+
+private:
+ static const std::string m_name;
+};
+
+/**
+ * fix checksum for ipv4
+ *
+ */
+class StreamVmInstructionFixChecksumIpv4 : public StreamVmInstruction {
+public:
+ StreamVmInstructionFixChecksumIpv4(uint16_t offset) : m_pkt_offset(offset) {
+
+ }
+
+private:
+ uint16_t m_pkt_offset;
+};
+
+/**
+ * flow manipulation instruction
+ *
+ * @author imarom (07-Sep-15)
+ */
+class StreamVmInstructionFlowMan : public StreamVmInstruction {
+
+public:
+
+ /**
+ * different types of operations on the object
+ */
+ enum flow_var_op_e {
+ FLOW_VAR_OP_INC,
+ FLOW_VAR_OP_DEC,
+ FLOW_VAR_OP_RANDOM
+ };
+
+ StreamVmInstructionFlowMan(const std::string &var_name,
+ uint8_t size,
+ flow_var_op_e op,
+ uint64_t init_value,
+ uint64_t min_value,
+ uint64_t max_value) :
+ m_var_name(var_name),
+ m_size_bytes(size),
+ m_op(op),
+ m_init_value(init_value),
+ m_min_value(min_value),
+ m_max_value(max_value) {
+
+ }
+
+private:
+
+
+ /* flow var name */
+ std::string m_var_name;
+
+ /* flow var size */
+ uint8_t m_size_bytes;
+
+ /* type of op */
+ flow_var_op_e m_op;
+
+ /* range */
+ uint64_t m_init_value;
+ uint64_t m_min_value;
+ uint64_t m_max_value;
+
+
+};
+
+/**
+ * write flow var to packet
+ *
+ */
+class StreamVmInstructionWriteToPkt : public StreamVmInstruction {
+public:
+
+ StreamVmInstructionWriteToPkt(const std::string &flow_var_name,
+ uint16_t pkt_offset,
+ int32_t add_value = 0,
+ bool is_big_endian = true) :
+
+ m_flow_var_name(flow_var_name),
+ m_pkt_offset(pkt_offset),
+ m_add_value(add_value),
+ m_is_big_endian(is_big_endian) {}
+private:
+
+ /* flow var name to write */
+ std::string m_flow_var_name;
+
+ /* where to write */
+ uint16_t m_pkt_offset;
+
+ /* add/dec value from field when writing */
+ int32_t m_add_value;
+
+ /* writing endian */
+ bool m_is_big_endian;
+};
+
+/**
+ * describes a VM program
+ *
+ */
+class StreamVm {
+public:
+
+ /**
+ * add new instruction to the VM
+ *
+ */
+ void add_instruction(StreamVmInstruction *inst);
+
+ /**
+ * get const access to the instruction list
+ *
+ */
+ const std::vector<StreamVmInstruction *> & get_instruction_list();
+
+ /**
+ * compile the VM
+ * return true of success, o.w false
+ *
+ */
+ bool compile();
+
+ ~StreamVm();
+
+private:
+ std::vector<StreamVmInstruction *> m_inst_list;
+};
+
+#endif /* __TREX_STREAM_VM_API_H__ */
diff --git a/src/timer_wheel_pq.cpp b/src/timer_wheel_pq.cpp
index 172d061e..bb480abd 100755
--- a/src/timer_wheel_pq.cpp
+++ b/src/timer_wheel_pq.cpp
@@ -169,11 +169,14 @@ bool CTimerWheel::handle(){
assert(timer->m_flow);
CFlowTimerHandle * flow =timer->m_flow;
m_st_handle++;
+
+ timer->m_flow=0;/* stop the timer */
+ flow->m_timer=0;
+
if ( flow->m_callback ){
flow->m_callback(flow);
}
- timer->m_flow=0;/* stop the timer */
- flow->m_timer=0;
+
m_pq.pop();
m_st_free++;
delete timer;