diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/common/captureFile.cpp | 2 | ||||
-rw-r--r-- | src/gtest/rpc_test.cpp | 516 | ||||
-rw-r--r-- | src/rpc-server/commands/trex_rpc_cmd_general.cpp | 230 | ||||
-rw-r--r-- | src/rpc-server/commands/trex_rpc_cmd_stream.cpp | 47 | ||||
-rw-r--r-- | src/rpc-server/commands/trex_rpc_cmd_test.cpp | 30 | ||||
-rw-r--r-- | src/rpc-server/commands/trex_rpc_cmds.h | 47 | ||||
-rw-r--r-- | src/rpc-server/trex_rpc_cmd.cpp | 39 | ||||
-rw-r--r-- | src/rpc-server/trex_rpc_cmd_api.h | 30 | ||||
-rw-r--r-- | src/rpc-server/trex_rpc_cmds_table.cpp | 11 | ||||
-rw-r--r-- | src/rpc-server/trex_rpc_jsonrpc_v2_parser.cpp | 8 | ||||
-rw-r--r-- | src/rpc-server/trex_rpc_jsonrpc_v2_parser.h | 9 | ||||
-rw-r--r-- | src/rpc-server/trex_rpc_req_resp_server.cpp | 27 | ||||
-rw-r--r-- | src/rpc-server/trex_rpc_req_resp_server.h | 4 | ||||
-rw-r--r-- | src/rpc-server/trex_rpc_server.cpp | 1 | ||||
-rw-r--r-- | src/rpc-server/trex_rpc_server_api.h | 26 | ||||
-rw-r--r-- | src/stateless/trex_stateless.cpp | 53 | ||||
-rw-r--r-- | src/stateless/trex_stateless_api.h | 99 | ||||
-rw-r--r-- | src/stateless/trex_stream.cpp | 11 | ||||
-rw-r--r-- | src/stateless/trex_stream_api.h | 24 |
19 files changed, 988 insertions, 226 deletions
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/gtest/rpc_test.cpp b/src/gtest/rpc_test.cpp index 8a7e9176..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\": \"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\": \"test_add\", \"params\": {\"x\": 17, \"y\": -13} , \"id\": \"itay\"}"; - resp_str = send_msg(req_str); - - 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\": \"test_add\", \"params\": {\"x\": \"blah\", \"y\": -13} , \"id\": 17}"; - 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"], 17); EXPECT_EQ(response["error"]["code"], -32602); - /* add with invalid count of parameters */ - req_str = "{\"jsonrpc\": \"2.0\", \"method\": \"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\": \"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); } @@ -225,87 +309,351 @@ TEST_F(RpcTest, batch_rpc_test) { return; } -TEST_F(RpcTest, add_stream) { +/* ping command */ +TEST_F(RpcTest, ping) { Json::Value request; Json::Value response; - Json::Reader reader; - string resp_str; + 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; + } + } - // check the stream does not exists - string lookup_str = "{\"jsonrpc\":\"2.0\", \"id\":1, \"method\":\"get_stream\", \"params\":{\"port_id\":1, \"stream_id\":5}}"; - resp_str = send_msg(lookup_str); + 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_TRUE(reader.parse(resp_str, response, false)); 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); - // add it +} - string add_str = "{\"jsonrpc\":\"2.0\", \"id\":1, \"method\":\"add_stream\", \"params\":" - "{\"port_id\":1, \"stream_id\":5, \"stream\":{" - "\"mode\": {\"type\":\"continuous\", \"pps\":3}," - "\"isg\":4.3, \"enabled\":true, \"self_start\":true," - "\"next_stream_id\":-1," - "\"packet\":{\"binary\":[4,1,255], \"meta\":\"dummy\"}," - "\"vm\":[]," - "\"rx_stats\":{\"enabled\":false}}}}"; - resp_str = send_msg(add_str); +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; - EXPECT_TRUE(reader.parse(resp_str, response, false)); - EXPECT_EQ(response["jsonrpc"], "2.0"); - EXPECT_EQ(response["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"); - resp_str = send_msg(lookup_str); + request["params"]["stream_id"] = 12; + send_request(request, response); + EXPECT_EQ(response["result"], "ACK"); - EXPECT_TRUE(reader.parse(resp_str, response, false)); - EXPECT_EQ(response["jsonrpc"], "2.0"); - EXPECT_EQ(response["id"], 1); + request["params"]["stream_id"] = 19; + send_request(request, response); + EXPECT_EQ(response["result"], "ACK"); - const Json::Value &stream = response["result"]["stream"]; - EXPECT_EQ(stream["enabled"], true); - EXPECT_EQ(stream["self_start"], true); + create_request(request, "get_stream_list"); + request["params"]["port_id"] = 1; + send_request(request, response); - EXPECT_EQ(stream["packet"]["binary"][0], 4); - EXPECT_EQ(stream["packet"]["binary"][1], 1); - EXPECT_EQ(stream["packet"]["binary"][2], 255); + EXPECT_TRUE(response["result"].isArray()); + vector<int> vec; + for (auto x : response["result"]) { + vec.push_back(x.asInt()); + } - EXPECT_EQ(stream["packet"]["meta"], "dummy"); - EXPECT_EQ(stream["next_stream_id"], -1); + sort(vec.begin(), vec.end()); - double delta = stream["isg"].asDouble() - 4.3; - EXPECT_TRUE(delta < 0.0001); + EXPECT_EQ(vec[0], 5); + EXPECT_EQ(vec[1], 12); + EXPECT_EQ(vec[2], 19); - EXPECT_EQ(stream["mode"]["type"], "continuous"); - EXPECT_EQ(stream["mode"]["pps"], 3); + create_request(request, "remove_all_streams"); + request["params"]["port_id"] = 1; + send_request(request, response); - // remove it + EXPECT_TRUE(response["result"] == "ACK"); - string remove_str = "{\"jsonrpc\":\"2.0\", \"id\":1, \"method\":\"remove_stream\", \"params\":{\"port_id\":1, \"stream_id\":5}}"; - resp_str = send_msg(remove_str); + /* make sure the lights are off ... */ + create_request(request, "get_stream_list"); + request["params"]["port_id"] = 1; + send_request(request, response); - EXPECT_TRUE(reader.parse(resp_str, response, false)); - EXPECT_EQ(response["jsonrpc"], "2.0"); - EXPECT_EQ(response["id"], 1); + 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"); - resp_str = send_msg(remove_str); + /* 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"); - // should not be present anymore + /* start port 1 */ + create_request(request, "start_traffic", 1, 1); + send_request(request, response); + EXPECT_EQ(response["result"], "ACK"); - EXPECT_TRUE(reader.parse(resp_str, response, false)); - EXPECT_EQ(response["jsonrpc"], "2.0"); - EXPECT_EQ(response["id"], 1); + /* 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/rpc-server/commands/trex_rpc_cmd_general.cpp b/src/rpc-server/commands/trex_rpc_cmd_general.cpp index 32952b1a..106a167a 100644 --- a/src/rpc-server/commands/trex_rpc_cmd_general.cpp +++ b/src/rpc-server/commands/trex_rpc_cmd_general.cpp @@ -18,9 +18,15 @@ 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> @@ -29,37 +35,233 @@ limitations under the License. using namespace std; /** - * get status + * 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 -TrexRpcCmdGetStatus::_run(const Json::Value ¶ms, Json::Value &result) { +TrexRpcCmdGetVersion::_run(const Json::Value ¶ms, Json::Value &result) { Json::Value §ion = result["result"]; #ifndef TREX_RPC_MOCK_SERVER - section["general"]["version"] = VERSION_BUILD_NUM; - section["general"]["build_date"] = get_build_date(); - section["general"]["build_time"] = get_build_time(); - section["general"]["built_by"] = VERSION_USER; + section["version"] = VERSION_BUILD_NUM; + section["build_date"] = get_build_date(); + section["build_time"] = get_build_time(); + section["built_by"] = VERSION_USER; #else - section["general"]["version"] = "v0.0"; - section["general"]["build_date"] = __DATE__; - section["general"]["build_time"] = __TIME__; - section["general"]["version_user"] = "MOCK"; + section["version"] = "v0.0"; + section["build_date"] = __DATE__; + section["build_time"] = __TIME__; + section["built_by"] = "MOCK"; #endif - section["general"]["uptime"] = TrexRpcServer::get_server_uptime(); - section["general"]["owner"] = TrexRpcServer::get_owner(); + 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 */ + - // ports + section["port_count"] = instance.get_port_count(); - section["ports"]["count"] = TrexStateless::get_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 index 90b55ea8..1450e1a9 100644 --- a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp +++ b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp @@ -63,6 +63,9 @@ TrexRpcCmdAddStream::_run(const Json::Value ¶ms, Json::Value &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); @@ -130,19 +133,19 @@ TrexRpcCmdAddStream::allocate_new_stream(const Json::Value §ion, uint8_t por if (type == "continuous") { - uint32_t pps = parse_int(mode, "pps", result); + 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); - uint32_t pps = parse_int(mode, "pps", result); + double pps = parse_double(mode, "pps", result); stream = new TrexStreamBurst(port_id, stream_id, total_pkts, pps); } else if (type == "multi_burst") { - uint32_t pps = parse_int(mode, "pps", result); + 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); @@ -413,30 +416,11 @@ TrexRpcCmdGetStream::_run(const Json::Value ¶ms, Json::Value &result) { generate_execute_err(result, ss.str()); } - Json::Value stream_json; - - stream_json["enabled"] = stream->m_enabled; - stream_json["self_start"] = stream->m_self_start; - - stream_json["isg"] = stream->m_isg_usec; - stream_json["next_stream_id"] = stream->m_next_stream_id; - - stream_json["packet"]["binary"] = Json::arrayValue; - for (int i = 0; i < stream->m_pkt.len; i++) { - stream_json["packet"]["binary"].append(stream->m_pkt.binary[i]); - } - - stream_json["packet"]["meta"] = stream->m_pkt.meta; - - if (TrexStreamContinuous *cont = dynamic_cast<TrexStreamContinuous *>(stream)) { - stream_json["mode"]["type"] = "continuous"; - stream_json["mode"]["pps"] = cont->get_pps(); - - } - - result["result"]["stream"] = stream_json; + /* return the stored stream json (instead of decoding it all over again) */ + result["result"]["stream"] = stream->get_stream_json(); return (TREX_RPC_CMD_OK); + } /*************************** @@ -445,7 +429,8 @@ TrexRpcCmdGetStream::_run(const Json::Value ¶ms, Json::Value &result) { **************************/ trex_rpc_cmd_rc_e TrexRpcCmdStartTraffic::_run(const Json::Value ¶ms, Json::Value &result) { - uint8_t port_id = parse_byte(params, "port_id", result); + + uint8_t port_id = parse_byte(params, "port_id", result); if (port_id >= TrexStateless::get_instance().get_port_count()) { std::stringstream ss; @@ -455,17 +440,17 @@ TrexRpcCmdStartTraffic::_run(const Json::Value ¶ms, Json::Value &result) { TrexStatelessPort *port = TrexStateless::get_instance().get_port_by_id(port_id); - TrexStatelessPort::traffic_rc_e rc = port->start_traffic(); + TrexStatelessPort::rc_e rc = port->start_traffic(); - if (rc == TrexStatelessPort::TRAFFIC_OK) { + if (rc == TrexStatelessPort::RC_OK) { result["result"] = "ACK"; } else { std::stringstream ss; switch (rc) { - case TrexStatelessPort::TRAFFIC_ERR_ALREADY_STARTED: - ss << "traffic has already started on that port"; + case TrexStatelessPort::RC_ERR_BAD_STATE_FOR_OP: + ss << "bad state for operations: port is either transmitting traffic or down"; break; - case TrexStatelessPort::TRAFFIC_ERR_NO_STREAMS: + case TrexStatelessPort::RC_ERR_NO_STREAMS: ss << "no active streams on that port"; break; default: diff --git a/src/rpc-server/commands/trex_rpc_cmd_test.cpp b/src/rpc-server/commands/trex_rpc_cmd_test.cpp index 3153317e..3cdddd31 100644 --- a/src/rpc-server/commands/trex_rpc_cmd_test.cpp +++ b/src/rpc-server/commands/trex_rpc_cmd_test.cpp @@ -21,7 +21,6 @@ limitations under the License. #include "trex_rpc_cmds.h" #include <iostream> #include <sstream> -#include <trex_rpc_cmds_table.h> using namespace std; @@ -50,32 +49,3 @@ TrexRpcCmdTestSub::_run(const Json::Value ¶ms, Json::Value &result) { return (TREX_RPC_CMD_OK); } -/** - * 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 -TrexRpcCmdGetReg::_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); -} - diff --git a/src/rpc-server/commands/trex_rpc_cmds.h b/src/rpc-server/commands/trex_rpc_cmds.h index f88631bc..e261d1c6 100644 --- a/src/rpc-server/commands/trex_rpc_cmds.h +++ b/src/rpc-server/commands/trex_rpc_cmds.h @@ -35,37 +35,52 @@ class TrexStream; * syntactic sugar for creating a simple command */ -#define TREX_RPC_CMD_DEFINE_EXTENED(class_name, cmd_name, param_count, ext) \ +#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) {} \ + 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) TREX_RPC_CMD_DEFINE_EXTENED(class_name, cmd_name, param_count, ;) +#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); -TREX_RPC_CMD_DEFINE(TrexRpcCmdTestSub, "test_sub", 2); +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); -TREX_RPC_CMD_DEFINE(TrexRpcCmdGetReg, "get_reg_cmds", 0); -TREX_RPC_CMD_DEFINE(TrexRpcCmdGetStatus, "get_status", 0); +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); -TREX_RPC_CMD_DEFINE(TrexRpcCmdRemoveStream, "remove_stream", 2); +TREX_RPC_CMD_DEFINE(TrexRpcCmdRemoveAllStreams, "remove_all_streams", 1, true); +TREX_RPC_CMD_DEFINE(TrexRpcCmdRemoveStream, "remove_stream", 2, true); -TREX_RPC_CMD_DEFINE_EXTENED(TrexRpcCmdAddStream, "add_stream", 3, +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); @@ -77,11 +92,13 @@ void parse_vm_instr_write_flow_var(const Json::Value &inst, TrexStream *stream, ); -TREX_RPC_CMD_DEFINE(TrexRpcCmdGetStreamList, "get_stream_list", 1); +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); -TREX_RPC_CMD_DEFINE(TrexRpcCmdGetStream, "get_stream", 2); -TREX_RPC_CMD_DEFINE(TrexRpcCmdStartTraffic, "start_traffic", 1); -TREX_RPC_CMD_DEFINE(TrexRpcCmdStopTraffic, "stop_traffic", 1); #endif /* __TREX_RPC_CMD_H__ */ diff --git a/src/rpc-server/trex_rpc_cmd.cpp b/src/rpc-server/trex_rpc_cmd.cpp index 3fc77f71..6c355e70 100644 --- a/src/rpc-server/trex_rpc_cmd.cpp +++ b/src/rpc-server/trex_rpc_cmd.cpp @@ -19,6 +19,8 @@ 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) { @@ -26,8 +28,16 @@ TrexRpcCommand::run(const Json::Value ¶ms, Json::Value &result) { /* 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(); } @@ -45,6 +55,35 @@ TrexRpcCommand::check_param_count(const Json::Value ¶ms, int expected, Json: } } +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) { diff --git a/src/rpc-server/trex_rpc_cmd_api.h b/src/rpc-server/trex_rpc_cmd_api.h index def52fca..3c718eaa 100644 --- a/src/rpc-server/trex_rpc_cmd_api.h +++ b/src/rpc-server/trex_rpc_cmd_api.h @@ -68,8 +68,15 @@ public: /** * method name and params */ - TrexRpcCommand(const std::string &method_name, int param_count) : m_name(method_name), m_param_count(param_count) { - + 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++; + } } /** @@ -112,6 +119,18 @@ protected: 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 * */ @@ -133,6 +152,9 @@ protected: const Json::Value & parse_object(const Json::Value &parent, int index, Json::Value &result); const Json::Value & parse_array(const Json::Value &parent, int index, Json::Value &result); + /* shortcut for parsing port id */ + uint8_t parse_port(const Json::Value ¶ms, Json::Value &result); + /** * parse a field from choices * @@ -164,6 +186,9 @@ protected: s.pop_back(); s += "]"; generate_parse_err(result, s); + + /* dummy return value - does not matter, the above will throw exception */ + return (*choices.begin()); } /** @@ -209,6 +234,7 @@ protected: /* 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/trex_rpc_cmds_table.cpp b/src/rpc-server/trex_rpc_cmds_table.cpp index 71668994..170f0de1 100644 --- a/src/rpc-server/trex_rpc_cmds_table.cpp +++ b/src/rpc-server/trex_rpc_cmds_table.cpp @@ -30,9 +30,16 @@ 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()); diff --git a/src/rpc-server/trex_rpc_jsonrpc_v2_parser.cpp b/src/rpc-server/trex_rpc_jsonrpc_v2_parser.cpp index 928baca6..9d9de53a 100644 --- a/src/rpc-server/trex_rpc_jsonrpc_v2_parser.cpp +++ b/src/rpc-server/trex_rpc_jsonrpc_v2_parser.cpp @@ -225,3 +225,11 @@ std::string TrexJsonRpcV2Parser::pretty_json_str(const std::string &json_str) { 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/trex_rpc_jsonrpc_v2_parser.h b/src/rpc-server/trex_rpc_jsonrpc_v2_parser.h index ebffaeb7..0563f21d 100644 --- a/src/rpc-server/trex_rpc_jsonrpc_v2_parser.h +++ b/src/rpc-server/trex_rpc_jsonrpc_v2_parser.h @@ -80,6 +80,15 @@ 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 diff --git a/src/rpc-server/trex_rpc_req_resp_server.cpp b/src/rpc-server/trex_rpc_req_resp_server.cpp index c4d9dfdb..3d52686c 100644 --- a/src/rpc-server/trex_rpc_req_resp_server.cpp +++ b/src/rpc-server/trex_rpc_req_resp_server.cpp @@ -82,6 +82,13 @@ 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); @@ -145,3 +152,23 @@ void TrexRpcServerReqRes::handle_request(const std::string &request) { 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/trex_rpc_req_resp_server.h b/src/rpc-server/trex_rpc_req_resp_server.h index f12d0540..7c1d66d1 100644 --- a/src/rpc-server/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/trex_rpc_server.cpp b/src/rpc-server/trex_rpc_server.cpp index 149bb668..6b8c200d 100644 --- a/src/rpc-server/trex_rpc_server.cpp +++ b/src/rpc-server/trex_rpc_server.cpp @@ -111,7 +111,6 @@ get_current_date_time() { } const std::string TrexRpcServer::s_server_uptime = get_current_date_time(); -std::string TrexRpcServer::s_owner = "none"; TrexRpcServer::TrexRpcServer(const TrexRpcServerConfig &req_resp_cfg) { diff --git a/src/rpc-server/trex_rpc_server_api.h b/src/rpc-server/trex_rpc_server_api.h index b4313670..06bbe10c 100644 --- a/src/rpc-server/trex_rpc_server_api.h +++ b/src/rpc-server/trex_rpc_server_api.h @@ -164,33 +164,17 @@ public: } - /** - * query for ownership - * - */ - static const std::string &get_owner() { - return s_owner; - } - - /** - * take ownership of the server array - * this is static - * ownership is total - * - */ - static void set_owner(const std::string &owner) { - s_owner = owner; - } - - static void clear_owner() { - s_owner = "none"; - } + private: + 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/stateless/trex_stateless.cpp b/src/stateless/trex_stateless.cpp index 2ab0c5d9..6a3169d4 100644 --- a/src/stateless/trex_stateless.cpp +++ b/src/stateless/trex_stateless.cpp @@ -20,6 +20,8 @@ limitations under the License. */ #include <trex_stateless_api.h> +using namespace std; + /*********************************************************** * Trex stateless object * @@ -76,7 +78,8 @@ uint8_t TrexStateless::get_port_count() { * **************************/ TrexStatelessPort::TrexStatelessPort(uint8_t port_id) : m_port_id(port_id) { - m_started = false; + m_port_state = PORT_STATE_UP_IDLE; + clear_owner(); } @@ -84,25 +87,29 @@ TrexStatelessPort::TrexStatelessPort(uint8_t port_id) : m_port_id(port_id) { * starts the traffic on the port * */ -TrexStatelessPort::traffic_rc_e +TrexStatelessPort::rc_e TrexStatelessPort::start_traffic(void) { - if (m_started) { - return (TRAFFIC_ERR_ALREADY_STARTED); + + if (m_port_state != PORT_STATE_UP_IDLE) { + return (RC_ERR_BAD_STATE_FOR_OP); } if (get_stream_table()->size() == 0) { - return (TRAFFIC_ERR_NO_STREAMS); + return (RC_ERR_NO_STREAMS); } - m_started = true; + m_port_state = PORT_STATE_TRANSMITTING; - return (TRAFFIC_OK); + /* real code goes here */ + return (RC_OK); } void TrexStatelessPort::stop_traffic(void) { - if (m_started) { - m_started = false; + + /* real code goes here */ + if (m_port_state == PORT_STATE_TRANSMITTING) { + m_port_state = PORT_STATE_UP_IDLE; } } @@ -114,4 +121,32 @@ 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 index 358ab339..e02e93da 100644 --- a/src/stateless/trex_stateless_api.h +++ b/src/stateless/trex_stateless_api.h @@ -50,19 +50,36 @@ class TrexStatelessPort { public: /** - * describess error codes for starting traffic + * port state */ - enum traffic_rc_e { - TRAFFIC_OK, - TRAFFIC_ERR_ALREADY_STARTED, - TRAFFIC_ERR_NO_STREAMS, - TRAFFIC_ERR_FAILED_TO_COMPILE_STREAMS + 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); - traffic_rc_e start_traffic(void); + /** + * start traffic + * + */ + rc_e start_traffic(void); + /** + * stop traffic + * + */ void stop_traffic(void); /** @@ -71,10 +88,76 @@ public: */ 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; - bool m_started; + port_state_e m_port_state; + std::string m_owner; + std::string m_owner_handler; }; /** diff --git a/src/stateless/trex_stream.cpp b/src/stateless/trex_stream.cpp index 2b5b2424..8bf04748 100644 --- a/src/stateless/trex_stream.cpp +++ b/src/stateless/trex_stream.cpp @@ -45,6 +45,17 @@ TrexStream::~TrexStream() { } } +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 *************************************/ diff --git a/src/stateless/trex_stream_api.h b/src/stateless/trex_stream_api.h index 26999751..d3c0fb29 100644 --- a/src/stateless/trex_stream_api.h +++ b/src/stateless/trex_stream_api.h @@ -26,6 +26,8 @@ limitations under the License. #include <stdint.h> #include <string> +#include <json/json.h> + #include <trex_stream_vm.h> class TrexRpcCmdAddStream; @@ -48,7 +50,13 @@ public: static const uint32_t MIN_PKT_SIZE_BYTES = 1; static const uint32_t MAX_PKT_SIZE_BYTES = 9000; -private: + /* 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; @@ -82,6 +90,8 @@ private: } m_rx_check; + /* original template provided by requester */ + Json::Value m_stream_json; }; /** @@ -90,15 +100,15 @@ private: */ class TrexStreamContinuous : public TrexStream { public: - TrexStreamContinuous(uint8_t port_id, uint32_t stream_id, uint32_t pps) : TrexStream(port_id, stream_id), m_pps(pps) { + TrexStreamContinuous(uint8_t port_id, uint32_t stream_id, double pps) : TrexStream(port_id, stream_id), m_pps(pps) { } - uint32_t get_pps() { + double get_pps() { return m_pps; } protected: - uint32_t m_pps; + double m_pps; }; /** @@ -107,7 +117,7 @@ protected: */ class TrexStreamBurst : public TrexStream { public: - TrexStreamBurst(uint8_t port_id, uint32_t stream_id, uint32_t total_pkts, uint32_t pps) : + 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) { @@ -115,7 +125,7 @@ public: protected: uint32_t m_total_pkts; - uint32_t m_pps; + double m_pps; }; /** @@ -127,7 +137,7 @@ public: TrexStreamMultiBurst(uint8_t port_id, uint32_t stream_id, uint32_t pkts_per_burst, - uint32_t pps, + 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) { |