diff options
Diffstat (limited to 'src')
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 ¶ms, Json::Value &result) { + + result["result"] = "ACK"; + return (TREX_RPC_CMD_OK); +} + +/** + * query command + */ +trex_rpc_cmd_rc_e +TrexRpcCmdGetCmds::_run(const Json::Value ¶ms, 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 ¶ms, Json::Value &result) { + + Json::Value §ion = 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 ¶ms, Json::Value &result) { + string hostname; + + TrexStateless & instance = TrexStateless::get_instance(); + + Json::Value §ion = 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 ¶ms, Json::Value &result) { + Json::Value §ion = 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 ¶ms, 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 ¶ms, 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 ¶ms, Json::Value &result) { + + uint8_t port_id = parse_int(params, "port_id", result); + uint32_t stream_id = parse_int(params, "stream_id", result); + + const Json::Value §ion = parse_object(params, "stream", result); + + /* get the type of the stream */ + 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 §ion, 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 ¶ms, Json::Value &result) { + uint8_t port_id = parse_byte(params, "port_id", result); + uint32_t stream_id = parse_int(params, "stream_id", result); + + + if (port_id >= TrexStateless::get_instance().get_port_count()) { + std::stringstream ss; + ss << "invalid port id - should be between 0 and " << (int)TrexStateless::get_instance().get_port_count() - 1; + generate_execute_err(result, ss.str()); + } + + TrexStatelessPort *port = TrexStateless::get_instance().get_port_by_id(port_id); + TrexStream *stream = port->get_stream_table()->get_stream_by_id(stream_id); + + if (!stream) { + std::stringstream ss; + ss << "stream " << 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 ¶ms, Json::Value &result) { + uint8_t port_id = parse_byte(params, "port_id", result); + + if (port_id >= TrexStateless::get_instance().get_port_count()) { + std::stringstream ss; + ss << "invalid port id - should be between 0 and " << (int)TrexStateless::get_instance().get_port_count() - 1; + generate_execute_err(result, ss.str()); + } + + TrexStatelessPort *port = TrexStateless::get_instance().get_port_by_id(port_id); + port->get_stream_table()->remove_and_delete_all_streams(); + + result["result"] = "ACK"; + + return (TREX_RPC_CMD_OK); +} + +/*************************** + * get all streams configured + * on a specific port + * + **************************/ +trex_rpc_cmd_rc_e +TrexRpcCmdGetStreamList::_run(const Json::Value ¶ms, Json::Value &result) { + std::vector<uint32_t> stream_list; + + uint8_t port_id = parse_byte(params, "port_id", result); + + if (port_id >= TrexStateless::get_instance().get_port_count()) { + std::stringstream ss; + ss << "invalid port id - should be between 0 and " << (int)TrexStateless::get_instance().get_port_count() - 1; + generate_execute_err(result, ss.str()); + } + + TrexStatelessPort *port = TrexStateless::get_instance().get_port_by_id(port_id); + + port->get_stream_table()->get_stream_list(stream_list); + + Json::Value json_list = Json::arrayValue; + + for (auto stream_id : stream_list) { + json_list.append(stream_id); + } + + result["result"] = json_list; + + return (TREX_RPC_CMD_OK); +} + +/*************************** + * get stream by id + * on a specific port + * + **************************/ +trex_rpc_cmd_rc_e +TrexRpcCmdGetStream::_run(const Json::Value ¶ms, Json::Value &result) { + uint8_t port_id = parse_byte(params, "port_id", result); + + uint32_t stream_id = parse_int(params, "stream_id", result); + + if (port_id >= TrexStateless::get_instance().get_port_count()) { + std::stringstream ss; + ss << "invalid port id - should be between 0 and " << (int)TrexStateless::get_instance().get_port_count() - 1; + generate_execute_err(result, ss.str()); + } + + TrexStatelessPort *port = TrexStateless::get_instance().get_port_by_id(port_id); + + TrexStream *stream = port->get_stream_table()->get_stream_by_id(stream_id); + + if (!stream) { + std::stringstream ss; + ss << "stream id " << stream_id << " on port " << (int)port_id << " does not exists"; + generate_execute_err(result, ss.str()); + } + + /* 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 ¶ms, Json::Value &result) { + + uint8_t port_id = parse_byte(params, "port_id", result); + + if (port_id >= TrexStateless::get_instance().get_port_count()) { + std::stringstream ss; + ss << "invalid port id - should be between 0 and " << (int)TrexStateless::get_instance().get_port_count() - 1; + generate_execute_err(result, ss.str()); + } + + TrexStatelessPort *port = TrexStateless::get_instance().get_port_by_id(port_id); + + TrexStatelessPort::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 ¶ms, Json::Value &result) { + uint8_t port_id = parse_byte(params, "port_id", result); + + if (port_id >= TrexStateless::get_instance().get_port_count()) { + std::stringstream ss; + ss << "invalid port id - should be between 0 and " << (int)TrexStateless::get_instance().get_port_count() - 1; + generate_execute_err(result, ss.str()); + } + + TrexStatelessPort *port = TrexStateless::get_instance().get_port_by_id(port_id); + + port->stop_traffic(); + result["result"] = "ACK"; + + return (TREX_RPC_CMD_OK); +} + diff --git a/src/rpc-server/commands/trex_rpc_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 ¶ms, 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 ¶ms, 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 ¶ms, 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 §ion, uint8_t port_id, uint32_t stream_id, Json::Value &result); +void validate_stream(const TrexStream *stream, Json::Value &result); +void parse_vm(const Json::Value &vm, TrexStream *stream, Json::Value &result); +void parse_vm_instr_checksum(const Json::Value &inst, TrexStream *stream, Json::Value &result); +void parse_vm_instr_flow_var(const Json::Value &inst, TrexStream *stream, Json::Value &result); +void parse_vm_instr_write_flow_var(const Json::Value &inst, TrexStream *stream, Json::Value &result); +); + + +TREX_RPC_CMD_DEFINE(TrexRpcCmdGetStreamList, "get_stream_list", 1, 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 ¶ms, 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 ¶ms, 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 ¶ms, 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 §ion = 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 ¶ms, 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 ¶ms, 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 ¶ms, 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 ¶ms, 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 ¶ms, Json::Value &result); -}; - -/** - * sub - * - */ -class TrexRpcCmdTestSub : public TrexRpcCommand { -public: - TrexRpcCmdTestSub() : TrexRpcCommand("test_sub") {} ; -protected: - virtual rpc_cmd_rc_e _run(const Json::Value ¶ms, Json::Value &result); -}; - -/** - * ping - * - */ -class TrexRpcCmdPing : public TrexRpcCommand { -public: - TrexRpcCmdPing() : TrexRpcCommand("ping") {}; -protected: - virtual rpc_cmd_rc_e _run(const Json::Value ¶ms, 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 ¶ms, Json::Value &result); -}; - -/** - * get status - * - */ -class TrexRpcCmdGetStatus : public TrexRpcCommand { -public: - TrexRpcCmdGetStatus() : TrexRpcCommand("get_status") {}; -protected: - virtual rpc_cmd_rc_e _run(const Json::Value ¶ms, 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 ¶ms, 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 ¶ms, 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 ¶ms, 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 ¶ms, 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 ¶ms, 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 ¶ms, Json::Value &result) = 0; + + /** + * check param count + */ + void check_param_count(const Json::Value ¶ms, int expected, Json::Value &result); + + /** + * verify ownership + * + */ + void verify_ownership(const Json::Value ¶ms, 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 ¶ms, Json::Value &result); + + /** + * parse a field from choices + * + */ + template<typename T> T parse_choice(const Json::Value ¶ms, const std::string &name, std::initializer_list<T> choices, Json::Value &result) { + const Json::Value &field = params[name]; + + if (field == Json::Value::null) { + std::stringstream ss; + ss << "field '" << name << "' is missing"; + generate_parse_err(result, ss.str()); + } + + for (auto x : choices) { + if (field == x) { + return (x); + } + } + + std::stringstream ss; + + ss << "field '" << name << "' can only be one of ["; + for (auto x : choices) { + ss << "'" << x << "' ,"; + } + + std::string s = ss.str(); + s.pop_back(); + s.pop_back(); + s += "]"; + generate_parse_err(result, s); + + /* 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; |