diff options
-rw-r--r-- | scripts/automation/trex_control_plane/client_utils/jsonrpc_client.py | 206 | ||||
-rw-r--r-- | scripts/automation/trex_control_plane/console/trex_console.py | 100 | ||||
-rw-r--r-- | scripts/automation/trex_control_plane/console/trex_status.py | 157 | ||||
-rw-r--r-- | src/rpc-server/commands/trex_rpc_cmd_general.cpp | 51 | ||||
-rw-r--r-- | src/rpc-server/commands/trex_rpc_cmds.h | 7 | ||||
-rw-r--r-- | src/rpc-server/trex_rpc_cmds_table.cpp | 1 | ||||
-rw-r--r-- | src/stateless/trex_stateless.cpp | 23 | ||||
-rw-r--r-- | src/stateless/trex_stateless_api.h | 31 |
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 ¶ms, 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 ¶ms, 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 ¶ms, 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 ¶ms, Json::Value &result) { return (TREX_RPC_CMD_OK); } + +/** + * get port stats + * + */ +trex_rpc_cmd_rc_e +TrexRpcCmdGetPortStats::_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_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; }; /** |