summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--scripts/automation/trex_control_plane/client_utils/jsonrpc_client.py206
-rw-r--r--scripts/automation/trex_control_plane/console/trex_console.py100
-rw-r--r--scripts/automation/trex_control_plane/console/trex_status.py157
-rw-r--r--src/rpc-server/commands/trex_rpc_cmd_general.cpp51
-rw-r--r--src/rpc-server/commands/trex_rpc_cmds.h7
-rw-r--r--src/rpc-server/trex_rpc_cmds_table.cpp1
-rw-r--r--src/stateless/trex_stateless.cpp23
-rw-r--r--src/stateless/trex_stateless_api.h31
8 files changed, 502 insertions, 74 deletions
diff --git a/scripts/automation/trex_control_plane/client_utils/jsonrpc_client.py b/scripts/automation/trex_control_plane/client_utils/jsonrpc_client.py
index aff6b36e..96a4154b 100644
--- a/scripts/automation/trex_control_plane/client_utils/jsonrpc_client.py
+++ b/scripts/automation/trex_control_plane/client_utils/jsonrpc_client.py
@@ -17,13 +17,38 @@ class bcolors:
BOLD = '\033[1m'
UNDERLINE = '\033[4m'
+# sub class to describe a batch
+class BatchMessage(object):
+ def __init__ (self, rpc_client):
+ self.rpc_client = rpc_client
+ self.batch_list = []
+ def add (self, method_name, params = {}):
+
+ id = self.rpc_client.id_gen.next()
+ msg = self.rpc_client.create_jsonrpc_v2(method_name, params, id)
+ self.batch_list.append(msg)
+
+ def invoke (self, block = False):
+ if not self.rpc_client.connected:
+ return False, "Not connected to server"
+
+ msg = json.dumps(self.batch_list)
+
+ rc, resp_list = self.rpc_client.send_raw_msg(msg, block = False)
+ if len(self.batch_list) == 1:
+ return True, [(rc, resp_list)]
+ else:
+ return rc, resp_list
+
+
+# JSON RPC v2.0 client
class JsonRpcClient(object):
def __init__ (self, default_server, default_port):
self.verbose = False
self.connected = False
-
+
# default values
self.port = default_port
self.server = default_server
@@ -63,6 +88,9 @@ class JsonRpcClient(object):
print "[verbose] " + msg
+ def create_batch (self):
+ return BatchMessage(self)
+
def create_jsonrpc_v2 (self, method_name, params = {}, id = None):
msg = {}
msg["jsonrpc"] = "2.0"
@@ -72,22 +100,21 @@ class JsonRpcClient(object):
msg["id"] = id
- return json.dumps(msg)
-
- def invoke_rpc_method (self, method_name, params = {}, block = False):
- rc, msg = self._invoke_rpc_method(method_name, params, block)
- if not rc:
- self.disconnect()
+ return msg
- return rc, msg
- def _invoke_rpc_method (self, method_name, params = {}, block = False):
+ def invoke_rpc_method (self, method_name, params = {}, block = False):
if not self.connected:
return False, "Not connected to server"
id = self.id_gen.next()
msg = self.create_jsonrpc_v2(method_name, params, id = id)
+ msg = json.dumps(msg)
+ return self.send_raw_msg(msg, block)
+
+
+ def send_raw_msg (self, msg, block = False):
self.verbose_msg("Sending Request To Server:\n\n" + self.pretty_json(msg) + "\n")
if block:
@@ -96,6 +123,7 @@ class JsonRpcClient(object):
try:
self.socket.send(msg, flags = zmq.NOBLOCK)
except zmq.error.ZMQError as e:
+ self.disconnect()
return False, "Failed To Get Send Message"
got_response = False
@@ -113,22 +141,41 @@ class JsonRpcClient(object):
sleep(0.2)
if not got_response:
+ self.disconnect()
return False, "Failed To Get Server Response"
self.verbose_msg("Server Response:\n\n" + self.pretty_json(response) + "\n")
# decode
+
+ # batch ?
response_json = json.loads(response)
+ if isinstance(response_json, list):
+ rc_list = []
+
+ for single_response in response_json:
+ rc, msg = self.process_single_response(single_response)
+ rc_list.append( (rc, msg) )
+
+ return True, rc_list
+
+ else:
+ rc, msg = self.process_single_response(response_json)
+ return rc, msg
+
+
+ def process_single_response (self, response_json):
+
if (response_json.get("jsonrpc") != "2.0"):
return False, "Malfromed Response ({0})".format(str(response))
- if (response_json.get("id") != id):
- return False, "Server Replied With Bad ID ({0})".format(str(response))
-
# error reported by server
if ("error" in response_json):
- return True, response_json["error"]["message"]
+ if "specific_err" in response_json["error"]:
+ return False, response_json["error"]["specific_err"]
+ else:
+ return False, response_json["error"]["message"]
# if no error there should be a result
if ("result" not in response_json):
@@ -137,17 +184,7 @@ class JsonRpcClient(object):
return True, response_json["result"]
- def ping_rpc_server(self):
-
- return self.invoke_rpc_method("ping", block = False)
-
- def get_rpc_server_status (self):
- return self.invoke_rpc_method("get_status")
-
- def query_rpc_server(self):
- return self.invoke_rpc_method("get_supported_cmds")
-
-
+
def set_verbose(self, mode):
self.verbose = mode
@@ -183,12 +220,6 @@ class JsonRpcClient(object):
self.connected = True
- # ping the server
- rc, err = self.ping_rpc_server()
- if not rc:
- self.disconnect()
- return rc, err
-
return True, ""
@@ -206,10 +237,119 @@ class JsonRpcClient(object):
def is_connected(self):
return self.connected
-
def __del__(self):
print "Shutting down RPC client\n"
self.context.destroy(linger=0)
-if __name__ == "__main__":
- pass
+# MOVE THIS TO DAN'S FILE
+class TrexStatelessClient(JsonRpcClient):
+
+ def __init__ (self, server, port, user):
+
+ super(TrexStatelessClient, self).__init__(server, port)
+
+ self.user = user
+ self.port_handlers = {}
+ self.system_info = None
+
+ def whoami (self):
+ return self.user
+
+ def ping_rpc_server(self):
+
+ return self.invoke_rpc_method("ping", block = False)
+
+ def get_rpc_server_version (self):
+ return self.invoke_rpc_method("get_version")
+
+ def get_system_info (self):
+ return self.invoke_rpc_method("get_system_info")
+
+ def get_supported_cmds(self):
+ return self.invoke_rpc_method("get_supported_cmds")
+
+ def get_port_count (self):
+ if not self.system_info:
+ return 0
+
+ return self.system_info["port_count"]
+
+ def connect (self):
+ rc, err = super(TrexStatelessClient, self).connect()
+ if not rc:
+ return rc, err
+
+ # ping the server
+ rc, msg = self.ping_rpc_server()
+ if not rc:
+ self.disconnect()
+ return rc, msg
+
+ # get supported commands
+ rc, msg = self.get_supported_cmds()
+ if not rc:
+ self.disconnect()
+ return rc, msg
+
+ self.supported_rpc = [str(x) for x in msg if x]
+
+ # get system info
+ rc, msg = self.get_system_info()
+ if not rc:
+ self.disconnect()
+ return rc, msg
+
+ self.system_info = msg
+
+ return True, ""
+
+ # take ownership over ports
+ def take_ownership (self, port_id_array, force = False):
+ if not self.connected:
+ return False, "Not connected to server"
+
+ batch = self.create_batch()
+
+ for port_id in port_id_array:
+ batch.add("acquire", params = {"port_id":port_id, "user":self.user, "force":force})
+
+ rc, resp_list = batch.invoke()
+ if not rc:
+ return rc, resp_list
+
+ for i, rc in enumerate(resp_list):
+ if rc[0]:
+ self.port_handlers[port_id_array[i]] = rc[1]
+
+ return True, resp_list
+
+
+ def get_owned_ports (self):
+ return self.port_handlers.keys()
+
+ # fetch port stats
+ def get_port_stats (self, port_id_array):
+ if not self.connected:
+ return False, "Not connected to server"
+
+ batch = self.create_batch()
+
+ # empty list means all
+ if port_id_array == []:
+ port_id_array = list([x for x in xrange(0, self.system_info["port_count"])])
+
+ for port_id in port_id_array:
+
+ # let the server handle un-acquired errors
+ if self.port_handlers.get(port_id):
+ handler = self.port_handlers[port_id]
+ else:
+ handler = ""
+
+ batch.add("get_port_stats", params = {"port_id":port_id, "handler":handler})
+
+
+ rc, resp_list = batch.invoke()
+
+ return rc, resp_list
+
diff --git a/scripts/automation/trex_control_plane/console/trex_console.py b/scripts/automation/trex_control_plane/console/trex_console.py
index 6514a51c..4ce6127e 100644
--- a/scripts/automation/trex_control_plane/console/trex_console.py
+++ b/scripts/automation/trex_control_plane/console/trex_console.py
@@ -4,9 +4,13 @@ import cmd
import json
import ast
import argparse
+import random
+import string
+
import sys
import trex_root_path
-from client_utils.jsonrpc_client import JsonRpcClient
+
+from client_utils.jsonrpc_client import TrexStatelessClient
import trex_status
class TrexConsole(cmd.Cmd):
@@ -34,7 +38,7 @@ class TrexConsole(cmd.Cmd):
# set verbose on / off
def do_verbose (self, line):
- '''shows or set verbose mode\n'''
+ '''Shows or set verbose mode\n'''
if line == "":
print "\nverbose is " + ("on\n" if self.verbose else "off\n")
@@ -78,6 +82,81 @@ class TrexConsole(cmd.Cmd):
print "\n*** " + msg + "\n"
return
+ def do_force_acquire (self, line):
+ '''Acquires ports by force\n'''
+
+ self.do_acquire(line, True)
+
+ def parse_ports_from_line (self, line):
+ port_list = set()
+
+ if line:
+ for port_id in line.split(' '):
+ if (not port_id.isdigit()) or (int(port_id) < 0) or (int(port_id) >= self.rpc_client.get_port_count()):
+ print "Please provide a list of ports seperated by spaces between 0 and {0}".format(self.rpc_client.get_port_count() - 1)
+ return None
+
+ port_list.add(int(port_id))
+
+ port_list = list(port_list)
+
+ else:
+ port_list = [i for i in xrange(0, self.rpc_client.get_port_count())]
+
+ return port_list
+
+ def do_acquire (self, line, force = False):
+ '''Acquire ports\n'''
+
+ port_list = self.parse_ports_from_line(line)
+ if not port_list:
+ return
+
+ print "\nTrying to acquire ports: " + (" ".join(str(x) for x in port_list)) + "\n"
+
+ rc, resp_list = self.rpc_client.take_ownership(port_list, force)
+
+ if not rc:
+ print "\n*** " + resp_list + "\n"
+ return
+
+ for i, rc in enumerate(resp_list):
+ if rc[0]:
+ print "Port {0} - Acquired".format(port_list[i])
+ else:
+ print "Port {0} - ".format(port_list[i]) + rc[1]
+
+ print "\n"
+
+ def do_release (self, line):
+ '''Release ports\n'''
+
+ port_list = self.parse_ports_from_line(line)
+ if not port_list:
+ return
+
+ def do_get_port_stats (self, line):
+ '''Get ports stats\n'''
+
+ port_list = self.parse_ports_from_line(line)
+ if not port_list:
+ return
+
+ rc, resp_list = self.rpc_client.get_port_stats(port_list)
+
+ if not rc:
+ print "\n*** " + resp_list + "\n"
+ return
+
+ for i, rc in enumerate(resp_list):
+ if rc[0]:
+ print "\nPort {0} stats:\n{1}\n".format(port_list[i], self.rpc_client.pretty_json(json.dumps(rc[1])))
+ else:
+ print "\nPort {0} - ".format(i) + rc[1] + "\n"
+
+ print "\n"
+
+
def do_connect (self, line):
'''Connects to the server\n'''
@@ -97,8 +176,7 @@ class TrexConsole(cmd.Cmd):
print "\n*** " + msg + "\n"
return
- rc, msg = self.rpc_client.query_rpc_server()
-
+ rc, msg = self.rpc_client.get_supported_cmds()
if rc:
self.supported_rpc = [str(x) for x in msg if x]
@@ -135,7 +213,7 @@ class TrexConsole(cmd.Cmd):
rc, msg = self.rpc_client.invoke_rpc_method(method, params)
if rc:
- print "\nServer Response:\n\n" + json.dumps(msg) + "\n"
+ print "\nServer Response:\n\n" + self.rpc_client.pretty_json(json.dumps(msg)) + "\n"
else:
print "\n*** " + msg + "\n"
#print "Please try 'reconnect' to reconnect to server"
@@ -151,7 +229,7 @@ class TrexConsole(cmd.Cmd):
trex_status.show_trex_status(self.rpc_client)
def do_quit(self, line):
- '''exit the client\n'''
+ '''Exit the client\n'''
return True
def do_disconnect (self, line):
@@ -166,6 +244,10 @@ class TrexConsole(cmd.Cmd):
else:
print msg + "\n"
+ def do_whoami (self, line):
+ '''Prints console user name\n'''
+ print "\n" + self.rpc_client.whoami() + "\n"
+
def postcmd(self, stop, line):
if self.rpc_client.is_connected():
self.prompt = "TRex > "
@@ -230,6 +312,10 @@ def setParserOptions ():
default = 5050,
type = int)
+ parser.add_argument("-u", "--user", help = "User Name [default is random generated]\n",
+ default = 'user_' + ''.join(random.choice(string.digits) for _ in range(5)),
+ type = str)
+
return parser
def main ():
@@ -237,7 +323,7 @@ def main ():
options = parser.parse_args(sys.argv[1:])
# RPC client
- rpc_client = JsonRpcClient(options.server, options.port)
+ rpc_client = TrexStatelessClient(options.server, options.port, options.user)
# console
try:
diff --git a/scripts/automation/trex_control_plane/console/trex_status.py b/scripts/automation/trex_control_plane/console/trex_status.py
index 54853ea3..b01bc3e7 100644
--- a/scripts/automation/trex_control_plane/console/trex_status.py
+++ b/scripts/automation/trex_control_plane/console/trex_status.py
@@ -51,6 +51,46 @@ def float_to_human_readable (size, suffix = "bps"):
size /= 1024.0
return "NaN"
+
+# total stats (ports + global)
+class Stats():
+ def __init__ (self, rpc_client, port_list, interval = 100):
+
+ self.rpc_client = rpc_client
+
+ self.port_list = port_list
+ self.port_stats = {}
+
+ self.interval = interval
+ self.delay_count = 0
+
+ def get_port_stats (self, port_id):
+ if self.port_stats.get(port_id):
+ return self.port_stats[port_id]
+ else:
+ return None
+
+ def query_sync (self):
+ self.delay_count += 1
+ if self.delay_count < self.interval:
+ return
+
+ self.delay_count = 0
+
+ # query global stats
+
+ # query port stats
+
+ rc, resp_list = self.rpc_client.get_port_stats(self.port_list)
+ if not rc:
+ return
+
+ for i, rc in enumerate(resp_list):
+ if rc[0]:
+ self.port_stats[self.port_list[i]] = rc[1]
+
+
+
# status object
class TrexStatus():
def __init__ (self, stdscr, rpc_client):
@@ -60,13 +100,39 @@ class TrexStatus():
self.get_server_info()
+ self.stats = Stats(rpc_client, self.rpc_client.get_owned_ports())
+
+ self.actions = {}
+ self.actions[ord('q')] = self.action_quit
+ self.actions[ord('p')] = self.action_ping
+
+ def action_quit(self):
+ return False
+
+ def action_ping (self):
+ self.add_log_event("Pinging RPC server")
+ rc, msg = self.rpc_client.ping_rpc_server()
+ if rc:
+ self.add_log_event("Server replied: '{0}'".format(msg))
+ else:
+ self.add_log_event("Failed to get reply")
+ return True
+
def get_server_info (self):
- rc, msg = self.rpc_client.get_rpc_server_status()
+ rc, msg = self.rpc_client.get_rpc_server_version()
+
+ if rc:
+ self.server_version = msg
+ else:
+ self.server_version = None
+
+ rc, msg = self.rpc_client.get_system_info()
if rc:
- self.server_status = msg
+ self.server_sys_info = msg
else:
- self.server_status = None
+ self.server_sys_info = None
+
def add_log_event (self, msg):
self.log.append("[{0}] {1}".format(str(datetime.datetime.now().time()), msg))
@@ -87,29 +153,75 @@ class TrexStatus():
# static info panel
def update_info (self):
- if self.server_status == None:
+ if self.server_version == None:
return
self.info_panel.clear()
connection_details = self.rpc_client.get_connection_details()
- self.info_panel.getwin().addstr(3, 2, "{:<30} {:30}".format("Server:", connection_details['server'] + ":" + str(connection_details['port'])))
- self.info_panel.getwin().addstr(4, 2, "{:<30} {:30}".format("Version:", self.server_status["general"]["version"]))
+ self.info_panel.getwin().addstr(3, 2, "{:<30} {:30}".format("Server:",self.server_sys_info["hostname"] + ":" + str(connection_details['port'])))
+ self.info_panel.getwin().addstr(4, 2, "{:<30} {:30}".format("Version:", self.server_version["version"]))
self.info_panel.getwin().addstr(5, 2, "{:<30} {:30}".format("Build:",
- self.server_status["general"]["build_date"] + " @ " + self.server_status["general"]["build_time"] + " by " + self.server_status["general"]["version_user"]))
+ self.server_version["build_date"] + " @ " + self.server_version["build_time"] + " by " + self.server_version["built_by"]))
+
+ self.info_panel.getwin().addstr(6, 2, "{:<30} {:30}".format("Server Uptime:", self.server_sys_info["uptime"]))
+ self.info_panel.getwin().addstr(7, 2, "{:<30} {:<3} / {:<30}".format("DP Cores:", str(self.server_sys_info["dp_core_count"]) + " cores", self.server_sys_info["core_type"]))
+ self.info_panel.getwin().addstr(9, 2, "{:<30} {:<30}".format("Ports Count:", self.server_sys_info["port_count"]))
+
+ ports_owned = " ".join(str(x) for x in self.rpc_client.get_owned_ports())
+ if not ports_owned:
+ ports_owned = "None"
+ self.info_panel.getwin().addstr(10, 2, "{:<30} {:<30}".format("Ports Owned:", ports_owned))
- self.info_panel.getwin().addstr(6, 2, "{:<30} {:30}".format("Server Uptime:", self.server_status["general"]["uptime"]))
# general stats
- def update_general (self, gen_stats):
- pass
+ def update_ports_stats (self):
+
+ self.ports_stats_panel.clear()
+
+ owned_ports = self.rpc_client.get_owned_ports()
+ if not owned_ports:
+ self.ports_stats_panel.getwin().addstr(3, 2, "No Owned Ports - Please Acquire One Or More Ports")
+ return
+
+ # table header
+ self.ports_stats_panel.getwin().addstr(3, 2, "{:^15} {:^15} {:^15} {:^15} {:^15} {:^15} {:^15}".format(
+ "Port ID", "Tx [pps]", "Tx [bps]", "Tx [bytes]", "Rx [pps]", "Rx [bps]", "Rx [bytes]"))
+
+ # port loop
+ self.stats.query_sync()
+
+ for i, port_index in enumerate(owned_ports):
+
+ port_stats = self.stats.get_port_stats(port_index)
+
+ if port_stats:
+ self.ports_stats_panel.getwin().addstr(5 + (i * 4), 2, "{:^15} {:^15,} {:^15,} {:^15,} {:^15,} {:^15,} {:^15,}".format(
+ "{0} ({1})".format(str(port_index), self.server_sys_info["ports"][port_index]["speed"]),
+ port_stats["tx_pps"],
+ port_stats["tx_bps"],
+ port_stats["total_tx_bytes"],
+ port_stats["rx_pps"],
+ port_stats["rx_bps"],
+ port_stats["total_rx_bytes"]))
+
+ else:
+ self.ports_stats_panel.getwin().addstr(5 + (i * 4), 2, "{:^15} {:^15} {:^15} {:^15} {:^15} {:^15} {:^15}".format(
+ "{0} ({1})".format(str(port_index), self.server_sys_info["ports"][port_index]["speed"]),
+ "N/A",
+ "N/A",
+ "N/A",
+ "N/A",
+ "N/A",
+ "N/A"))
# control panel
def update_control (self):
self.control_panel.clear()
- self.control_panel.getwin().addstr(1, 2, "'f' - freeze, 'c' - clear stats, 'p' - ping server, 'q' - quit")
+ self.control_panel.getwin().addstr(1, 2, "'g' - general, '0-{0}' - specific port, 'f' - freeze, 'c' - clear stats, 'p' - ping server, 'q' - quit"
+ .format(self.rpc_client.get_port_count() - 1))
index = 3
@@ -126,11 +238,11 @@ class TrexStatus():
self.max_x = self.stdscr.getmaxyx()[1]
# create cls panel
- self.main_panel = TrexStatusPanel(int(self.max_y * 0.8), self.max_x / 2, 0,0, "Trex Ports:")
+ self.ports_stats_panel = TrexStatusPanel(int(self.max_y * 0.8), self.max_x / 2, 0,0, "Trex Ports:")
- self.general_panel = TrexStatusPanel(int(self.max_y * 0.6), self.max_x / 2, 0, self.max_x /2, "General Statistics:")
+ self.general_panel = TrexStatusPanel(int(self.max_y * 0.5), self.max_x / 2, 0, self.max_x /2, "General Statistics:")
- self.info_panel = TrexStatusPanel(int(self.max_y * 0.2), self.max_x / 2, int(self.max_y * 0.6), self.max_x /2, "Server Info:")
+ self.info_panel = TrexStatusPanel(int(self.max_y * 0.3), self.max_x / 2, int(self.max_y * 0.5), self.max_x /2, "Server Info:")
self.control_panel = TrexStatusPanel(int(self.max_y * 0.2), self.max_x , int(self.max_y * 0.8), 0, "")
@@ -139,6 +251,18 @@ class TrexStatus():
def wait_for_key_input (self):
ch = self.stdscr.getch()
+ # no key , continue
+ if ch == curses.ERR:
+ return True
+
+ # check for registered function
+ if ch in self.actions:
+ return self.actions[ch]()
+ else:
+ self.add_log_event("Unknown key pressed, please see legend")
+
+ return True
+
if (ch != curses.ERR):
# stop/start status
if (ch == ord('f')):
@@ -160,7 +284,7 @@ class TrexStatus():
elif (ch == ord('q')):
return False
else:
- self.add_log_event("Unknown key pressed {0}".format("'" + chr(ch) + "'" if chr(ch).isalpha() else ""))
+ self.add_log_event("Unknown key pressed, please see legend")
return True
@@ -187,10 +311,11 @@ class TrexStatus():
self.update_control()
self.update_info()
+ self.update_ports_stats()
panel.update_panels();
self.stdscr.refresh()
- sleep(0.1)
+ sleep(0.01)
def show_trex_status_internal (stdscr, rpc_client):
diff --git a/src/rpc-server/commands/trex_rpc_cmd_general.cpp b/src/rpc-server/commands/trex_rpc_cmd_general.cpp
index 106a167a..0c9f2c49 100644
--- a/src/rpc-server/commands/trex_rpc_cmd_general.cpp
+++ b/src/rpc-server/commands/trex_rpc_cmd_general.cpp
@@ -81,7 +81,7 @@ TrexRpcCmdGetVersion::_run(const Json::Value &params, Json::Value &result) {
#else
- section["version"] = "v0.0";
+ section["version"] = "v1.75";
section["build_date"] = __DATE__;
section["build_time"] = __TIME__;
section["built_by"] = "MOCK";
@@ -177,19 +177,7 @@ TrexRpcCmdGetSysInfo::_run(const Json::Value &params, Json::Value &result) {
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;
- }
+ section["ports"][i]["status"] = port->get_state_as_string();
}
@@ -234,7 +222,7 @@ TrexRpcCmdAcquire::_run(const Json::Value &params, Json::Value &result) {
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() + "'");
+ generate_execute_err(result, "port is already taken by '" + port->get_owner() + "'");
}
port->set_owner(new_owner);
@@ -265,3 +253,36 @@ TrexRpcCmdRelease::_run(const Json::Value &params, Json::Value &result) {
return (TREX_RPC_CMD_OK);
}
+
+/**
+ * get port stats
+ *
+ */
+trex_rpc_cmd_rc_e
+TrexRpcCmdGetPortStats::_run(const Json::Value &params, Json::Value &result) {
+
+ uint8_t port_id = parse_port(params, result);
+
+ TrexStatelessPort *port = TrexStateless::get_instance().get_port_by_id(port_id);
+
+ if (port->get_state() == TrexStatelessPort::PORT_STATE_DOWN) {
+ generate_execute_err(result, "cannot get stats - port is down");
+ }
+
+ result["result"]["status"] = port->get_state_as_string();
+
+ result["result"]["tx_bps"] = Json::Value::UInt64(port->get_port_stats().tx_bps);
+ result["result"]["tx_pps"] = Json::Value::UInt64(port->get_port_stats().tx_pps);
+ result["result"]["total_tx_pkts"] = Json::Value::UInt64(port->get_port_stats().total_tx_pkts);
+ result["result"]["total_tx_bytes"] = Json::Value::UInt64(port->get_port_stats().total_tx_bytes);
+
+ result["result"]["rx_bps"] = Json::Value::UInt64(port->get_port_stats().rx_bps);
+ result["result"]["rx_pps"] = Json::Value::UInt64(port->get_port_stats().rx_pps);
+ result["result"]["total_rx_pkts"] = Json::Value::UInt64(port->get_port_stats().total_rx_pkts);
+ result["result"]["total_rx_bytes"] = Json::Value::UInt64(port->get_port_stats().total_rx_bytes);
+
+ result["result"]["tx_rx_error"] = Json::Value::UInt64(port->get_port_stats().tx_rx_errors);
+
+ 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 e261d1c6..5926a8d8 100644
--- a/src/rpc-server/commands/trex_rpc_cmds.h
+++ b/src/rpc-server/commands/trex_rpc_cmds.h
@@ -75,6 +75,12 @@ TREX_RPC_CMD_DEFINE(TrexRpcCmdRelease, "release", 1, true);
/**
+ * port commands
+ */
+TREX_RPC_CMD_DEFINE(TrexRpcCmdGetPortStats, "get_port_stats", 1, true);
+
+
+/**
* stream cmds
*/
TREX_RPC_CMD_DEFINE(TrexRpcCmdRemoveAllStreams, "remove_all_streams", 1, true);
@@ -100,5 +106,4 @@ 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/trex_rpc_cmds_table.cpp b/src/rpc-server/trex_rpc_cmds_table.cpp
index 170f0de1..c1c546f3 100644
--- a/src/rpc-server/trex_rpc_cmds_table.cpp
+++ b/src/rpc-server/trex_rpc_cmds_table.cpp
@@ -40,6 +40,7 @@ TrexRpcCommandsTable::TrexRpcCommandsTable() {
register_command(new TrexRpcCmdGetOwner());
register_command(new TrexRpcCmdAcquire());
register_command(new TrexRpcCmdRelease());
+ register_command(new TrexRpcCmdGetPortStats());
/* stream commands */
register_command(new TrexRpcCmdAddStream());
diff --git a/src/stateless/trex_stateless.cpp b/src/stateless/trex_stateless.cpp
index 6a3169d4..0eb96f05 100644
--- a/src/stateless/trex_stateless.cpp
+++ b/src/stateless/trex_stateless.cpp
@@ -80,6 +80,7 @@ uint8_t TrexStateless::get_port_count() {
TrexStatelessPort::TrexStatelessPort(uint8_t port_id) : m_port_id(port_id) {
m_port_state = PORT_STATE_UP_IDLE;
clear_owner();
+ m_stats = {0};
}
@@ -121,12 +122,30 @@ TrexStreamTable * TrexStatelessPort::get_stream_table() {
return &m_stream_table;
}
+
+std::string
+TrexStatelessPort::get_state_as_string() {
+
+ switch (get_state()) {
+ case PORT_STATE_DOWN:
+ return "down";
+
+ case PORT_STATE_UP_IDLE:
+ return "idle";
+
+ case PORT_STATE_TRANSMITTING:
+ return "transmitting";
+ }
+
+ return "unknown";
+}
+
void
TrexStatelessPort::get_properties(string &driver, string &speed) {
/* take this from DPDK */
- driver = "Unknown Driver";
- speed = "Unknown Speed";
+ driver = "e1000";
+ speed = "1 Gbps";
}
diff --git a/src/stateless/trex_stateless_api.h b/src/stateless/trex_stateless_api.h
index e02e93da..7a9080aa 100644
--- a/src/stateless/trex_stateless_api.h
+++ b/src/stateless/trex_stateless_api.h
@@ -49,6 +49,20 @@ public:
class TrexStatelessPort {
public:
+ struct TrexPortStats {
+ uint64_t tx_pps;
+ uint64_t tx_bps;
+ uint64_t total_tx_pkts;
+ uint64_t total_tx_bytes;
+
+ uint64_t rx_pps;
+ uint64_t rx_bps;
+ uint64_t total_rx_pkts;
+ uint64_t total_rx_bytes;
+
+ uint64_t tx_rx_errors;
+ };
+
/**
* port state
*/
@@ -97,6 +111,12 @@ public:
}
/**
+ * port state as string
+ *
+ */
+ std::string get_state_as_string();
+
+ /**
* fill up properties of the port
*
* @author imarom (16-Sep-15)
@@ -149,6 +169,16 @@ public:
}
+ const TrexPortStats & get_port_stats(void) {
+ /* scrabble */
+ m_stats.tx_bps += 1 + rand() % 100;
+ m_stats.tx_pps += 1 + rand() % 10;
+ m_stats.total_tx_bytes += 1 + rand() % 10;
+ m_stats.total_tx_pkts += 1 + rand() % 5;
+
+ return m_stats;
+ }
+
private:
std::string generate_handler();
@@ -158,6 +188,7 @@ private:
port_state_e m_port_state;
std::string m_owner;
std::string m_owner_handler;
+ TrexPortStats m_stats;
};
/**