diff options
author | Hanoh Haim <hhaim@cisco.com> | 2015-11-09 11:20:28 +0200 |
---|---|---|
committer | Hanoh Haim <hhaim@cisco.com> | 2015-11-09 11:20:28 +0200 |
commit | 82280f7c87fabed60d83643bd9ec2c79cac34668 (patch) | |
tree | 62916038bc3650e161c53bc1f9a44df02dca8fe3 | |
parent | 7c9355cc198ee897de9cd2d60e88a232ce1fa405 (diff) | |
parent | c6d2cb0554ebc39142fb433040a968714a7ec24f (diff) |
Merge branch 'rpc_intg1'
86 files changed, 4214 insertions, 1707 deletions
@@ -1,4 +1,4 @@ -v1.78 +v1.78-intg1 diff --git a/linux/ws_main.py b/linux/ws_main.py index eac46ac7..d020411a 100755 --- a/linux/ws_main.py +++ b/linux/ws_main.py @@ -91,12 +91,20 @@ def configure(conf): conf.load('g++') verify_cc_version(conf.env) +bp_sim_main = SrcGroup(dir='src', + src_list=['main.cpp']) + +bp_sim_gtest = SrcGroup(dir='src', + src_list=[ + 'bp_gtest.cpp', + 'gtest/tuple_gen_test.cpp', + 'gtest/nat_test.cpp', + 'gtest/trex_stateless_gtest.cpp' + ]) main_src = SrcGroup(dir='src', src_list=[ - 'main.cpp', 'bp_sim.cpp', - 'bp_gtest.cpp', 'os_time.cpp', 'rx_check.cpp', 'tuple_gen.cpp', @@ -110,9 +118,6 @@ main_src = SrcGroup(dir='src', 'utl_cpuu.cpp', 'msg_manager.cpp', - 'gtest/tuple_gen_test.cpp', - 'gtest/nat_test.cpp', - 'gtest/trex_stateless_gtest.cpp', 'pal/linux/pal_utl.cpp', 'pal/linux/mbuf.cpp' @@ -146,7 +151,9 @@ stateless_src = SrcGroup(dir='src/stateless/', 'cp/trex_stream_vm.cpp', 'cp/trex_stateless.cpp', 'cp/trex_stateless_port.cpp', - 'dp/trex_stateless_dp_core.cpp' + 'cp/trex_streams_compiler.cpp', + 'dp/trex_stateless_dp_core.cpp', + 'messaging/trex_stateless_messaging.cpp', ]) # RPC code rpc_server_src = SrcGroup(dir='src/rpc-server/', @@ -168,9 +175,8 @@ rpc_server_src = SrcGroup(dir='src/rpc-server/', rpc_server_mock_src = SrcGroup(dir='src/mock/', src_list=[ 'trex_rpc_server_mock.cpp', + 'trex_platform_api_mock.cpp', '../gtest/rpc_test.cpp', - '../pal/linux/mbuf.cpp', - '../os_time.cpp', ]) # JSON package @@ -179,12 +185,6 @@ json_src = SrcGroup(dir='external_libs/json', 'jsoncpp.cpp' ]) -rpc_server_mock = SrcGroups([cmn_src, - rpc_server_src, - rpc_server_mock_src, - stateless_src, - json_src - ]) yaml_src = SrcGroup(dir='external_libs/yaml-cpp/src/', src_list=[ @@ -216,11 +216,31 @@ yaml_src = SrcGroup(dir='external_libs/yaml-cpp/src/', 'stream.cpp', 'tag.cpp']); + +rpc_server_mock = SrcGroups([ + main_src, + cmn_src, + rpc_server_src, + rpc_server_mock_src, + stateless_src, + json_src, + yaml_src, + net_src, + ]) + +# REMOVE ME - need to decide if stateless is part of bp sim or not +bp_hack_for_compile = SrcGroup(dir='/src/stub/', + src_list=['trex_stateless_stub.cpp' + ]) + bp =SrcGroups([ + bp_sim_main, + bp_sim_gtest, main_src, cmn_src , net_src , yaml_src, + bp_hack_for_compile, ]); @@ -242,6 +262,7 @@ includes_path =''' ../src/pal/linux/ ../src/rpc-server/ ../src/stateless/cp/ ../src/stateless/dp/ + ../src/stateless/messaging/ ../external_libs/json/ ../external_libs/zmq/include/ ../external_libs/yaml-cpp/include/ @@ -372,13 +393,13 @@ class build_option: build_types = [ - #build_option(name = "bp-sim", src = bp, debug_mode= DEBUG_, platform = PLATFORM_32, is_pie = False), - build_option(name = "bp-sim", src = bp, debug_mode= DEBUG_, platform = PLATFORM_64, is_pie = False), - #build_option(name = "bp-sim", src = bp, debug_mode= RELEASE_,platform = PLATFORM_32, is_pie = False), - build_option(name = "bp-sim", src = bp, debug_mode= RELEASE_,platform = PLATFORM_64, is_pie = False), + build_option(name = "bp-sim", src = bp, debug_mode= DEBUG_, platform = PLATFORM_64, is_pie = False, + flags = ['-Wall', '-Werror', '-Wno-sign-compare', '-Wno-strict-aliasing']), + build_option(name = "bp-sim", src = bp, debug_mode= RELEASE_,platform = PLATFORM_64, is_pie = False, + flags = ['-Wall', '-Werror', '-Wno-sign-compare', '-Wno-strict-aliasing']), build_option(name = "mock-rpc-server", use = ['zmq'], src = rpc_server_mock, debug_mode= DEBUG_,platform = PLATFORM_64, is_pie = False, - flags = ['-DTREX_RPC_MOCK_SERVER', '-Wall', '-Wno-sign-compare', '-Werror'], + flags = ['-DTREX_RPC_MOCK_SERVER', '-Wall', '-Werror', '-Wno-sign-compare'], rpath = ['.']), ] diff --git a/linux_dpdk/ws_main.py b/linux_dpdk/ws_main.py index 61a9d4f3..c8cbb38a 100755 --- a/linux_dpdk/ws_main.py +++ b/linux_dpdk/ws_main.py @@ -158,7 +158,9 @@ stateless_src = SrcGroup(dir='src/stateless/', 'cp/trex_stream_vm.cpp', 'cp/trex_stateless.cpp', 'cp/trex_stateless_port.cpp', - 'dp/trex_stateless_dp_core.cpp' + 'cp/trex_streams_compiler.cpp', + 'dp/trex_stateless_dp_core.cpp', + 'messaging/trex_stateless_messaging.cpp' ]) # JSON package json_src = SrcGroup(dir='external_libs/json', @@ -415,6 +417,7 @@ includes_path =''' ../src/pal/linux_dpdk/ ../src/rpc-server/ ../src/stateless/cp/ ../src/stateless/dp/ + ../src/stateless/messaging/ ../external_libs/yaml-cpp/include/ ../external_libs/zmq/include/ @@ -579,6 +582,12 @@ class build_option: # support c++ 2011 flags += ['-std=c++0x'] + flags += ['-Wall', + '-Werror', + '-Wno-literal-suffix', + '-Wno-sign-compare', + '-Wno-strict-aliasing'] + return (flags) def get_c_flags (self): diff --git a/scripts/automation/trex_control_plane/client/trex_async_client.py b/scripts/automation/trex_control_plane/client/trex_async_client.py new file mode 100644 index 00000000..72cce5aa --- /dev/null +++ b/scripts/automation/trex_control_plane/client/trex_async_client.py @@ -0,0 +1,203 @@ +#!/router/bin/python + +try: + # support import for Python 2 + import outer_packages +except ImportError: + # support import for Python 3 + import client.outer_packages +from client_utils.jsonrpc_client import JsonRpcClient, BatchMessage + +import json +import threading +import time +import datetime +import zmq +import re + +from common.trex_stats import * +from common.trex_streams import * + +# basic async stats class +class TrexAsyncStats(object): + def __init__ (self): + self.ref_point = None + self.current = {} + self.last_update_ts = datetime.datetime.now() + + def __format_num (self, size, suffix = ""): + + for unit in ['','K','M','G','T','P']: + if abs(size) < 1000.0: + return "%3.2f %s%s" % (size, unit, suffix) + size /= 1000.0 + + return "NaN" + + def update (self, snapshot): + + #update + self.last_update_ts = datetime.datetime.now() + + self.current = snapshot + + if self.ref_point == None: + self.ref_point = self.current + + + def get (self, field, format = False, suffix = ""): + + if not field in self.current: + return "N/A" + + if not format: + return self.current[field] + else: + return self.__format_num(self.current[field], suffix) + + + def get_rel (self, field, format = False, suffix = ""): + if not field in self.current: + return "N/A" + + if not format: + return (self.current[field] - self.ref_point[field]) + else: + return self.__format_num(self.current[field] - self.ref_point[field], suffix) + + + # return true if new data has arrived in the past 2 seconds + def is_online (self): + delta_ms = (datetime.datetime.now() - self.last_update_ts).total_seconds() * 1000 + return (delta_ms < 2000) + +# describes the general stats provided by TRex +class TrexAsyncStatsGeneral(TrexAsyncStats): + def __init__ (self): + super(TrexAsyncStatsGeneral, self).__init__() + + +# per port stats +class TrexAsyncStatsPort(TrexAsyncStats): + def __init__ (self): + super(TrexAsyncStatsPort, self).__init__() + + def get_stream_stats (self, stream_id): + return None + +# stats manager +class TrexAsyncStatsManager(): + def __init__ (self): + + self.general_stats = TrexAsyncStatsGeneral() + self.port_stats = {} + + + def get_general_stats (self): + return self.general_stats + + def get_port_stats (self, port_id): + + if not str(port_id) in self.port_stats: + return None + + return self.port_stats[str(port_id)] + + def update (self, snapshot): + + if snapshot['name'] == 'trex-global': + self.__handle_snapshot(snapshot['data']) + else: + # for now ignore the rest + return + + def __handle_snapshot (self, snapshot): + + general_stats = {} + port_stats = {} + + # filter the values per port and general + for key, value in snapshot.iteritems(): + + # match a pattern of ports + m = re.search('(.*)\-([0-8])', key) + if m: + + port_id = m.group(2) + field_name = m.group(1) + + if not port_id in port_stats: + port_stats[port_id] = {} + + port_stats[port_id][field_name] = value + + else: + # no port match - general stats + general_stats[key] = value + + # update the general object with the snapshot + self.general_stats.update(general_stats) + + # update all ports + for port_id, data in port_stats.iteritems(): + + if not port_id in self.port_stats: + self.port_stats[port_id] = TrexAsyncStatsPort() + + self.port_stats[port_id].update(data) + + + + + +class CTRexAsyncClient(): + def __init__ (self, port): + + self.port = port + + self.raw_snapshot = {} + + self.stats = TrexAsyncStatsManager() + + + self.tr = "tcp://localhost:{0}".format(self.port) + print "\nConnecting To ZMQ Publisher At {0}".format(self.tr) + + self.active = True + self.t = threading.Thread(target = self._run) + + # kill this thread on exit and don't add it to the join list + self.t.setDaemon(True) + self.t.start() + + + def _run (self): + + # Socket to talk to server + self.context = zmq.Context() + self.socket = self.context.socket(zmq.SUB) + + self.socket.connect(self.tr) + self.socket.setsockopt(zmq.SUBSCRIBE, '') + + while self.active: + msg = json.loads(self.socket.recv_string()) + + key = msg['name'] + self.raw_snapshot[key] = msg['data'] + + self.stats.update(msg) + + + def get_stats (self): + return self.stats + + def get_raw_snapshot (self): + #return str(self.stats.global_stats.get('m_total_tx_bytes')) + " / " + str(self.stats.global_stats.get_rel('m_total_tx_bytes')) + return self.raw_snapshot + + + def stop (self): + self.active = False + self.t.join() + diff --git a/scripts/automation/trex_control_plane/client/trex_hltapi.py b/scripts/automation/trex_control_plane/client/trex_hltapi.py index 46c283f8..92768ca4 100644..100755 --- a/scripts/automation/trex_control_plane/client/trex_hltapi.py +++ b/scripts/automation/trex_control_plane/client/trex_hltapi.py @@ -2,16 +2,305 @@ import trex_root_path from client_utils.packet_builder import CTRexPktBuilder +from trex_stateless_client import CTRexStatelessClient +from common.trex_streams import * +from client_utils.general_utils import id_count_gen +import dpkt -print "done!" class CTRexHltApi(object): def __init__(self): - pass + self.trex_client = None + self.connected = False + # self._stream_db = CStreamList() + self._port_data = {} + + # ----- session functions ----- # + + def connect(self, device, port_list, username, port=5050, reset=False, break_locks=False): + ret_dict = {"status": 0} + self.trex_client = CTRexStatelessClient(username, device, port) + res_ok, msg = self.trex_client.connect() + if not res_ok: + self.trex_client = None + ret_dict.update({"log": msg}) + return ret_dict + # arrived here, connection successfully created with server + # next, try acquiring ports of TRex + port_list = self.parse_port_list(port_list) + response = self.trex_client.acquire(port_list, force=break_locks) + res_ok, log = CTRexHltApi.process_response(port_list, response) + if not res_ok: + self.trex_client.disconnect() + self.trex_client = None + ret_dict.update({"log": log}) + # TODO: should revert taken ports?! + return ret_dict + # arrived here, all desired ports were successfully acquired + print log + if reset: + # remove all port traffic configuration from TRex + response = self.trex_client.remove_all_streams(port_list) + res_ok, log = CTRexHltApi.process_response(port_list, response) + if not res_ok: + self.trex_client.disconnect() + self.trex_client = None + ret_dict.update({"log": log}) + return ret_dict + print log + port_handle = {device: {port: port # since only supporting single TRex at the moment, 1:1 map + for port in port_list} + } + ret_dict.update({"status": 1, + "log": None, + "port_handle": port_handle, + "offline": 0}) # ports are online + self.connected = True + self._port_data_init(port_list) + return ret_dict + + def cleanup_session(self, port_list, maintain_lock=False): + ret_dict = {"status": 0} + if not maintain_lock: + # release taken ports + if port_list == "all": + port_list = self.trex_client.get_acquired_ports() + else: + port_list = self.parse_port_list(port_list) + response = self.trex_client.release(port_list) + res_ok, log = CTRexHltApi.process_response(port_list, response) + print log + if not res_ok: + ret_dict.update({"log": log}) + return ret_dict + ret_dict.update({"status": 1, + "log": None}) + self.trex_client.disconnect() + self.trex_client = None + self.connected = False + return ret_dict + + def interface_config(self, port_handle, mode="config"): + ALLOWED_MODES = ["config", "modify", "destroy"] + if mode not in ALLOWED_MODES: + raise ValueError("mode must be one of the following values: {modes}".format(modes=ALLOWED_MODES)) + # pass this function for now... + return {"status": 1, "log": None} + + # ----- traffic functions ----- # + def traffic_config(self, mode, port_handle, + l2_encap="ethernet_ii", mac_src="00:00:01:00:00:01", mac_dst="00:00:00:00:00:00", + l3_protocol="ipv4", ip_src_addr="0.0.0.0", ip_dst_addr="192.0.0.1", l3_length=110, + transmit_mode="continuous", rate_pps=100, + **kwargs): + ALLOWED_MODES = ["create", "modify", "remove", "enable", "disable", "reset"] + if mode not in ALLOWED_MODES: + raise ValueError("mode must be one of the following values: {modes}".format(modes=ALLOWED_MODES)) + if mode == "create": + # create a new stream with desired attributes, starting by creating packet + try: + packet = CTRexHltApi.generate_stream(l2_encap, mac_src, mac_dst, + l3_protocol, ip_src_addr, ip_dst_addr, l3_length) + # set transmission attributes + tx_mode = CTxMode(transmit_mode, rate_pps, **kwargs) + # set rx_stats + rx_stats = CRxStats() # defaults with disabled + # join the generated data into stream + stream_obj = CStream() + stream_obj_params = {"enabled": True, + "self_start": True, + "next_stream_id": -1, + "isg": 0.0, + "mode": tx_mode, + "rx_stats": rx_stats, + "packet": packet} # vm is excluded from this list since CTRexPktBuilder obj is passed + stream_obj.load_data(**stream_obj_params) + except Exception as e: + # some exception happened during the stream creation + return {"status": 0, "log": str(e)} + # try adding the stream, until free stream_id is found + port_data = self._port_data.get(port_handle) + id_candidate = None + # TODO: change this to better implementation + while True: + id_candidate = port_data["stream_id_gen"].next() + response = self.trex_client.add_stream(stream_id=id_candidate, + stream_obj=stream_obj, + port_id=port_handle) + res_ok, log = CTRexHltApi.process_response(port_handle, response) + if res_ok: + # found non-taken stream_id on server + # save it for modifying needs + port_data["streams"].update({id_candidate: stream_obj}) + break + else: + # proceed to another iteration to use another id + continue + return {"status": 1, + "stream_id": id_candidate, + "log": None} + else: + raise NotImplementedError("mode '{0}' is not supported yet on TRex".format(mode)) + + def traffic_control(self, action, port_handle): + ALLOWED_ACTIONS = ["clear_stats", "run", "stop", "sync_run"] + if action not in ALLOWED_ACTIONS: + raise ValueError("action must be one of the following values: {actions}".format(actions=ALLOWED_ACTIONS)) + # ret_dict = {"status": 0, "stopped": 1} + port_list = self.parse_port_list(port_handle) + if action == "run": + response = self.trex_client.start_traffic(port_id=port_list) + res_ok, log = CTRexHltApi.process_response(port_list, response) + if res_ok: + return {"status": 1, + "stopped": 0, + "log": None} + elif action == "stop": + response = self.trex_client.stop_traffic(port_id=port_list) + res_ok, log = CTRexHltApi.process_response(port_list, response) + if res_ok: + return {"status": 1, + "stopped": 1, + "log": None} + else: + raise NotImplementedError("action '{0}' is not supported yet on TRex".format(action)) + + # if we arrived here, this means that operation FAILED! + return {"status": 0, + "log": log} + + + def traffic_stats(self, port_handle, mode): + ALLOWED_MODES = ["aggregate", "streams", "all"] + if mode not in ALLOWED_MODES: + raise ValueError("mode must be one of the following values: {modes}".format(modes=ALLOWED_MODES)) + # pass this function for now... + if mode == "aggregate": + # create a new stream with desired attributes, starting by creating packet + try: + packet = CTRexHltApi.generate_stream(l2_encap, mac_src, mac_dst, + l3_protocol, ip_src_addr, ip_dst_addr, l3_length) + # set transmission attributes + tx_mode = CTxMode(transmit_mode, rate_pps, **kwargs) + # set rx_stats + rx_stats = CRxStats() # defaults with disabled + # join the generated data into stream + stream_obj = CStream() + stream_obj_params = {"enabled": True, + "self_start": True, + "next_stream_id": -1, + "isg": 0.0, + "mode": tx_mode, + "rx_stats": rx_stats, + "packet": packet} # vm is excluded from this list since CTRexPktBuilder obj is passed + stream_obj.load_data(**stream_obj_params) + except Exception as e: + # some exception happened during the stream creation + return {"status": 0, "log": str(e)} + # try adding the stream, until free stream_id is found + port_data = self._port_data.get(port_handle) + id_candidate = None + # TODO: change this to better implementation + while True: + id_candidate = port_data["stream_id_gen"].next() + response = self.trex_client.add_stream(stream_id=id_candidate, + stream_obj=stream_obj, + port_id=port_handle) + res_ok, log = CTRexHltApi.process_response(port_handle, response) + if res_ok: + # found non-taken stream_id on server + # save it for modifying needs + port_data["streams"].update({id_candidate: stream_obj}) + break + else: + # proceed to another iteration to use another id + continue + return {"status": 1, + "stream_id": id_candidate, + "log": None} + else: + raise NotImplementedError("mode '{0}' is not supported yet on TRex".format(mode)) + + def get_aggregate_port_stats(self, port_handle): + return self.traffic_stats(port_handle, mode="aggregate") + + def get_stream_stats(self, port_handle): + return self.traffic_stats(port_handle, mode="streams") + + # ----- internal functions ----- # + def _port_data_init(self, port_list): + for port in port_list: + self._port_data[port] = {"stream_id_gen": id_count_gen(), + "streams": {}} + + @staticmethod + def process_response(port_list, response): + if isinstance(port_list, list): + res_ok, response = response + log = CTRexHltApi.join_batch_response(response) + else: + res_ok = response.success + log = str(response) + return res_ok, log + + @staticmethod + def parse_port_list(port_list): + if isinstance(port_list, str): + return [int(port) + for port in port_list.split()] + elif isinstance(port_list, list): + return [int(port) + for port in port_list] + else: + return port_list + + @staticmethod + def join_batch_response(responses): + return "\n".join([str(response) + for response in responses]) + + @staticmethod + def generate_stream(l2_encap, mac_src, mac_dst, + l3_protocol, ip_src_addr, ip_dst_addr, l3_length): + ALLOWED_L3_PROTOCOL = {"ipv4": dpkt.ethernet.ETH_TYPE_IP, + "ipv6": dpkt.ethernet.ETH_TYPE_IP6, + "arp": dpkt.ethernet.ETH_TYPE_ARP} + ALLOWED_L4_PROTOCOL = {"tcp": dpkt.ip.IP_PROTO_TCP, + "udp": dpkt.ip.IP_PROTO_UDP, + "icmp": dpkt.ip.IP_PROTO_ICMP, + "icmpv6": dpkt.ip.IP_PROTO_ICMP6, + "igmp": dpkt.ip.IP_PROTO_IGMP, + "rtp": dpkt.ip.IP_PROTO_IRTP, + "isis": dpkt.ip.IP_PROTO_ISIS, + "ospf": dpkt.ip.IP_PROTO_OSPF} + + pkt_bld = CTRexPktBuilder() + if l2_encap == "ethernet_ii": + pkt_bld.add_pkt_layer("l2", dpkt.ethernet.Ethernet()) + # set Ethernet layer attributes + pkt_bld.set_eth_layer_addr("l2", "src", mac_src) + pkt_bld.set_eth_layer_addr("l2", "dst", mac_dst) + else: + raise NotImplementedError("l2_encap does not support the desired encapsulation '{0}'".format(l2_encap)) + # set l3 on l2 + if l3_protocol not in ALLOWED_L3_PROTOCOL: + raise ValueError("l3_protocol must be one of the following: {0}".format(ALLOWED_L3_PROTOCOL)) + pkt_bld.set_layer_attr("l2", "type", ALLOWED_L3_PROTOCOL[l3_protocol]) + + # set l3 attributes + if l3_protocol == "ipv4": + pkt_bld.add_pkt_layer("l3", dpkt.ip.IP()) + pkt_bld.set_ip_layer_addr("l3", "src", ip_src_addr) + pkt_bld.set_ip_layer_addr("l3", "dst", ip_dst_addr) + pkt_bld.set_layer_attr("l3", "len", l3_length) + else: + raise NotImplementedError("l3_protocol '{0}' is not supported by TRex yet.".format(l3_protocol)) + + pkt_bld.dump_pkt_to_pcap("stream_test.pcap") + return pkt_bld + - def config_traffic(self): - pass if __name__ == "__main__": pass diff --git a/scripts/automation/trex_control_plane/client/trex_stateless_client.py b/scripts/automation/trex_control_plane/client/trex_stateless_client.py index 334496d1..627c3365 100755 --- a/scripts/automation/trex_control_plane/client/trex_stateless_client.py +++ b/scripts/automation/trex_control_plane/client/trex_stateless_client.py @@ -10,58 +10,151 @@ from client_utils.jsonrpc_client import JsonRpcClient, BatchMessage from client_utils.packet_builder import CTRexPktBuilder import json from common.trex_stats import * +from common.trex_streams import * from collections import namedtuple +from trex_async_client import CTRexAsyncClient + +RpcCmdData = namedtuple('RpcCmdData', ['method', 'params']) + +class RpcResponseStatus(namedtuple('RpcResponseStatus', ['success', 'id', 'msg'])): + __slots__ = () + def __str__(self): + return "{id:^3} - {msg} ({stat})".format(id=self.id, + msg=self.msg, + stat="success" if self.success else "fail") + +# RpcResponseStatus = namedtuple('RpcResponseStatus', ['success', 'id', 'msg']) class CTRexStatelessClient(object): """docstring for CTRexStatelessClient""" - RpcCmdData = namedtuple('RpcCmdData', ['method', 'params']) - def __init__(self, username, server="localhost", port=5050, virtual=False): + def __init__(self, username, server="localhost", sync_port=5050, async_port = 4500, virtual=False): super(CTRexStatelessClient, self).__init__() self.user = username - self.tx_link = CTRexStatelessClient.CTxLink(server, port, virtual) + self.comm_link = CTRexStatelessClient.CCommLink(server, sync_port, virtual) + self.verbose = False self._conn_handler = {} self._active_ports = set() self._stats = CTRexStatsManager("port", "stream") self._system_info = None + self._server_version = None + self.__err_log = None + + self._async_client = CTRexAsyncClient(async_port) + # ----- decorator methods ----- # + def acquired(func): + def wrapper_f(self, *args, **kwargs): + # print func.__name__ + # print args + # print kwargs + port_ids = kwargs.get("port_id") + if not port_ids: + # print "FROM ARGS!" + # print args + port_ids = args[0] + if isinstance(port_ids, int): + # make sure port_ids is a list + port_ids = [port_ids] + bad_ids = set() + # print "=============" + # print port_ids + for port_id in port_ids: + port_owned = self._conn_handler.get(port_id) + if not port_owned: + bad_ids.add(port_id) + # elif active_and_owned: # stronger condition than just owned, hence gets precedence + # if port_owned and port_id in self._active_ports: + # continue + # else: + # bad_ids.add(port_id) + else: + continue + if bad_ids: + # Some port IDs are not according to desires status + raise ValueError("The requested method ('{0}') cannot be invoked since port IDs {1} are not " + "at allowed states".format(func.__name__, list(bad_ids))) + else: + return func(self, *args, **kwargs) + return wrapper_f + def force_status(owned=True, active_and_owned=False): def wrapper(func): def wrapper_f(self, *args, **kwargs): + # print args + # print kwargs port_ids = kwargs.get("port_id") + if not port_ids: + #print "FROM ARGS!" + #print args + port_ids = args[0] if isinstance(port_ids, int): # make sure port_ids is a list port_ids = [port_ids] bad_ids = set() + # print "=============" + # print port_ids for port_id in port_ids: - port_owned = self._conn_handler.get(kwargs.get(port_id)) + port_owned = self._conn_handler.get(port_id) if owned and not port_owned: - bad_ids.add(port_ids) + bad_ids.add(port_id) elif active_and_owned: # stronger condition than just owned, hence gets precedence if port_owned and port_id in self._active_ports: continue else: - bad_ids.add(port_ids) + bad_ids.add(port_id) else: continue if bad_ids: # Some port IDs are not according to desires status - raise RuntimeError("The requested method ('{0}') cannot be invoked since port IDs {1} are not" - "at allowed stated".format(func.__name__)) + raise ValueError("The requested method ('{0}') cannot be invoked since port IDs {1} are not " + "at allowed states".format(func.__name__, list(bad_ids))) else: - func(self, *args, **kwargs) + return func(self, *args, **kwargs) return wrapper_f return wrapper @property def system_info(self): if not self._system_info: - self._system_info = self.get_system_info() - return self._system_info + rc, info = self.get_system_info() + if rc: + self._system_info = info + else: + self.__err_log = info + return self._system_info if self._system_info else "Unknown" + + @property + def server_version(self): + if not self._server_version: + rc, ver_info = self.get_version() + if rc: + self._server_version = ver_info + else: + self.__err_log = ver_info + return self._server_version if self._server_version else "Unknown" + + def is_connected(self): + return self.comm_link.is_connected # ----- user-access methods ----- # + def connect(self): + rc, err = self.comm_link.connect() + if not rc: + return rc, err + return self._init_sync() + + def get_stats_async (self): + return self._async_client.get_stats() + + def get_connection_port (self): + return self.comm_link.port + + def disconnect(self): + return self.comm_link.disconnect() + def ping(self): return self.transmit("ping") @@ -77,24 +170,45 @@ class CTRexStatelessClient(object): def get_port_count(self): return self.system_info.get("port_count") + def get_port_ids(self, as_str=False): + port_ids = range(self.get_port_count()) + if as_str: + return " ".join(str(p) for p in port_ids) + else: + return port_ids + + def sync_user(self, sync_streams=False): + return self.transmit("sync_user", {"user": self.user, "sync_streams": sync_streams}) + + def get_acquired_ports(self): + return self._conn_handler.keys() + + def get_active_ports(self): + return list(self._active_ports) + + def set_verbose(self, mode): + self.comm_link.set_verbose(mode) + self.verbose = mode + def acquire(self, port_id, force=False): if not self._is_ports_valid(port_id): raise ValueError("Provided illegal port id input") if isinstance(port_id, list) or isinstance(port_id, set): # handle as batch mode port_ids = set(port_id) # convert to set to avoid duplications - commands = [self.RpcCmdData("acquire", {"port_id": p_id, "user": self.user, "force": force}) + commands = [RpcCmdData("acquire", {"port_id": p_id, "user": self.user, "force": force}) for p_id in port_ids] rc, resp_list = self.transmit_batch(commands) if rc: - self._process_batch_result(commands, resp_list, self._handle_acquire_response) + return self._process_batch_result(commands, resp_list, self._handle_acquire_response) else: params = {"port_id": port_id, "user": self.user, "force": force} - command = self.RpcCmdData("acquire", params) - self._handle_acquire_response(command, self.transmit(command.method, command.params)) - return self._conn_handler.get(port_id) + command = RpcCmdData("acquire", params) + return self._handle_acquire_response(command, + self.transmit(command.method, command.params), + self.default_success_test) @force_status(owned=True) def release(self, port_id=None): @@ -103,18 +217,20 @@ class CTRexStatelessClient(object): if isinstance(port_id, list) or isinstance(port_id, set): # handle as batch mode port_ids = set(port_id) # convert to set to avoid duplications - commands = [self.RpcCmdData("release", {"handler": self._conn_handler.get(p_id), "port_id": p_id}) + commands = [RpcCmdData("release", {"handler": self._conn_handler.get(p_id), "port_id": p_id}) for p_id in port_ids] rc, resp_list = self.transmit_batch(commands) if rc: - self._process_batch_result(commands, resp_list, self._handle_release_response) + return self._process_batch_result(commands, resp_list, self._handle_release_response, + success_test=self.ack_success_test) else: self._conn_handler.pop(port_id) params = {"handler": self._conn_handler.get(port_id), "port_id": port_id} - command = self.RpcCmdData("release", params) - self._handle_release_response(command, self.transmit(command.method, command.params)) - return + command = RpcCmdData("release", params) + return self._handle_release_response(command, + self.transmit(command.method, command.params), + self.ack_success_test) @force_status(owned=True) def add_stream(self, stream_id, stream_obj, port_id=None): @@ -128,6 +244,27 @@ class CTRexStatelessClient(object): return self.transmit("add_stream", params) @force_status(owned=True) + def add_stream_pack(self, port_id=None, *stream_packs): + if not self._is_ports_valid(port_id): + raise ValueError("Provided illegal port id input") + + # since almost every run contains more than one transaction with server, handle all as batch mode + port_ids = set(port_id) # convert to set to avoid duplications + commands = [] + for stream_pack in stream_packs: + commands.extend([RpcCmdData("add_stream", {"port_id": p_id, + "handler": self._conn_handler.get(p_id), + "stream_id": stream_pack.stream_id, + "stream": stream_pack.stream} + ) + for p_id in port_ids] + ) + res_ok, resp_list = self.transmit_batch(commands) + if res_ok: + return self._process_batch_result(commands, resp_list, self._handle_add_stream_response, + success_test=self.ack_success_test) + + @force_status(owned=True) def remove_stream(self, stream_id, port_id=None): if not self._is_ports_valid(port_id): raise ValueError("Provided illegal port id input") @@ -136,7 +273,39 @@ class CTRexStatelessClient(object): "stream_id": stream_id} return self.transmit("remove_stream", params) - @force_status(owned=True, active_and_owned=True) + @force_status(owned=True) + def remove_all_streams(self, port_id=None): + if not self._is_ports_valid(port_id): + raise ValueError("Provided illegal port id input") + if isinstance(port_id, list) or isinstance(port_id, set): + # handle as batch mode + port_ids = set(port_id) # convert to set to avoid duplications + commands = [RpcCmdData("remove_all_streams", {"port_id": p_id, "handler": self._conn_handler.get(p_id)}) + for p_id in port_ids] + rc, resp_list = self.transmit_batch(commands) + if rc: + return self._process_batch_result(commands, resp_list, self._handle_remove_streams_response, + success_test=self.ack_success_test) + else: + params = {"port_id": port_id, + "handler": self._conn_handler.get(port_id)} + command = RpcCmdData("remove_all_streams", params) + return self._handle_remove_streams_response(command, + self.transmit(command.method, command.params), + self.ack_success_test) + pass + + + @force_status(owned=True)#, active_and_owned=True) + def get_all_streams(self, port_id, get_pkt = False): + if not self._is_ports_valid(port_id): + raise ValueError("Provided illegal port id input") + params = {"handler": self._conn_handler.get(port_id), + "port_id": port_id, + "get_pkt": get_pkt} + return self.transmit("get_all_streams", params) + + @force_status(owned=True)#, active_and_owned=True) def get_stream_id_list(self, port_id=None): if not self._is_ports_valid(port_id): raise ValueError("Provided illegal port id input") @@ -145,32 +314,38 @@ class CTRexStatelessClient(object): return self.transmit("get_stream_list", params) @force_status(owned=True, active_and_owned=True) - def get_stream(self, stream_id, port_id=None): + def get_stream(self, stream_id, port_id, get_pkt = False): if not self._is_ports_valid(port_id): raise ValueError("Provided illegal port id input") params = {"handler": self._conn_handler.get(port_id), "port_id": port_id, - "stream_id": stream_id} + "stream_id": stream_id, + "get_pkt": get_pkt} return self.transmit("get_stream_list", params) - @force_status(owned=True) - def start_traffic(self, port_id=None): + @acquired + def start_traffic(self, multiplier, port_id=None): if not self._is_ports_valid(port_id): raise ValueError("Provided illegal port id input") if isinstance(port_id, list) or isinstance(port_id, set): # handle as batch mode port_ids = set(port_id) # convert to set to avoid duplications - commands = [self.RpcCmdData("start_traffic", {"handler": self._conn_handler.get(p_id), "port_id": p_id}) + commands = [RpcCmdData("start_traffic", {"handler": self._conn_handler.get(p_id), + "port_id": p_id, + "mul": multiplier}) for p_id in port_ids] rc, resp_list = self.transmit_batch(commands) if rc: - self._process_batch_result(commands, resp_list, self._handle_start_traffic_response) + return self._process_batch_result(commands, resp_list, self._handle_start_traffic_response, + success_test=self.ack_success_test) else: params = {"handler": self._conn_handler.get(port_id), - "port_id": port_id} - command = self.RpcCmdData("start_traffic", params) - self._handle_start_traffic_response(command, self.transmit(command.method, command.params)) - return + "port_id": port_id, + "mul": multiplier} + command = RpcCmdData("start_traffic", params) + return self._handle_start_traffic_response(command, + self.transmit(command.method, command.params), + self.ack_success_test) @force_status(owned=False, active_and_owned=True) def stop_traffic(self, port_id=None): @@ -179,22 +354,24 @@ class CTRexStatelessClient(object): if isinstance(port_id, list) or isinstance(port_id, set): # handle as batch mode port_ids = set(port_id) # convert to set to avoid duplications - commands = [self.RpcCmdData("stop_traffic", {"handler": self._conn_handler.get(p_id), "port_id": p_id}) + commands = [RpcCmdData("stop_traffic", {"handler": self._conn_handler.get(p_id), "port_id": p_id}) for p_id in port_ids] rc, resp_list = self.transmit_batch(commands) if rc: - self._process_batch_result(commands, resp_list, self._handle_stop_traffic_response) + return self._process_batch_result(commands, resp_list, self._handle_stop_traffic_response, + success_test=self.ack_success_test) else: params = {"handler": self._conn_handler.get(port_id), "port_id": port_id} - command = self.RpcCmdData("stop_traffic", params) - self._handle_start_traffic_response(command, self.transmit(command.method, command.params)) - return + command = RpcCmdData("stop_traffic", params) + return self._handle_start_traffic_response(command, + self.transmit(command.method, command.params), + self.ack_success_test) - def get_global_stats(self): - command = self.RpcCmdData("get_global_stats", {}) - return self._handle_get_global_stats_response(command, self.transmit(command.method, command.params)) - # return self.transmit("get_global_stats") +# def get_global_stats(self): +# command = RpcCmdData("get_global_stats", {}) +# return self._handle_get_global_stats_response(command, self.transmit(command.method, command.params)) +# # return self.transmit("get_global_stats") @force_status(owned=True, active_and_owned=True) def get_port_stats(self, port_id=None): @@ -203,7 +380,7 @@ class CTRexStatelessClient(object): if isinstance(port_id, list) or isinstance(port_id, set): # handle as batch mode port_ids = set(port_id) # convert to set to avoid duplications - commands = [self.RpcCmdData("get_port_stats", {"handler": self._conn_handler.get(p_id), "port_id": p_id}) + commands = [RpcCmdData("get_port_stats", {"handler": self._conn_handler.get(p_id), "port_id": p_id}) for p_id in port_ids] rc, resp_list = self.transmit_batch(commands) if rc: @@ -211,7 +388,7 @@ class CTRexStatelessClient(object): else: params = {"handler": self._conn_handler.get(port_id), "port_id": port_id} - command = self.RpcCmdData("get_port_stats", params) + command = RpcCmdData("get_port_stats", params) return self._handle_get_port_stats_response(command, self.transmit(command.method, command.params)) @force_status(owned=True, active_and_owned=True) @@ -221,7 +398,7 @@ class CTRexStatelessClient(object): if isinstance(port_id, list) or isinstance(port_id, set): # handle as batch mode port_ids = set(port_id) # convert to set to avoid duplications - commands = [self.RpcCmdData("get_stream_stats", {"handler": self._conn_handler.get(p_id), "port_id": p_id}) + commands = [RpcCmdData("get_stream_stats", {"handler": self._conn_handler.get(p_id), "port_id": p_id}) for p_id in port_ids] rc, resp_list = self.transmit_batch(commands) if rc: @@ -229,15 +406,36 @@ class CTRexStatelessClient(object): else: params = {"handler": self._conn_handler.get(port_id), "port_id": port_id} - command = self.RpcCmdData("get_stream_stats", params) + command = RpcCmdData("get_stream_stats", params) return self._handle_get_stream_stats_response(command, self.transmit(command.method, command.params)) # ----- internal methods ----- # + def _init_sync(self): + # get server version and system info + err = False + if self.server_version == "Unknown" or self.system_info == "Unknown": + self.disconnect() + return False, self.__err_log + # sync with previous session + res_ok, port_info = self.sync_user() + if not res_ok: + self.disconnect() + return False, port_info + else: + # handle sync data + for port in port_info: + self._conn_handler[port.get("port_id")] = port.get("handler") + if port.get("state") == "transmitting": + # port is active + self._active_ports.add(port.get("port_id")) + return True, "" + + def transmit(self, method_name, params={}): - return self.tx_link.transmit(method_name, params) + return self.comm_link.transmit(method_name, params) def transmit_batch(self, batch_list): - return self.tx_link.transmit_batch(batch_list) + return self.comm_link.transmit_batch(batch_list) @staticmethod def _object_decoder(obj_type, obj_data): @@ -258,36 +456,86 @@ class CTRexStatelessClient(object): else: return False + @staticmethod + def ack_success_test(result_obj): + if result_obj.success and result_obj.data == "ACK": + return True + else: + return False + + # ----- handler internal methods ----- # - def _handle_acquire_response(self, request, response): - if response.success: - self._conn_handler[request.get("port_id")] = response.data + def _handle_general_response(self, request, response, msg, success_test=None): + port_id = request.params.get("port_id") + if not success_test: + success_test = self.default_success_test + if success_test(response): + self._conn_handler[port_id] = response.data + return RpcResponseStatus(True, port_id, msg) + else: + return RpcResponseStatus(False, port_id, response.data) - def _handle_release_response(self, request, response): - if response.success: - del self._conn_handler[request.get("port_id")] - def _handle_start_traffic_response(self, request, response): - if response.success: - self._active_ports.add(request.get("port_id")) + def _handle_acquire_response(self, request, response, success_test): + port_id = request.params.get("port_id") + if success_test(response): + self._conn_handler[port_id] = response.data + return RpcResponseStatus(True, port_id, "Acquired") + else: + return RpcResponseStatus(False, port_id, response.data) - def _handle_stop_traffic_response(self, request, response): - if response.success: - self._active_ports.remove(request.get("port_id")) + def _handle_add_stream_response(self, request, response, success_test): + port_id = request.params.get("port_id") + stream_id = request.params.get("stream_id") + if success_test(response): + return RpcResponseStatus(True, port_id, "Stream {0} added".format(stream_id)) + else: + return RpcResponseStatus(False, port_id, response.data) + + def _handle_remove_streams_response(self, request, response, success_test): + port_id = request.params.get("port_id") + if success_test(response): + return RpcResponseStatus(True, port_id, "Removed") + else: + return RpcResponseStatus(False, port_id, response.data) - def _handle_get_global_stats_response(self, request, response): + def _handle_release_response(self, request, response, success_test): + port_id = request.params.get("port_id") + if success_test(response): + del self._conn_handler[port_id] + return RpcResponseStatus(True, port_id, "Released") + else: + return RpcResponseStatus(False, port_id, response.data) + + def _handle_start_traffic_response(self, request, response, success_test): + port_id = request.params.get("port_id") + if success_test(response): + self._active_ports.add(port_id) + return RpcResponseStatus(True, port_id, "Traffic started") + else: + return RpcResponseStatus(False, port_id, response.data) + + def _handle_stop_traffic_response(self, request, response, success_test): + port_id = request.params.get("port_id") + if success_test(response): + self._active_ports.remove(port_id) + return RpcResponseStatus(True, port_id, "Traffic stopped") + else: + return RpcResponseStatus(False, port_id, response.data) + + def _handle_get_global_stats_response(self, request, response, success_test): if response.success: return CGlobalStats(**response.success) else: return False - def _handle_get_port_stats_response(self, request, response): + def _handle_get_port_stats_response(self, request, response, success_test): if response.success: return CPortStats(**response.success) else: return False - def _handle_get_stream_stats_response(self, request, response): + def _handle_get_stream_stats_response(self, request, response, success_test): if response.success: return CStreamStats(**response.success) else: @@ -298,32 +546,58 @@ class CTRexStatelessClient(object): # check each item of the sequence return all([self._is_ports_valid(port) for port in port_id]) - elif (isinstance(port_id, int)) and (port_id > 0) and (port_id <= self.get_port_count()): + elif (isinstance(port_id, int)) and (port_id >= 0) and (port_id <= self.get_port_count()): return True else: return False def _process_batch_result(self, req_list, resp_list, handler_func=None, success_test=default_success_test): + res_ok = True + responses = [] + if isinstance(success_test, staticmethod): + success_test = success_test.__func__ for i, response in enumerate(resp_list): - # testing each result with success test so that a conclusion report could be deployed in future. - if success_test(response): - # run handler method with its params - handler_func(req_list[i], response) - else: - continue # TODO: mark in this case somehow the bad result + # run handler method with its params + processed_response = handler_func(req_list[i], response, success_test) + responses.append(processed_response) + if not processed_response.success: + res_ok = False + # else: + # res_ok = False # TODO: mark in this case somehow the bad result + # print res_ok + # print responses + return res_ok, responses # ------ private classes ------ # - class CTxLink(object): + class CCommLink(object): """describes the connectivity of the stateless client method""" def __init__(self, server="localhost", port=5050, virtual=False): - super(CTRexStatelessClient.CTxLink, self).__init__() + super(CTRexStatelessClient.CCommLink, self).__init__() self.virtual = virtual self.server = server self.port = port + self.verbose = False self.rpc_link = JsonRpcClient(self.server, self.port) + + @property + def is_connected(self): + if not self.virtual: + return self.rpc_link.connected + else: + return True + + def set_verbose(self, mode): + self.verbose = mode + return self.rpc_link.set_verbose(mode) + + def connect(self): + if not self.virtual: + return self.rpc_link.connect() + + def disconnect(self): if not self.virtual: - self.rpc_link.connect() + return self.rpc_link.disconnect() def transmit(self, method_name, params={}): if self.virtual: @@ -352,144 +626,5 @@ class CTRexStatelessClient(object): port=self.port) -class CStream(object): - """docstring for CStream""" - DEFAULTS = {"rx_stats": CRxStats, - "mode": CTxMode, - "isg": 5.0, - "next_stream": -1, - "self_start": True, - "enabled": True} - - def __init__(self, **kwargs): - super(CStream, self).__init__() - for k, v in kwargs.items(): - setattr(self, k, v) - # set default values to unset attributes, according to DEFAULTS dict - set_keys = set(kwargs.keys()) - keys_to_set = [x - for x in self.DEFAULTS - if x not in set_keys] - for key in keys_to_set: - default = self.DEFAULTS.get(key) - if type(default) == type: - setattr(self, key, default()) - else: - setattr(self, key, default) - - @property - def packet(self): - return self._packet - - @packet.setter - def packet(self, packet_obj): - assert isinstance(packet_obj, CTRexPktBuilder) - self._packet = packet_obj - - @property - def enabled(self): - return self._enabled - - @enabled.setter - def enabled(self, bool_value): - self._enabled = bool(bool_value) - - @property - def self_start(self): - return self._self_start - - @self_start.setter - def self_start(self, bool_value): - self._self_start = bool(bool_value) - - @property - def next_stream(self): - return self._next_stream - - @next_stream.setter - def next_stream(self, value): - self._next_stream = int(value) - - def dump(self): - pass - return {"enabled": self.enabled, - "self_start": self.self_start, - "isg": self.isg, - "next_stream": self.next_stream, - "packet": self.packet.dump_pkt(), - "mode": self.mode.dump(), - "vm": self.packet.get_vm_data(), - "rx_stats": self.rx_stats.dump()} - -class CRxStats(object): - - def __init__(self, enabled=False, seq_enabled=False, latency_enabled=False): - self._rx_dict = {"enabled": enabled, - "seq_enabled": seq_enabled, - "latency_enabled": latency_enabled} - - @property - def enabled(self): - return self._rx_dict.get("enabled") - - @enabled.setter - def enabled(self, bool_value): - self._rx_dict['enabled'] = bool(bool_value) - - @property - def seq_enabled(self): - return self._rx_dict.get("seq_enabled") - - @seq_enabled.setter - def seq_enabled(self, bool_value): - self._rx_dict['seq_enabled'] = bool(bool_value) - - @property - def latency_enabled(self): - return self._rx_dict.get("latency_enabled") - - @latency_enabled.setter - def latency_enabled(self, bool_value): - self._rx_dict['latency_enabled'] = bool(bool_value) - - def dump(self): - return {k: v - for k, v in self._rx_dict.items() - if v - } - - -class CTxMode(object): - """docstring for CTxMode""" - def __init__(self, tx_mode, pps): - super(CTxMode, self).__init__() - if tx_mode not in ["continuous", "single_burst", "multi_burst"]: - raise ValueError("Unknown TX mode ('{0}')has been initialized.".format(tx_mode)) - self._tx_mode = tx_mode - self._fields = {'pps': float(pps)} - if tx_mode == "single_burst": - self._fields['total_pkts'] = 0 - elif tx_mode == "multi_burst": - self._fields['pkts_per_burst'] = 0 - self._fields['ibg'] = 0.0 - self._fields['count'] = 0 - else: - pass - - def set_tx_mode_attr(self, attr, val): - if attr in self._fields: - self._fields[attr] = type(self._fields.get(attr))(val) - else: - raise ValueError("The provided attribute ('{0}') is not a legal attribute in selected TX mode ('{1}')". - format(attr, self._tx_mode)) - - def dump(self): - dump = {"type": self._tx_mode} - dump.update({k: v - for k, v in self._fields.items() - }) - return dump - - if __name__ == "__main__": pass diff --git a/scripts/automation/trex_control_plane/client_utils/general_utils.py b/scripts/automation/trex_control_plane/client_utils/general_utils.py index 5488b9dd..69ad14b2 100755 --- a/scripts/automation/trex_control_plane/client_utils/general_utils.py +++ b/scripts/automation/trex_control_plane/client_utils/general_utils.py @@ -24,7 +24,7 @@ def user_input(): def get_current_user(): if pwd: - return pwd.getpwuid( os.geteuid() ).pw_name + return pwd.getpwuid(os.geteuid()).pw_name else: return getpass.getuser() @@ -75,6 +75,22 @@ def random_id_gen(length=8): return_id += random.choice(id_chars) yield return_id +def id_count_gen(): + """ + A generator for creating an increasing id for objects, starting from 0 + + :parameters: + None + + :return: + an id (unsigned int) with each next() request. + """ + return_id = 0 + while True: + yield return_id + return_id += 1 + + if __name__ == "__main__": pass 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 ed14e6f8..58491aba 100755 --- a/scripts/automation/trex_control_plane/client_utils/jsonrpc_client.py +++ b/scripts/automation/trex_control_plane/client_utils/jsonrpc_client.py @@ -6,6 +6,9 @@ import json import general_utils import re from time import sleep +from collections import namedtuple + +CmdResponse = namedtuple('CmdResponse', ['success', 'data']) class bcolors: BLUE = '\033[94m' @@ -23,12 +26,12 @@ class BatchMessage(object): self.rpc_client = rpc_client self.batch_list = [] - def add (self, method_name, params = {}): + def add (self, method_name, params={}): id, msg = self.rpc_client.create_jsonrpc_v2(method_name, params, encode = False) self.batch_list.append(msg) - def invoke (self, block = False): + def invoke(self, block = False): if not self.rpc_client.connected: return False, "Not connected to server" @@ -36,9 +39,9 @@ class BatchMessage(object): rc, resp_list = self.rpc_client.send_raw_msg(msg, block = False) if len(self.batch_list) == 1: - return True, [(rc, resp_list)] + return CmdResponse(True, [CmdResponse(rc, resp_list)]) else: - return rc, resp_list + return CmdResponse(rc, resp_list) # JSON RPC v2.0 client @@ -47,7 +50,7 @@ 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 @@ -73,7 +76,7 @@ class JsonRpcClient(object): # float pretty_str = re.sub(r'([ ]*:[ ]+)(\-?[1-9][0-9]*\.[0-9]+)',r'\1{0}\2{1}'.format(bcolors.MAGENTA, bcolors.ENDC), pretty_str) # strings - + pretty_str = re.sub(r'([ ]*:[ ]+)("[^"]*")',r'\1{0}\2{1}'.format(bcolors.RED, bcolors.ENDC), pretty_str) pretty_str = re.sub(r"('[^']*')", r'{0}\1{1}'.format(bcolors.MAGENTA, bcolors.RED), pretty_str) except : @@ -115,7 +118,7 @@ class JsonRpcClient(object): return self.send_raw_msg(msg, block) - + # low level send of string message def send_raw_msg (self, msg, block = False): self.verbose_msg("Sending Request To Server:\n\n" + self.pretty_json(msg) + "\n") @@ -127,7 +130,7 @@ class JsonRpcClient(object): self.socket.send(msg, flags = zmq.NOBLOCK) except zmq.error.ZMQError as e: self.disconnect() - return False, "Failed To Get Send Message" + return CmdResponse(False, "Failed To Get Send Message") got_response = False @@ -145,7 +148,7 @@ class JsonRpcClient(object): if not got_response: self.disconnect() - return False, "Failed To Get Server Response" + return CmdResponse(False, "Failed To Get Server Response") self.verbose_msg("Server Response:\n\n" + self.pretty_json(response) + "\n") @@ -159,13 +162,13 @@ class JsonRpcClient(object): for single_response in response_json: rc, msg = self.process_single_response(single_response) - rc_list.append( (rc, msg) ) + rc_list.append( CmdResponse(rc, msg) ) - return True, rc_list + return CmdResponse(True, rc_list) else: rc, msg = self.process_single_response(response_json) - return rc, msg + return CmdResponse(rc, msg) def process_single_response (self, response_json): @@ -182,7 +185,7 @@ class JsonRpcClient(object): # if no error there should be a result if ("result" not in response_json): - return False, "Malfromed Response ({0})".format(str(response)) + return False, "Malformed Response ({0})".format(str(response)) return True, response_json["result"] @@ -200,7 +203,7 @@ class JsonRpcClient(object): else: return False, "Not connected to server" - def connect(self, server = None, port = None): + def connect(self, server=None, port=None): if self.connected: self.disconnect() @@ -511,3 +514,6 @@ class TrexStatelessClient(JsonRpcClient): return True, resp_list # return self.invoke_rpc_method('add_stream', params = params) + +if __name__ == "__main__": + pass
\ No newline at end of file diff --git a/scripts/automation/trex_control_plane/common/text_opts.py b/scripts/automation/trex_control_plane/common/text_opts.py new file mode 100755 index 00000000..06c2c056 --- /dev/null +++ b/scripts/automation/trex_control_plane/common/text_opts.py @@ -0,0 +1,100 @@ +import json +import re + +TEXT_CODES = {'bold': {'start': '\x1b[1m', + 'end': '\x1b[22m'}, + 'cyan': {'start': '\x1b[36m', + 'end': '\x1b[39m'}, + 'blue': {'start': '\x1b[34m', + 'end': '\x1b[39m'}, + 'red': {'start': '\x1b[31m', + 'end': '\x1b[39m'}, + 'magenta': {'start': '\x1b[35m', + 'end': '\x1b[39m'}, + 'green': {'start': '\x1b[32m', + 'end': '\x1b[39m'}, + 'yellow': {'start': '\x1b[33m', + 'end': '\x1b[39m'}, + 'underline': {'start': '\x1b[4m', + 'end': '\x1b[24m'}} + + +def bold(text): + return text_attribute(text, 'bold') + + +def cyan(text): + return text_attribute(text, 'cyan') + + +def blue(text): + return text_attribute(text, 'blue') + + +def red(text): + return text_attribute(text, 'red') + + +def magenta(text): + return text_attribute(text, 'magenta') + + +def green(text): + return text_attribute(text, 'green') + +def yellow(text): + return text_attribute(text, 'yellow') + +def underline(text): + return text_attribute(text, 'underline') + + +def text_attribute(text, attribute): + return "{start}{txt}{stop}".format(start=TEXT_CODES[attribute]['start'], + txt=text, + stop=TEXT_CODES[attribute]['end']) + + +FUNC_DICT = {'blue': blue, + 'bold': bold, + 'green': green, + 'yellow': yellow, + 'cyan': cyan, + 'magenta': magenta, + 'underline': underline, + 'red': red} + + +def format_text(text, *args): + return_string = text + for i in args: + func = FUNC_DICT.get(i) + if func: + return_string = func(return_string) + return return_string + +# pretty print for JSON +def pretty_json (json_str, use_colors = True): + pretty_str = json.dumps(json.loads(json_str), indent = 4, separators=(',', ': '), sort_keys = True) + + if not use_colors: + return pretty_str + + try: + # int numbers + pretty_str = re.sub(r'([ ]*:[ ]+)(\-?[1-9][0-9]*[^.])',r'\1{0}'.format(blue(r'\2')), pretty_str) + # float + pretty_str = re.sub(r'([ ]*:[ ]+)(\-?[1-9][0-9]*\.[0-9]+)',r'\1{0}'.format(magenta(r'\2')), pretty_str) + # # strings + # + pretty_str = re.sub(r'([ ]*:[ ]+)("[^"]*")',r'\1{0}'.format(red(r'\2')), pretty_str) + pretty_str = re.sub(r"('[^']*')", r'{0}\1{1}'.format(TEXT_CODES['magenta']['start'], + TEXT_CODES['red']['start']), pretty_str) + except : + pass + + return pretty_str + + +if __name__ == "__main__": + pass diff --git a/scripts/automation/trex_control_plane/common/trex_streams.py b/scripts/automation/trex_control_plane/common/trex_streams.py index 783f2769..bb4c72ca 100755 --- a/scripts/automation/trex_control_plane/common/trex_streams.py +++ b/scripts/automation/trex_control_plane/common/trex_streams.py @@ -23,7 +23,7 @@ class CStreamList(object): if name in self.streams_list: raise NameError("A stream with this name already exists on this list.") self.streams_list[name]=stream_obj - return + return name def remove_stream(self, name): popped = self.streams_list.pop(name) @@ -48,6 +48,7 @@ class CStreamList(object): self.streams_list.clear() streams_data = load_yaml_to_obj(file_path) assert isinstance(streams_data, list) + new_streams_data = [] for stream in streams_data: stream_name = stream.get("name") raw_stream = stream.get("stream") @@ -58,10 +59,11 @@ class CStreamList(object): new_stream_data = self.yaml_loader.validate_yaml(raw_stream, "stream", multiplier= multiplier) + new_streams_data.append(new_stream_data) new_stream_obj = CStream() new_stream_obj.load_data(**new_stream_data) self.append_stream(stream_name, new_stream_obj) - return new_stream_data + return new_streams_data def compile_streams(self): # first, assign an id to each stream @@ -156,7 +158,6 @@ class CStream(object): """docstring for CStream""" FIELDS = ["enabled", "self_start", "next_stream_id", "isg", "mode", "rx_stats", "packet", "vm"] - # COMPILE_FIELDS = ["enabled", "self_start", "next_stream_id", "isg", "mode", "rx_stats", "packet", "vm"] def __init__(self): self.is_loaded = False @@ -183,6 +184,7 @@ class CStream(object): if isinstance(kwargs[k], CTRexPktBuilder): if "vm" not in kwargs: self.load_packet_obj(kwargs[k]) + break # vm field check is skipped else: raise ValueError("When providing packet object with a CTRexPktBuilder, vm parameter " "should not be supplied") @@ -226,8 +228,7 @@ class CStream(object): return - def dump(self, compilation=False): - # fields = CStream.COMPILE_FIELDS if compilation else CStream.FIELDS + def dump(self): if self.is_loaded: dump = {} for key in CStream.FIELDS: @@ -239,10 +240,6 @@ class CStream(object): else: raise RuntimeError("CStream object isn't loaded with data. Use 'load_data' method.") - def dump_compiled(self): - return self.dump(compilation=True) - - if __name__ == "__main__": pass diff --git a/scripts/automation/trex_control_plane/console/parsing_opts.py b/scripts/automation/trex_control_plane/console/parsing_opts.py new file mode 100755 index 00000000..c94a7461 --- /dev/null +++ b/scripts/automation/trex_control_plane/console/parsing_opts.py @@ -0,0 +1,103 @@ +import argparse +from collections import namedtuple +import sys + +ArgumentPack = namedtuple('ArgumentPack', ['name_or_flags', 'options']) +ArgumentGroup = namedtuple('ArgumentGroup', ['type', 'args', 'options']) + + +# list of available parsing options +MULTIPLIER = 1 +PORT_LIST = 2 +ALL_PORTS = 3 +PORT_LIST_WITH_ALL = 4 +FILE_PATH = 5 +FILE_FROM_DB = 6 +STREAM_FROM_PATH_OR_FILE = 7 + +# list of ArgumentGroup types +MUTEX = 1 + + + + +OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'], + {'help': "Set multiplier for stream", 'dest': "mult", 'type': float}), + PORT_LIST: ArgumentPack(['--port'], + {"nargs": '+', + # "action": "store_" + 'help': "A list of ports on which to apply the command", + 'default': []}), + ALL_PORTS: ArgumentPack(['-a'], + {"action": "store_true", + "dest": "all", + 'help': "Set this flag to apply the command on all available ports"}), + + FILE_PATH: ArgumentPack(['-f'], + {'help': "File path to YAML file that describes a stream pack"}), + FILE_FROM_DB: ArgumentPack(['--db'], + {'help': "A stream pack which already loaded into console cache."}), + # advanced options + PORT_LIST_WITH_ALL: ArgumentGroup(MUTEX, [PORT_LIST, + ALL_PORTS], + {'required': True}), + STREAM_FROM_PATH_OR_FILE: ArgumentGroup(MUTEX, [FILE_PATH, + FILE_FROM_DB], + {'required': True}) + } + + +class CCmdArgParser(argparse.ArgumentParser): + + def __init__(self, *args, **kwargs): + super(CCmdArgParser, self).__init__(*args, **kwargs) + pass + + # def error(self, message): + # try: + # super(CCmdArgParser, self).error(message) # this will trigger system exit! + # except SystemExit: + # return -1 + # + # # self.print_usage(sys.stderr) + # # print ('%s: error: %s\n') % (self.prog, message) + # # self.print_help() + # return + + def exit(self, status=0, message=None): + try: + super(CCmdArgParser, self).exit(status, message) # this will trigger system exit! + except SystemExit: + return -1 + return + +def gen_parser(op_name, description, *args): + parser = CCmdArgParser(prog=op_name, conflict_handler='resolve', + # add_help=False, + description=description) + for param in args: + try: + argument = OPTIONS_DB[param] + if isinstance(argument, ArgumentGroup): + if argument.type == MUTEX: + # handle as mutually exclusive group + group = parser.add_mutually_exclusive_group(**argument.options) + for sub_argument in argument.args: + group.add_argument(*OPTIONS_DB[sub_argument].name_or_flags, + **OPTIONS_DB[sub_argument].options) + else: + # ignore invalid objects + continue + elif isinstance(argument, ArgumentPack): + parser.add_argument(*argument.name_or_flags, + **argument.options) + else: + # ignore invalid objects + continue + except KeyError as e: + cause = e.args[0] + raise KeyError("The attribute '{0}' is missing as a field of the {1} option.\n".format(cause, param)) + return parser + +if __name__ == "__main__": + pass
\ No newline at end of file diff --git a/scripts/automation/trex_control_plane/console/trex_console.py b/scripts/automation/trex_control_plane/console/trex_console.py index a9ac040b..a2c738ab 100755 --- a/scripts/automation/trex_control_plane/console/trex_console.py +++ b/scripts/automation/trex_control_plane/console/trex_console.py @@ -17,6 +17,7 @@ See the License for the specific language governing permissions and limitations under the License. """ + import cmd import json import ast @@ -28,18 +29,20 @@ import sys import tty, termios import trex_root_path from common.trex_streams import * - - -from client_utils.jsonrpc_client import TrexStatelessClient +from client.trex_stateless_client import CTRexStatelessClient +from common.text_opts import * +from client_utils.general_utils import user_input, get_current_user +import parsing_opts import trex_status from collections import namedtuple +__version__ = "1.0" + LoadedStreamList = namedtuple('LoadedStreamList', ['loaded', 'compiled']) -# -def readch (choices = []): - +def readch(choices=[]): + fd = sys.stdin.fileno() old_settings = termios.tcgetattr(fd) try: @@ -55,22 +58,49 @@ def readch (choices = []): return None -class YesNoMenu(object): +class ConfirmMenu(object): def __init__ (self, caption): - self.caption = caption + self.caption = "{cap} [confirm] : ".format(cap=caption) - def show (self): - print "{0}".format(self.caption) - sys.stdout.write("[Y/y/N/n] : ") - ch = readch(choices = ['y', 'Y', 'n', 'N']) - if ch == None: - return None - - print "\n" - if ch == 'y' or ch == 'Y': - return True + def show(self): + sys.stdout.write(self.caption) + input = user_input() + if input: + return False else: + # user hit Enter + return True + + +class CStreamsDB(object): + + def __init__(self): + self.stream_packs = {} + + def load_streams(self, name, LoadedStreamList_obj): + if name in self.stream_packs: return False + else: + self.stream_packs[name] = LoadedStreamList_obj + return True + + def remove_stream_packs(self, *names): + removed_streams = [] + for name in names: + removed = self.stream_packs.pop(name) + if removed: + removed_streams.append(name) + return removed_streams + + def clear(self): + self.stream_packs.clear() + + def get_loaded_streams_names(self): + return self.stream_packs.keys() + + def get_stream_pack(self, name): + return self.stream_packs.get(name) + # multi level cmd menu class CmdMenu(object): @@ -119,31 +149,33 @@ class AddStreamMenu(CmdMenu): self.add_menu('Please select ISG', ['d', 'e', 'f']) # main console object -class TrexConsole(cmd.Cmd): +class TRexConsole(cmd.Cmd): """Trex Console""" - - def __init__(self, rpc_client): + + def __init__(self, stateless_client, verbose): cmd.Cmd.__init__(self) - self.rpc_client = rpc_client + self.stateless_client = stateless_client self.do_connect("") - self.intro = "\n-=TRex Console V1.0=-\n" - self.intro += "\nType 'help' or '?' for supported actions\n" + self.intro = "\n-=TRex Console v{ver}=-\n".format(ver=__version__) + self.intro += "\nType 'help' or '?' for supported actions\n" self.verbose = False self.postcmd(False, "") self.user_streams = {} - + self.streams_db = CStreamsDB() + # a cool hack - i stole this function and added space def completenames(self, text, *ignored): dotext = 'do_'+text return [a[3:]+' ' for a in self.get_names() if a.startswith(dotext)] + # set verbose on / off def do_verbose (self, line): '''Shows or set verbose mode\n''' @@ -152,40 +184,41 @@ class TrexConsole(cmd.Cmd): elif line == "on": self.verbose = True - self.rpc_client.set_verbose(True) - print "\nverbose set to on\n" + self.stateless_client.set_verbose(True) + print green("\nverbose set to on\n") elif line == "off": self.verbose = False - self.rpc_client.set_verbose(False) - print "\nverbose set to off\n" + self.stateless_client.set_verbose(False) + print green("\nverbose set to off\n") else: - print "\nplease specify 'on' or 'off'\n" + print magenta("\nplease specify 'on' or 'off'\n") # query the server for registered commands def do_query_server(self, line): '''query the RPC server for supported remote commands\n''' - rc, msg = self.rpc_client.query_rpc_server() - if not rc: - print "\n*** " + msg + "\n" + res_ok, msg = self.stateless_client.get_supported_cmds() + if not res_ok: + print format_text("[FAILED]\n", 'red', 'bold') return - - print "\nRPC server supports the following commands: \n\n" + print "\nRPC server supports the following commands:\n" for func in msg: if func: print func - print "\n" + print '' + print format_text("[SUCCESS]\n", 'green', 'bold') + return def do_ping (self, line): '''Pings the RPC server\n''' print "\n-> Pinging RPC server" - rc, msg = self.rpc_client.ping_rpc_server() - if rc: - print "[SUCCESS]\n" + res_ok, msg = self.stateless_client.ping() + if res_ok: + print format_text("[SUCCESS]\n", 'green', 'bold') else: print "\n*** " + msg + "\n" return @@ -195,13 +228,21 @@ class TrexConsole(cmd.Cmd): self.do_acquire(line, True) + def complete_force_acquire(self, text, line, begidx, endidx): + return self.port_auto_complete(text, line, begidx, endidx, acquired=False) + + def extract_port_ids_from_line(self, line): + return {int(x) for x in line.split()} + + def extract_port_ids_from_list(self, port_list): + return {int(x) for x in port_list} + 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) + if (not port_id.isdigit()) or (int(port_id) < 0) or (int(port_id) >= self.stateless_client.get_port_count()): + print "Please provide a list of ports separated by spaces between 0 and {0}".format(self.stateless_client.get_port_count() - 1) return None port_list.add(int(port_id)) @@ -209,106 +250,122 @@ class TrexConsole(cmd.Cmd): port_list = list(port_list) else: - port_list = [i for i in xrange(0, self.rpc_client.get_port_count())] + port_list = [i for i in xrange(0, self.stateless_client.get_port_count())] return port_list - def do_acquire (self, line, force = False): + + def do_acquire(self, line, force=False): '''Acquire ports\n''' # make sure that the user wants to acquire all - if line == "": - ask = YesNoMenu('Do you want to acquire all ports ? ') + args = line.split() + if len(args) < 1: + print magenta("Please provide a list of ports separated by spaces, or specify 'all' to acquire all available ports") + return + + if args[0] == "all": + ask = ConfirmMenu('Are you sure you want to acquire all ports ? ') rc = ask.show() if rc == False: + print yellow("[ABORTED]\n") return - - 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''' - - if line: - port_list = self.parse_ports_from_line(line) + port_list = self.stateless_client.get_port_ids() else: - port_list = self.rpc_client.get_owned_ports() - - if not port_list: - return - - rc, resp_list = self.rpc_client.release_ports(port_list) - - - print "\n" - - for i, rc in enumerate(resp_list): - if rc[0]: - print "Port {0} - Released".format(port_list[i]) + port_list = self.extract_port_ids_from_line(line) + + # rc, resp_list = self.stateless_client.take_ownership(port_list, force) + try: + res_ok, log = self.stateless_client.acquire(port_list, force) + self.prompt_response(log) + if not res_ok: + print format_text("[FAILED]\n", 'red', 'bold') + return + print format_text("[SUCCESS]\n", 'green', 'bold') + except ValueError as e: + print magenta(str(e)) + print format_text("[FAILED]\n", 'red', 'bold') + + + def port_auto_complete(self, text, line, begidx, endidx, acquired=True, active=False): + if acquired: + if not active: + ret_list = [x + for x in map(str, self.stateless_client.get_acquired_ports()) + if x.startswith(text)] else: - print "Port {0} - Failed to release port, probably not owned by you or port is under traffic" - - print "\n" - - def do_get_port_stats (self, line): - '''Get ports stats\n''' + ret_list = [x + for x in map(str, self.stateless_client.get_active_ports()) + if x.startswith(text)] + else: + ret_list = [x + for x in map(str, self.stateless_client.get_port_ids()) + if x.startswith(text)] + ret_list.append("all") + return ret_list - port_list = self.parse_ports_from_line(line) - if not port_list: - return - rc, resp_list = self.rpc_client.get_port_stats(port_list) + def complete_acquire(self, text, line, begidx, endidx): + return self.port_auto_complete(text, line, begidx, endidx, acquired=False) - if not rc: - print "\n*** " + resp_list + "\n" - return + def do_release (self, line): + '''Release ports\n''' - 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]))) + # if line: + # port_list = self.parse_ports_from_line(line) + # else: + # port_list = self.stateless_client.get_owned_ports() + args = line.split() + if len(args) < 1: + print "Please provide a list of ports separated by spaces, or specify 'all' to acquire all available ports" + if args[0] == "all": + ask = ConfirmMenu('Are you sure you want to release all acquired ports? ') + rc = ask.show() + if rc == False: + print yellow("[ABORTED]\n") + return else: - print "\nPort {0} - ".format(i) + rc[1] + "\n" + port_list = self.stateless_client.get_acquired_ports() + else: + port_list = self.extract_port_ids_from_line(line) - print "\n" + try: + res_ok, log = self.stateless_client.release(port_list) + self.prompt_response(log) + if not res_ok: + print format_text("[FAILED]\n", 'red', 'bold') + return + print format_text("[SUCCESS]\n", 'green', 'bold') + except ValueError as e: + print magenta(str(e)) + print format_text("[FAILED]\n", 'red', 'bold') + return + def complete_release(self, text, line, begidx, endidx): + return self.port_auto_complete(text, line, begidx, endidx) def do_connect (self, line): '''Connects to the server\n''' if line == "": - rc, msg = self.rpc_client.connect() + res_ok, msg = self.stateless_client.connect() else: sp = line.split() if (len(sp) != 2): print "\n[usage] connect [server] [port] or without parameters\n" return - rc, msg = self.rpc_client.connect(sp[0], sp[1]) + res_ok, msg = self.stateless_client.connect(sp[0], sp[1]) - if rc: - print "[SUCCESS]\n" + if res_ok: + print format_text("[SUCCESS]\n", 'green', 'bold') else: print "\n*** " + msg + "\n" + print format_text("[FAILED]\n", 'red', 'bold') return - self.supported_rpc = self.rpc_client.get_supported_cmds() + self.supported_rpc = self.stateless_client.get_supported_cmds().data def do_rpc (self, line): '''Launches a RPC on the server\n''' @@ -341,22 +398,28 @@ class TrexConsole(cmd.Cmd): print "Example: rpc test_add {'x': 12, 'y': 17}\n" return - rc, msg = self.rpc_client.invoke_rpc_method(method, params) - if rc: - print "\nServer Response:\n\n" + self.rpc_client.pretty_json(json.dumps(msg)) + "\n" + res_ok, msg = self.stateless_client.transmit(method, params) + if res_ok: + print "\nServer Response:\n\n" + pretty_json(json.dumps(msg)) + "\n" else: print "\n*** " + msg + "\n" #print "Please try 'reconnect' to reconnect to server" def complete_rpc (self, text, line, begidx, endidx): - return [x for x in self.supported_rpc if x.startswith(text)] + return [x + for x in self.supported_rpc + if x.startswith(text)] def do_status (self, line): '''Shows a graphical console\n''' + if not self.stateless_client.is_connected(): + print "Not connected to server\n" + return + self.do_verbose('off') - trex_status.show_trex_status(self.rpc_client) + trex_status.show_trex_status(self.stateless_client) def do_quit(self, line): '''Exit the client\n''' @@ -364,22 +427,22 @@ class TrexConsole(cmd.Cmd): def do_disconnect (self, line): '''Disconnect from the server\n''' - if not self.rpc_client.is_connected(): + if not self.stateless_client.is_connected(): print "Not connected to server\n" return - rc, msg = self.rpc_client.disconnect() - if rc: - print "[SUCCESS]\n" + res_ok, msg = self.stateless_client.disconnect() + if res_ok: + print format_text("[SUCCESS]\n", 'green', 'bold') else: print msg + "\n" def do_whoami (self, line): '''Prints console user name\n''' - print "\n" + self.rpc_client.whoami() + "\n" - + print "\n" + self.stateless_client.user + "\n" + def postcmd(self, stop, line): - if self.rpc_client.is_connected(): + if self.stateless_client.is_connected(): self.prompt = "TRex > " else: self.supported_rpc = None @@ -390,47 +453,47 @@ class TrexConsole(cmd.Cmd): def default(self, line): print "'{0}' is an unrecognized command. type 'help' or '?' for a list\n".format(line) - def do_help (self, line): - '''Shows This Help Screen\n''' - if line: - try: - func = getattr(self, 'help_' + line) - except AttributeError: - try: - doc = getattr(self, 'do_' + line).__doc__ - if doc: - self.stdout.write("%s\n"%str(doc)) - return - except AttributeError: - pass - self.stdout.write("%s\n"%str(self.nohelp % (line,))) - return - func() - return - - print "\nSupported Console Commands:" - print "----------------------------\n" - - cmds = [x[3:] for x in self.get_names() if x.startswith("do_")] - for cmd in cmds: - if cmd == "EOF": - continue - - try: - doc = getattr(self, 'do_' + cmd).__doc__ - if doc: - help = str(doc) - else: - help = "*** Undocumented Function ***\n" - except AttributeError: - help = "*** Undocumented Function ***\n" - - print "{:<30} {:<30}".format(cmd + " - ", help) - - def do_load_stream_list(self, line): + # def do_help (self, line): + # '''Shows This Help Screen\n''' + # if line: + # try: + # func = getattr(self, 'help_' + line) + # except AttributeError: + # try: + # doc = getattr(self, 'do_' + line).__doc__ + # if doc: + # self.stdout.write("%s\n"%str(doc)) + # return + # except AttributeError: + # pass + # self.stdout.write("%s\n"%str(self.nohelp % (line,))) + # return + # func() + # return + # + # print "\nSupported Console Commands:" + # print "----------------------------\n" + # + # cmds = [x[3:] for x in self.get_names() if x.startswith("do_")] + # for cmd in cmds: + # if cmd == "EOF": + # continue + # + # try: + # doc = getattr(self, 'do_' + cmd).__doc__ + # if doc: + # help = str(doc) + # else: + # help = "*** Undocumented Function ***\n" + # except AttributeError: + # help = "*** Undocumented Function ***\n" + # + # print "{:<30} {:<30}".format(cmd + " - ", help) + + def do_stream_db_add(self, line): '''Loads a YAML stream list serialization into user console \n''' args = line.split() - if args >= 2: + if len(args) >= 2: name = args[0] yaml_path = args[1] try: @@ -439,23 +502,24 @@ class TrexConsole(cmd.Cmd): multiplier = 1 stream_list = CStreamList() loaded_obj = stream_list.load_yaml(yaml_path, multiplier) - # print self.rpc_client.pretty_json(json.dumps(loaded_obj)) - if name in self.user_streams: - print "Picked name already exist. Please pick another name." - else: - try: - compiled_streams = stream_list.compile_streams() - self.user_streams[name] = LoadedStreamList(loaded_obj, - [StreamPack(v.stream_id, v.stream.dump_compiled()) - for k, v in compiled_streams.items()]) - - print "Stream '{0}' loaded successfully".format(name) - except Exception as e: - raise + # print self.stateless_client.pretty_json(json.dumps(loaded_obj)) + try: + compiled_streams = stream_list.compile_streams() + res_ok = self.streams_db.load_streams(name, LoadedStreamList(loaded_obj, + [StreamPack(v.stream_id, v.stream.dump()) + for k, v in compiled_streams.items()])) + if res_ok: + print green("Stream pack '{0}' loaded and added successfully\n".format(name)) + else: + print magenta("Picked name already exist. Please pick another name.\n") + except Exception as e: + print "adding new stream failed due to the following error:\n", str(e) + print format_text("[FAILED]\n", 'red', 'bold') + return else: - print "please provide load name and YAML path, separated by space.\n" \ - "Optionally, you may provide a third argument to specify multiplier." + print magenta("please provide load name and YAML path, separated by space.\n" + "Optionally, you may provide a third argument to specify multiplier.\n") @staticmethod def tree_autocomplete(text): @@ -470,92 +534,271 @@ class TrexConsole(cmd.Cmd): if x.startswith(start_string)] - def complete_load_stream_list(self, text, line, begidx, endidx): + def complete_stream_db_add(self, text, line, begidx, endidx): arg_num = len(line.split()) - 1 if arg_num == 2: - return TrexConsole.tree_autocomplete(line.split()[-1]) + return TRexConsole.tree_autocomplete(line.split()[-1]) else: return [text] - def do_show_stream_list(self, line): + def do_stream_db_show(self, line): '''Shows the loaded stream list named [name] \n''' args = line.split() if args: list_name = args[0] try: - stream = self.user_streams[list_name] + stream = self.streams_db.get_stream_pack(list_name)#user_streams[list_name] if len(args) >= 2 and args[1] == "full": - print self.rpc_client.pretty_json(json.dumps(stream.compiled)) + print pretty_json(json.dumps(stream.compiled)) else: - print self.rpc_client.pretty_json(json.dumps(stream.loaded)) + print pretty_json(json.dumps(stream.loaded)) except KeyError as e: print "Unknown stream list name provided" else: - print "\nAvailable stream lists:\n{0}".format(', '.join([x - for x in self.user_streams.keys()])) + print "Available stream packs:\n{0}".format(', '.join(sorted(self.streams_db.get_loaded_streams_names()))) - def complete_show_stream_list(self, text, line, begidx, endidx): + def complete_stream_db_show(self, text, line, begidx, endidx): return [x - for x in self.user_streams.keys() + for x in self.streams_db.get_loaded_streams_names() if x.startswith(text)] + def do_stream_db_remove(self, line): + '''Removes a single loaded stream packs from loaded stream pack repository\n''' + args = line.split() + if args: + removed_streams = self.streams_db.remove_stream_packs(*args) + if removed_streams: + print green("The following stream packs were removed:") + print bold(", ".join(sorted(removed_streams))) + print format_text("[SUCCESS]\n", 'green', 'bold') + else: + print red("No streams were removed. Make sure to provide valid stream pack names.") + else: + print magenta("Please provide stream pack name(s), separated with spaces.") + + def do_stream_db_clear(self, line): + '''Clears all loaded stream packs from loaded stream pack repository\n''' + self.streams_db.clear() + print format_text("[SUCCESS]\n", 'green', 'bold') + + + def complete_stream_db_remove(self, text, line, begidx, endidx): + return [x + for x in self.streams_db.get_loaded_streams_names() + if x.startswith(text)] + + def do_attach(self, line): + '''Assign loaded stream pack into specified ports on TRex\n''' args = line.split() - if len(args) >= 1: + if len(args) >= 2: + stream_pack_name = args[0] + stream_list = self.streams_db.get_stream_pack(stream_pack_name) #user_streams[args[0]] + if not stream_list: + print "Provided stream list name '{0}' doesn't exists.".format(stream_pack_name) + print format_text("[FAILED]\n", 'red', 'bold') + return + if args[1] == "all": + ask = ConfirmMenu('Are you sure you want to release all acquired ports? ') + rc = ask.show() + if rc == False: + print yellow("[ABORTED]\n") + return + else: + port_list = self.stateless_client.get_acquired_ports() + else: + port_list = self.extract_port_ids_from_line(' '.join(args[1:])) + owned = set(self.stateless_client.get_acquired_ports()) try: - stream_list = self.user_streams[args[0]] - port_list = self.parse_ports_from_line(' '.join(args[1:])) - owned = set(self.rpc_client.get_owned_ports()) if set(port_list).issubset(owned): - rc, resp_list = self.rpc_client.add_stream(port_list, stream_list.compiled) - if not rc: - print "\n*** " + resp_list + "\n" + res_ok, log = self.stateless_client.add_stream_pack(port_list, *stream_list.compiled) + # res_ok, msg = self.stateless_client.add_stream(port_list, stream_list.compiled) + self.prompt_response(log) + if not res_ok: + print format_text("[FAILED]\n", 'red', 'bold') return + print format_text("[SUCCESS]\n", 'green', 'bold') + return else: - print "Not all desired ports are aquired.\n" \ + print "Not all desired ports are acquired.\n" \ "Acquired ports are: {acq}\n" \ "Requested ports: {req}\n" \ "Missing ports: {miss}".format(acq=list(owned), req=port_list, miss=list(set(port_list).difference(owned))) - except KeyError as e: - cause = e.args[0] - print "Provided stream list name '{0}' doesn't exists.".format(cause) + print format_text("[FAILED]\n", 'red', 'bold') + except ValueError as e: + print magenta(str(e)) + print format_text("[FAILED]\n", 'red', 'bold') + else: + print magenta("Please provide list name and ports to attach to, " + "or specify 'all' to attach all owned ports.\n") + + def complete_attach(self, text, line, begidx, endidx): + arg_num = len(line.split()) - 1 + if arg_num == 1: + # return optional streams packs + if line.endswith(" "): + return self.port_auto_complete(text, line, begidx, endidx) + return [x + for x in self.streams_db.get_loaded_streams_names() + if x.startswith(text)] + elif arg_num >= 2: + # return optional ports to attach to + return self.port_auto_complete(text, line, begidx, endidx) else: - print "Please provide list name and ports to attach to, or leave empty to attach to all ports." + return [text] + def prompt_response(self, response_obj): + resp_list = response_obj if isinstance(response_obj, list) else [response_obj] + def format_return_status(return_status): + if return_status: + return green("OK") + else: + return red("FAIL") + for response in resp_list: + response_str = "{id:^3} - {msg} ({stat})".format(id=response.id, + msg=response.msg, + stat=format_return_status(response.success)) + print response_str + return + def do_remove_all_streams(self, line): + '''Acquire ports\n''' + # make sure that the user wants to acquire all + args = line.split() + if len(args) < 1: + print magenta("Please provide a list of ports separated by spaces, " + "or specify 'all' to remove from all acquired ports") + return + if args[0] == "all": + ask = ConfirmMenu('Are you sure you want to remove all stream packs from all acquired ports? ') + rc = ask.show() + if rc == False: + print yellow("[ABORTED]\n") + return + else: + port_list = self.stateless_client.get_acquired_ports() + else: + port_list = self.extract_port_ids_from_line(line) + + # rc, resp_list = self.stateless_client.take_ownership(port_list, force) + try: + res_ok, log = self.stateless_client.remove_all_streams(port_list) + self.prompt_response(log) + if not res_ok: + print format_text("[FAILED]\n", 'red', 'bold') + return + print format_text("[SUCCESS]\n", 'green', 'bold') + except ValueError as e: + print magenta(str(e)) + print format_text("[FAILED]\n", 'red', 'bold') + def complete_remove_all_streams(self, text, line, begidx, endidx): + return self.port_auto_complete(text, line, begidx, endidx) + def do_start_traffic(self, line): + '''Start pre-submitted traffic in specified ports on TRex\n''' + # make sure that the user wants to acquire all + # parser = parsing_opts.gen_parser("start_traffic", self.do_start_traffic.__doc__, + # parsing_opts.PORT_LIST_WITH_ALL, parsing_opts.MULTIPLIER) + # opts = parser.parse_args(line.split()) + # + # print opts + # return + # # return + # # if not opts.port_list: + # # print magenta("Please provide a list of ports separated by spaces, " + # # "or specify 'all' to start traffic on all acquired ports") + # # return + # + # if "all" in opts.port_list: + # ask = ConfirmMenu('Are you sure you want to start traffic at all acquired ports? ') + # rc = ask.show() + # if rc == False: + # print yellow("[ABORTED]\n") + # return + # else: + # port_list = self.stateless_client.get_acquired_ports() + # else: + # try: + # port_list = self.extract_port_ids_from_list(opts.port_list) + # except ValueError as e: + # print magenta(e) + # return + args = line.split() + if len(args) < 1: + print magenta("Please provide a list of ports separated by spaces, " + "or specify 'all' to start traffic on all acquired ports") + return + if args[0] == "all": + ask = ConfirmMenu('Are you sure you want to start traffic at all acquired ports? ') + rc = ask.show() + if rc == False: + print yellow("[ABORTED]\n") + return + else: + port_list = self.stateless_client.get_acquired_ports() + else: + port_list = self.extract_port_ids_from_line(line) + try: + res_ok, log = self.stateless_client.start_traffic(1.0, port_id=port_list) + self.prompt_response(log) + if not res_ok: + print format_text("[FAILED]\n", 'red', 'bold') + return + print format_text("[SUCCESS]\n", 'green', 'bold') + except ValueError as e: + print magenta(str(e)) + print format_text("[FAILED]\n", 'red', 'bold') + def complete_start_traffic(self, text, line, begidx, endidx): + return self.port_auto_complete(text, line, begidx, endidx) + def help_start_traffic(self): + self.do_start_traffic("-h") - # adds a very simple stream - def do_add_simple_stream (self, line): - if line == "": - add_stream = AddStreamMenu() - add_stream.show() + def do_stop_traffic(self, line): + '''Stop active traffic in specified ports on TRex\n''' + # make sure that the user wants to acquire all + args = line.split() + if len(args) < 1: + print magenta("Please provide a list of ports separated by spaces, " + "or specify 'all' to stop traffic on all acquired ports") return + if args[0] == "all": + ask = ConfirmMenu('Are you sure you want to start traffic at all acquired ports? ') + rc = ask.show() + if rc == False: + print yellow("[ABORTED]\n") + return + else: + port_list = self.stateless_client.get_active_ports() + else: + port_list = self.extract_port_ids_from_line(line) - params = line.split() - port_id = int(params[0]) - stream_id = int(params[1]) + try: + res_ok, log = self.stateless_client.stop_traffic(port_list) + self.prompt_response(log) + if not res_ok: + print format_text("[FAILED]\n", 'red', 'bold') + return + print format_text("[SUCCESS]\n", 'green', 'bold') + except ValueError as e: + print magenta(str(e)) + print format_text("[FAILED]\n", 'red', 'bold') - packet = [0xFF,0xFF,0xFF] - rc, msg = self.rpc_client.add_stream(port_id = port_id, stream_id = stream_id, isg = 1.1, next_stream_id = -1, packet = packet) - if rc: - print "\nServer Response:\n\n" + self.rpc_client.pretty_json(json.dumps(msg)) + "\n" - else: - print "\n*** " + msg + "\n" + def complete_stop_traffic(self, text, line, begidx, endidx): + return self.port_auto_complete(text, line, begidx, endidx, active=True) # aliasing do_exit = do_EOF = do_q = do_quit -def setParserOptions (): +def setParserOptions(): parser = argparse.ArgumentParser(prog="trex_console.py") parser.add_argument("-s", "--server", help = "TRex Server [default is localhost]", @@ -566,22 +809,30 @@ 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)), + parser.add_argument("-z", "--pub", help = "TRex Async Publisher Port [default is 4500]\n", + default = 4500, + type = int) + + parser.add_argument("-u", "--user", help = "User Name [default is currently logged in user]\n", + default = get_current_user(), type = str) + parser.add_argument("--verbose", dest="verbose", + action="store_true", help="Switch ON verbose option. Default is: OFF.", + default = False) + return parser -def main (): +def main(): parser = setParserOptions() - options = parser.parse_args(sys.argv[1:]) + options = parser.parse_args() - # RPC client - rpc_client = TrexStatelessClient(options.server, options.port, options.user) + # Stateless client connection + stateless_client = CTRexStatelessClient(options.user, options.server, options.port, options.pub) # console try: - console = TrexConsole(rpc_client) + console = TRexConsole(stateless_client, options.verbose) console.cmdloop() except KeyboardInterrupt as e: print "\n\n*** Caught Ctrl + C... Exiting...\n\n" diff --git a/scripts/automation/trex_control_plane/console/trex_status.py b/scripts/automation/trex_control_plane/console/trex_status.py index 2c5a648f..2b97d7d3 100644 --- a/scripts/automation/trex_control_plane/console/trex_status.py +++ b/scripts/automation/trex_control_plane/console/trex_status.py @@ -11,22 +11,27 @@ import datetime g_curses_active = False +################### utils ################# + # simple percetange show def percentage (a, total): x = int ((float(a) / total) * 100) return str(x) + "%" -# simple float to human readable -def float_to_human_readable (size, suffix = "bps"): - for unit in ['','K','M','G']: - if abs(size) < 1024.0: - return "%3.1f %s%s" % (size, unit, suffix) - size /= 1024.0 - return "NaN" +################### panels ################# # panel object class TrexStatusPanel(object): - def __init__ (self, h, l, y, x, headline): + def __init__ (self, h, l, y, x, headline, status_obj): + + self.status_obj = status_obj + + self.log = status_obj.log + self.stateless_client = status_obj.stateless_client + + self.stats = status_obj.stats + self.general_stats = status_obj.general_stats + self.h = h self.l = l self.y = y @@ -53,64 +58,26 @@ class TrexStatusPanel(object): return self.win -# 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] - - # various kinds of panels # Server Info Panel class ServerInfoPanel(TrexStatusPanel): def __init__ (self, h, l, y, x, status_obj): - super(ServerInfoPanel, self).__init__(h, l, y ,x ,"Server Info:") - - self.status_obj = status_obj + super(ServerInfoPanel, self).__init__(h, l, y ,x ,"Server Info:", status_obj) def draw (self): - if self.status_obj.server_version == None: + if not self.status_obj.server_version : + return + + if not self.status_obj.server_sys_info: return - self.clear() - connection_details = self.status_obj.rpc_client.get_connection_details() + self.clear() - self.getwin().addstr(3, 2, "{:<30} {:30}".format("Server:",self.status_obj.server_sys_info["hostname"] + ":" + str(connection_details['port']))) + self.getwin().addstr(3, 2, "{:<30} {:30}".format("Server:",self.status_obj.server_sys_info["hostname"] + ":" + str(self.stateless_client.get_connection_port()))) self.getwin().addstr(4, 2, "{:<30} {:30}".format("Version:", self.status_obj.server_version["version"])) self.getwin().addstr(5, 2, "{:<30} {:30}".format("Build:", self.status_obj.server_version["build_date"] + " @ " + @@ -123,7 +90,7 @@ class ServerInfoPanel(TrexStatusPanel): self.getwin().addstr(9, 2, "{:<30} {:<30}".format("Ports Count:", self.status_obj.server_sys_info["port_count"])) - ports_owned = " ".join(str(x) for x in self.status_obj.rpc_client.get_owned_ports()) + ports_owned = " ".join(str(x) for x in self.status_obj.owned_ports_list) if not ports_owned: ports_owned = "None" @@ -134,92 +101,123 @@ class ServerInfoPanel(TrexStatusPanel): class GeneralInfoPanel(TrexStatusPanel): def __init__ (self, h, l, y, x, status_obj): - super(GeneralInfoPanel, self).__init__(h, l, y ,x ,"General Info:") - - self.status_obj = status_obj + super(GeneralInfoPanel, self).__init__(h, l, y ,x ,"General Info:", status_obj) def draw (self): - pass + self.clear() + + if not self.general_stats.is_online(): + self.getwin().addstr(3, 2, "No Published Data From TRex Server") + return + + self.getwin().addstr(3, 2, "{:<30} {:0.2f} %".format("CPU util.:", self.general_stats.get("m_cpu_util"))) + + self.getwin().addstr(6, 2, "{:<30} {:} / {:}".format("Total Tx. rate:", + self.general_stats.get("m_tx_bps", format = True, suffix = "bps"), + self.general_stats.get("m_tx_pps", format = True, suffix = "pps"))) + + + self.getwin().addstr(8, 2, "{:<30} {:} / {:}".format("Total Tx:", + self.general_stats.get_rel("m_total_tx_bytes", format = True, suffix = "B"), + self.general_stats.get_rel("m_total_tx_pkts", format = True, suffix = "pkts"))) + + self.getwin().addstr(11, 2, "{:<30} {:} / {:}".format("Total Rx. rate:", + self.general_stats.get("m_rx_bps", format = True, suffix = "bps"), + self.general_stats.get("m_rx_pps", format = True, suffix = "pps"))) + + + self.getwin().addstr(13, 2, "{:<30} {:} / {:}".format("Total Rx:", + self.general_stats.get_rel("m_total_rx_bytes", format = True, suffix = "B"), + self.general_stats.get_rel("m_total_rx_pkts", format = True, suffix = "pkts"))) # all ports stats class PortsStatsPanel(TrexStatusPanel): def __init__ (self, h, l, y, x, status_obj): - super(PortsStatsPanel, self).__init__(h, l, y ,x ,"Trex Ports:") + super(PortsStatsPanel, self).__init__(h, l, y ,x ,"Trex Ports:", status_obj) - self.status_obj = status_obj def draw (self): self.clear() - owned_ports = self.status_obj.rpc_client.get_owned_ports() + owned_ports = self.status_obj.owned_ports_list if not owned_ports: self.getwin().addstr(3, 2, "No Owned Ports - Please Acquire One Or More Ports") return # table header - self.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]")) + self.getwin().addstr(3, 2, "{:^15} {:^30} {:^30} {:^30}".format( + "Port ID", "Tx Rate [bps/pps]", "Rx Rate [bps/pps]", "Total Bytes [tx/rx]")) + - # port loop - self.status_obj.stats.query_sync() for i, port_index in enumerate(owned_ports): port_stats = self.status_obj.stats.get_port_stats(port_index) if port_stats: - self.getwin().addstr(5 + (i * 4), 2, "{:^15} {:^15,.2f} {:^15,.2f} {:^15,} {:^15,.2f} {:^15,.2f} {:^15,}".format( + self.getwin().addstr(5 + (i * 4), 2, "{:^15} {:^30} {:^30} {:^30}".format( "{0} ({1})".format(str(port_index), self.status_obj.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"])) - + "{0} / {1}".format(port_stats.get("m_total_tx_bps", format = True, suffix = "bps"), + port_stats.get("m_total_tx_pps", format = True, suffix = "pps")), + + "{0} / {1}".format(port_stats.get("m_total_rx_bps", format = True, suffix = "bps"), + port_stats.get("m_total_rx_pps", format = True, suffix = "pps")), + "{0} / {1}".format(port_stats.get_rel("obytes", format = True, suffix = "B"), + port_stats.get_rel("ibytes", format = True, suffix = "B")))) + else: - self.getwin().addstr(5 + (i * 4), 2, "{:^15} {:^15} {:^15} {:^15} {:^15} {:^15} {:^15}".format( + self.getwin().addstr(5 + (i * 4), 2, 2, "{:^15} {:^30} {:^30} {:^30}".format( "{0} ({1})".format(str(port_index), self.status_obj.server_sys_info["ports"][port_index]["speed"]), "N/A", "N/A", "N/A", - "N/A", - "N/A", "N/A")) + + # old format +# if port_stats: +# self.getwin().addstr(5 + (i * 4), 2, "{:^15} {:^15} {:^15} {:^15} {:^15} {:^15} {:^15}".format( +# "{0} ({1})".format(str(port_index), self.status_obj.server_sys_info["ports"][port_index]["speed"]), +# port_stats.get("m_total_tx_pps", format = True, suffix = "pps"), +# port_stats.get("m_total_tx_bps", format = True, suffix = "bps"), +# port_stats.get_rel("obytes", format = True, suffix = "B"), +# port_stats.get("m_total_rx_pps", format = True, suffix = "pps"), +# port_stats.get("m_total_rx_bps", format = True, suffix = "bps"), +# port_stats.get_rel("ibytes", format = True, suffix = "B"))) +# +# else: +# self.getwin().addstr(5 + (i * 4), 2, "{:^15} {:^15} {:^15} {:^15} {:^15} {:^15} {:^15}".format( +# "{0} ({1})".format(str(port_index), self.status_obj.server_sys_info["ports"][port_index]["speed"]), +# "N/A", +# "N/A", +# "N/A", +# "N/A", +# "N/A", +# "N/A")) + # control panel class ControlPanel(TrexStatusPanel): def __init__ (self, h, l, y, x, status_obj): - super(ControlPanel, self).__init__(h, l, y, x, "") + super(ControlPanel, self).__init__(h, l, y, x, "", status_obj) - self.status_obj = status_obj def draw (self): self.clear() self.getwin().addstr(1, 2, "'g' - general, '0-{0}' - specific port, 'f' - freeze, 'c' - clear stats, 'p' - ping server, 'q' - quit" - .format(self.status_obj.rpc_client.get_port_count() - 1)) + .format(self.status_obj.stateless_client.get_port_count() - 1)) - index = 3 - - cut = len(self.status_obj.log) - 4 - if cut < 0: - cut = 0 - - for l in self.status_obj.log[cut:]: - self.getwin().addstr(index, 2, l) - index += 1 + self.log.draw(self.getwin(), 2, 3) # specific ports panels class SinglePortPanel(TrexStatusPanel): def __init__ (self, h, l, y, x, status_obj, port_id): - super(SinglePortPanel, self).__init__(h, l, y, x, "Port {0}".format(port_id)) + super(SinglePortPanel, self).__init__(h, l, y, x, "Port {0}".format(port_id), status_obj) - self.status_obj = status_obj self.port_id = port_id def draw (self): @@ -227,7 +225,7 @@ class SinglePortPanel(TrexStatusPanel): self.clear() - if not self.port_id in self.status_obj.rpc_client.get_owned_ports(): + if not self.port_id in self.status_obj.owned_ports_list: self.getwin().addstr(y, 2, "Port {0} is not owned by you, please acquire the port for more info".format(self.port_id)) return @@ -241,16 +239,19 @@ class SinglePortPanel(TrexStatusPanel): y += 2 # streams - if 'streams' in self.status_obj.snapshot[self.port_id]: - for stream_id, stream in self.status_obj.snapshot[self.port_id]['streams'].iteritems(): + + if 'streams' in self.status_obj.owned_ports[str(self.port_id)]: + stream_info = self.status_obj.owned_ports[str(self.port_id)]['streams'] + + for stream_id, stream in sorted(stream_info.iteritems(), key=operator.itemgetter(0)): self.getwin().addstr(y, 2, "{:^15} {:^15} {:^15} {:^15} {:^15} {:^15} {:^15}".format( stream_id, - ("True" if stream['stream']['enabled'] else "False"), - stream['stream']['mode']['type'], - ("True" if stream['stream']['self_start'] else "False"), - stream['stream']['isg'], - (stream['stream']['next_stream_id'] if stream['stream']['next_stream_id'] != -1 else "None"), - ("{0} instr.".format(len(stream['stream']['vm'])) if stream['stream']['vm'] else "None"))) + ("True" if stream['enabled'] else "False"), + stream['mode']['type'], + ("True" if stream['self_start'] else "False"), + stream['isg'], + (stream['next_stream_id'] if stream['next_stream_id'] != -1 else "None"), + ("{0} instr.".format(len(stream['vm'])) if stream['vm'] else "None"))) y += 1 @@ -260,128 +261,180 @@ class SinglePortPanel(TrexStatusPanel): self.getwin().addstr(y, 2, "Traffic:", curses.A_UNDERLINE) y += 2 - self.status_obj.stats.query_sync() - port_stats = self.status_obj.stats.get_port_stats(self.port_id) - # table header - self.getwin().addstr(y, 2, "{:^15} {:^15} {:^15} {:^15} {:^15} {:^15} {:^15}".format( - "Port ID", "Tx [pps]", "Tx [bps]", "Tx [bytes]", "Rx [pps]", "Rx [bps]", "Rx [bytes]")) + # table header + self.getwin().addstr(y, 2, "{:^15} {:^30} {:^30} {:^30}".format( + "Port ID", "Tx Rate [bps/pps]", "Rx Rate [bps/pps]", "Total Bytes [tx/rx]")) + y += 2 - if port_stats: - self.getwin().addstr(y, 2, "{:^15} {:^15,} {:^15,} {:^15,} {:^15,} {:^15,} {:^15,}".format( - "{0} ({1})".format(str(self.port_id), self.status_obj.server_sys_info["ports"][self.port_id]["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"])) + port_stats = self.status_obj.stats.get_port_stats(self.port_id) + if port_stats: + self.getwin().addstr(y, 2, "{:^15} {:^30} {:^30} {:^30}".format( + "{0} ({1})".format(str(self.port_id), self.status_obj.server_sys_info["ports"][self.port_id]["speed"]), + "{0} / {1}".format(port_stats.get("m_total_tx_bps", format = True, suffix = "bps"), + port_stats.get("m_total_tx_pps", format = True, suffix = "pps")), + + "{0} / {1}".format(port_stats.get("m_total_rx_bps", format = True, suffix = "bps"), + port_stats.get("m_total_rx_pps", format = True, suffix = "pps")), + "{0} / {1}".format(port_stats.get_rel("obytes", format = True, suffix = "B"), + port_stats.get_rel("ibytes", format = True, suffix = "B")))) + else: - self.getwin().addstr(y, 2, "{:^15} {:^15} {:^15} {:^15} {:^15} {:^15} {:^15}".format( + self.getwin().addstr(y + (i * 4), 2, 2, "{:^15} {:^30} {:^30} {:^30}".format( "{0} ({1})".format(str(self.port_id), self.status_obj.server_sys_info["ports"][self.port_id]["speed"]), "N/A", "N/A", "N/A", - "N/A", - "N/A", "N/A")) - y += 2 -# status object -class TrexStatus(): - def __init__ (self, stdscr, rpc_client): - self.stdscr = stdscr +################### main objects ################# + +# status log +class TrexStatusLog(): + def __init__ (self): self.log = [] - self.rpc_client = rpc_client - self.snapshot = self.rpc_client.snapshot() + def add_event (self, msg): + self.log.append("[{0}] {1}".format(str(datetime.datetime.now().time()), msg)) - # fetch server info - self.get_server_info() + def draw (self, window, x, y, max_lines = 4): + index = y + + cut = len(self.log) - max_lines + if cut < 0: + cut = 0 + + for msg in self.log[cut:]: + window.addstr(index, x, msg) + index += 1 + +# status commands +class TrexStatusCommands(): + def __init__ (self, status_object): - # create stats objects - self.stats = Stats(rpc_client, self.rpc_client.get_owned_ports()) + self.status_object = status_object + + self.stateless_client = status_object.stateless_client + self.log = self.status_object.log - # register actions self.actions = {} - self.actions[ord('q')] = self.action_quit - self.actions[ord('p')] = self.action_ping - self.actions[ord('f')] = self.action_freeze + self.actions[ord('q')] = self._quit + self.actions[ord('p')] = self._ping + self.actions[ord('f')] = self._freeze - self.actions[ord('g')] = self.action_show_ports_stats + self.actions[ord('g')] = self._show_ports_stats - for port_id in xrange(0, self.rpc_client.get_port_count()): - self.actions[ord('0') + port_id] = self.action_show_port_generator(port_id) + # register all the available ports shortcuts + for port_id in xrange(0, self.stateless_client.get_port_count()): + self.actions[ord('0') + port_id] = self._show_port_generator(port_id) + + + # handle a key pressed + def handle (self, ch): + if ch in self.actions: + return self.actions[ch]() + else: + self.log.add_event("Unknown key pressed, please see legend") + return True + + # show all ports + def _show_ports_stats (self): + self.log.add_event("Switching to all ports view") + self.status_object.stats_panel = self.status_object.ports_stats_panel - - # all ports stats - def action_show_ports_stats (self): - self.add_log_event("Switching to all ports view") - self.stats_panel = self.ports_stats_panel - return True - # function generator for different ports requests - def action_show_port_generator (self, port_id): - def action_show_port(): - self.add_log_event("Switching panel to port {0}".format(port_id)) - self.stats_panel = self.ports_panels[port_id] + + # function generator for different ports requests + def _show_port_generator (self, port_id): + def _show_port(): + self.log.add_event("Switching panel to port {0}".format(port_id)) + self.status_object.stats_panel = self.status_object.ports_panels[port_id] return True - return action_show_port + return _show_port - def action_freeze (self): - self.update_active = not self.update_active - self.add_log_event("Update continued" if self.update_active else "Update stopped") + def _freeze (self): + self.status_object.update_active = not self.status_object.update_active + self.log.add_event("Update continued" if self.status_object.update_active else "Update stopped") return True - def action_quit(self): + def _quit(self): return False - def action_ping (self): - self.add_log_event("Pinging RPC server") + def _ping (self): + self.log.add_event("Pinging RPC server") - rc, msg = self.rpc_client.ping_rpc_server() + rc, msg = self.stateless_client.ping() if rc: - self.add_log_event("Server replied: '{0}'".format(msg)) + self.log.add_event("Server replied: '{0}'".format(msg)) else: - self.add_log_event("Failed to get reply") + self.log.add_event("Failed to get reply") return True - def get_server_info (self): +# status object +# +# +# +class TrexStatus(): + def __init__ (self, stdscr, stateless_client): + self.stdscr = stdscr - self.server_version = self.rpc_client.get_rpc_server_version() - self.server_sys_info = self.rpc_client.get_system_info() + self.stateless_client = stateless_client + self.log = TrexStatusLog() + self.cmds = TrexStatusCommands(self) - def add_log_event (self, msg): - self.log.append("[{0}] {1}".format(str(datetime.datetime.now().time()), msg)) + self.stats = stateless_client.get_stats_async() + self.general_stats = stateless_client.get_stats_async().get_general_stats() - # control panel - def update_control (self): - self.control_panel.clear() + # fetch server info + rc, self.server_sys_info = self.stateless_client.get_system_info() + if not rc: + return - 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)) + rc, self.server_version = self.stateless_client.get_version() + if not rc: + return - index = 3 + # list of owned ports + self.owned_ports_list = self.stateless_client.get_acquired_ports() + + # data per port + self.owned_ports = {} - cut = len(self.log) - 4 - if cut < 0: - cut = 0 + for port_id in self.owned_ports_list: + self.owned_ports[str(port_id)] = {} + self.owned_ports[str(port_id)]['streams'] = {} - for l in self.log[cut:]: - self.control_panel.getwin().addstr(index, 2, l) - index += 1 + rc, stream_list = self.stateless_client.get_all_streams(port_id) + if not rc: + raise Exception("unable to get streams") + self.owned_ports[str(port_id)] = stream_list + + + try: + curses.curs_set(0) + except: + pass + + curses.use_default_colors() + self.stdscr.nodelay(1) + curses.nonl() + curses.noecho() + + self.generate_layout() + + def generate_layout (self): self.max_y = self.stdscr.getmaxyx()[0] self.max_x = self.stdscr.getmaxyx()[1] @@ -394,7 +447,7 @@ class TrexStatus(): self.ports_stats_panel = PortsStatsPanel(int(self.max_y * 0.8), self.max_x / 2, 0, 0, self) self.ports_panels = {} - for i in xrange(0, self.rpc_client.get_port_count()): + for i in xrange(0, self.stateless_client.get_port_count()): self.ports_panels[i] = SinglePortPanel(int(self.max_y * 0.8), self.max_x / 2, 0, 0, self, i) # at start time we point to the main one @@ -411,28 +464,27 @@ class TrexStatus(): # 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 + + return self.cmds.handle(ch) # main run entry point def run (self): - try: - curses.curs_set(0) - except: - pass - curses.use_default_colors() - self.stdscr.nodelay(1) - curses.nonl() - curses.noecho() + # list of owned ports + self.owned_ports_list = self.stateless_client.get_acquired_ports() - self.generate_layout() + # data per port + self.owned_ports = {} + + for port_id in self.owned_ports_list: + self.owned_ports[str(port_id)] = {} + self.owned_ports[str(port_id)]['streams'] = {} + + rc, stream_list = self.stateless_client.get_all_streams(port_id) + if not rc: + raise Exception("unable to get streams") + + self.owned_ports[str(port_id)] = stream_list self.update_active = True while (True): @@ -454,14 +506,21 @@ class TrexStatus(): sleep(0.01) -def show_trex_status_internal (stdscr, rpc_client): - trex_status = TrexStatus(stdscr, rpc_client) +# global container +trex_status = None + +def show_trex_status_internal (stdscr, stateless_client): + global trex_status + + if trex_status == None: + trex_status = TrexStatus(stdscr, stateless_client) + trex_status.run() -def show_trex_status (rpc_client): +def show_trex_status (stateless_client): try: - curses.wrapper(show_trex_status_internal, rpc_client) + curses.wrapper(show_trex_status_internal, stateless_client) except KeyboardInterrupt: curses.endwin() diff --git a/scripts/automation/trex_control_plane/examples/stateless_example.py b/scripts/automation/trex_control_plane/examples/stateless_example.py new file mode 100755 index 00000000..bb0fe983 --- /dev/null +++ b/scripts/automation/trex_control_plane/examples/stateless_example.py @@ -0,0 +1,30 @@ +#!/router/bin/python + +import trex_root_path +from client.trex_hltapi import CTRexHltApi + +if __name__ == "__main__": + port_list = [1,2] + try: + hlt_client = CTRexHltApi() + con = hlt_client.connect("localhost", port_list, "danklei", break_locks=True, reset=True)#, port=6666) + print con + + res = hlt_client.traffic_config("create", 1)#, ip_src_addr="2000.2.2") + print res + res = hlt_client.traffic_config("create", 2)#, ip_src_addr="2000.2.2") + print res + + res = hlt_client.traffic_control("run", [1, 2])#, ip_src_addr="2000.2.2") + print res + + res = hlt_client.traffic_control("stop", [1, 2])#, ip_src_addr="2000.2.2") + print res + + + + except Exception as e: + raise + finally: + res = hlt_client.cleanup_session(port_list) + print res
\ No newline at end of file diff --git a/scripts/cap2/many_client_example.yaml b/scripts/cap2/many_client_example.yaml new file mode 100644 index 00000000..7908a5a4 --- /dev/null +++ b/scripts/cap2/many_client_example.yaml @@ -0,0 +1,42 @@ +- duration : 1.0 + generator : + distribution : "random" + clients_start : "20.0.0.1" + clients_end : "20.10.85.255" + servers_start : "90.0.0.1" + servers_end : "90.0.255.255" + clients_per_gb : 201 + min_clients : 101 + dual_port_mask : "1.0.0.0" + tcp_aging : 0 + udp_aging : 0 + generator_clients : + - name : "c1" + distribution : "random" + ip_start : "21.0.0.1" + ip_end : "21.10.255.255" + - name : "c2" + distribution : "random" + ip_start : "36.0.0.1" + ip_end : "36.0.1.254" + generator_servers : + - name : "s1" + distribution : "random" + ip_start : "22.0.0.1" + ip_end : "22.1.255.255" + track_ports : false + - name : "s2" + distribution : "random" + ip_start : "38.0.0.1" + ip_end : "38.0.3.255" + track_ports : false + mac : [0x0,0x0,0x0,0x1,0x0,0x00] + cap_info : + - name: cap2/http_get.pcap + client_pool: "c1" + server_pool: "s1" + cps : 1.0 + ipg : 100 + rtt : 10000 + w : 1 + diff --git a/scripts/exp/dns-0-ex.erf b/scripts/exp/dns-0-ex.erf Binary files differindex 5ffffcb3..fdb19009 100755 --- a/scripts/exp/dns-0-ex.erf +++ b/scripts/exp/dns-0-ex.erf diff --git a/scripts/exp/dns-0.erf b/scripts/exp/dns-0.erf Binary files differindex d8d601b7..fdb19009 100644 --- a/scripts/exp/dns-0.erf +++ b/scripts/exp/dns-0.erf diff --git a/scripts/exp/dns_e-0-ex.erf b/scripts/exp/dns_e-0-ex.erf Binary files differindex 7ebfd69a..e0de09fc 100755 --- a/scripts/exp/dns_e-0-ex.erf +++ b/scripts/exp/dns_e-0-ex.erf diff --git a/scripts/exp/dns_e-0.erf b/scripts/exp/dns_e-0.erf Binary files differindex 7ebfd69a..e0de09fc 100644 --- a/scripts/exp/dns_e-0.erf +++ b/scripts/exp/dns_e-0.erf diff --git a/scripts/exp/dns_flip-0-ex.erf b/scripts/exp/dns_flip-0-ex.erf Binary files differindex f6074ad7..774f0fdf 100755 --- a/scripts/exp/dns_flip-0-ex.erf +++ b/scripts/exp/dns_flip-0-ex.erf diff --git a/scripts/exp/dns_flip-0.erf b/scripts/exp/dns_flip-0.erf Binary files differindex f6074ad7..774f0fdf 100644 --- a/scripts/exp/dns_flip-0.erf +++ b/scripts/exp/dns_flip-0.erf diff --git a/scripts/exp/dns_ipv6-0-ex.erf b/scripts/exp/dns_ipv6-0-ex.erf Binary files differindex c47a6496..e0d33efc 100755 --- a/scripts/exp/dns_ipv6-0-ex.erf +++ b/scripts/exp/dns_ipv6-0-ex.erf diff --git a/scripts/exp/dns_ipv6-0.erf b/scripts/exp/dns_ipv6-0.erf Binary files differindex 53dee235..e0d33efc 100644 --- a/scripts/exp/dns_ipv6-0.erf +++ b/scripts/exp/dns_ipv6-0.erf diff --git a/scripts/exp/dns_one_server-0-ex.erf b/scripts/exp/dns_one_server-0-ex.erf Binary files differindex 0d3d447b..15323016 100755 --- a/scripts/exp/dns_one_server-0-ex.erf +++ b/scripts/exp/dns_one_server-0-ex.erf diff --git a/scripts/exp/dns_one_server-0.erf b/scripts/exp/dns_one_server-0.erf Binary files differindex ef76a69b..15323016 100644 --- a/scripts/exp/dns_one_server-0.erf +++ b/scripts/exp/dns_one_server-0.erf diff --git a/scripts/exp/dns_p-0-ex.erf b/scripts/exp/dns_p-0-ex.erf Binary files differindex ec313584..7d93c1d3 100755 --- a/scripts/exp/dns_p-0-ex.erf +++ b/scripts/exp/dns_p-0-ex.erf diff --git a/scripts/exp/dns_p-0.erf b/scripts/exp/dns_p-0.erf Binary files differindex ec313584..7d93c1d3 100644 --- a/scripts/exp/dns_p-0.erf +++ b/scripts/exp/dns_p-0.erf diff --git a/scripts/exp/dyn_pyld1-0-ex.erf b/scripts/exp/dyn_pyld1-0-ex.erf Binary files differindex 7d2089db..6a0028dc 100755 --- a/scripts/exp/dyn_pyld1-0-ex.erf +++ b/scripts/exp/dyn_pyld1-0-ex.erf diff --git a/scripts/exp/dyn_pyld1-0.erf b/scripts/exp/dyn_pyld1-0.erf Binary files differindex 175a810c..6a0028dc 100644 --- a/scripts/exp/dyn_pyld1-0.erf +++ b/scripts/exp/dyn_pyld1-0.erf diff --git a/scripts/exp/imix-0-ex.erf b/scripts/exp/imix-0-ex.erf Binary files differindex 233e6b31..07fb2ace 100755 --- a/scripts/exp/imix-0-ex.erf +++ b/scripts/exp/imix-0-ex.erf diff --git a/scripts/exp/imix-0.erf b/scripts/exp/imix-0.erf Binary files differindex c41a3006..07fb2ace 100644 --- a/scripts/exp/imix-0.erf +++ b/scripts/exp/imix-0.erf diff --git a/scripts/exp/imix_v6-0-ex.erf b/scripts/exp/imix_v6-0-ex.erf Binary files differindex 56412091..c5f247d1 100755 --- a/scripts/exp/imix_v6-0-ex.erf +++ b/scripts/exp/imix_v6-0-ex.erf diff --git a/scripts/exp/imix_v6-0.erf b/scripts/exp/imix_v6-0.erf Binary files differindex a85ed2b9..c5f247d1 100644 --- a/scripts/exp/imix_v6-0.erf +++ b/scripts/exp/imix_v6-0.erf diff --git a/scripts/exp/limit_single_pkt-0-ex.erf b/scripts/exp/limit_single_pkt-0-ex.erf Binary files differindex 3f7f0ff2..adc6fd46 100755 --- a/scripts/exp/limit_single_pkt-0-ex.erf +++ b/scripts/exp/limit_single_pkt-0-ex.erf diff --git a/scripts/exp/limit_single_pkt-0.erf b/scripts/exp/limit_single_pkt-0.erf Binary files differindex 548d2e3f..adc6fd46 100644 --- a/scripts/exp/limit_single_pkt-0.erf +++ b/scripts/exp/limit_single_pkt-0.erf diff --git a/scripts/exp/sfr2-0-ex.erf b/scripts/exp/sfr2-0-ex.erf Binary files differindex 5e2b791f..e5dfc4c3 100755 --- a/scripts/exp/sfr2-0-ex.erf +++ b/scripts/exp/sfr2-0-ex.erf diff --git a/scripts/exp/sfr2-0.erf b/scripts/exp/sfr2-0.erf Binary files differindex bf5ff3ef..e5dfc4c3 100644 --- a/scripts/exp/sfr2-0.erf +++ b/scripts/exp/sfr2-0.erf diff --git a/src/bp_gtest.cpp b/src/bp_gtest.cpp index a529d637..03ab74bd 100755 --- a/src/bp_gtest.cpp +++ b/src/bp_gtest.cpp @@ -66,7 +66,7 @@ int test_priorty_queue(void){ int i; for (i=0; i<10; i++) { node = new CGenNode(); - printf(" +%x \n",node); + printf(" +%p \n",node); node->m_flow_id = 10-i; node->m_pkt_info = (CFlowPktInfo *)(uintptr_t)i; node->m_time = (double)i+0.1; @@ -74,7 +74,7 @@ int test_priorty_queue(void){ } while (!p_queue.empty()) { node = p_queue.top(); - printf(" -->%x \n",node); + printf(" -->%p \n",node); //node->Dump(stdout); p_queue.pop(); //delete node; @@ -159,7 +159,7 @@ public: bool init(void){ - uint16 * ports; + uint16 * ports = NULL; CTupleBase tuple; CErfIF erf_vif; @@ -205,7 +205,7 @@ public: } } - lpt->generate_erf(buf,CGlobalInfo::m_options.preview); + lpt->start_generate_stateful(buf,CGlobalInfo::m_options.preview); lpt->m_node_gen.DumpHist(stdout); cmp.d_sec = m_time_diff; @@ -663,6 +663,7 @@ TEST_F(basic, latency1) { po->preview.setFileWrite(true); uint8_t mac[]={0,0,0,1,0,0}; + (void)mac; CErfIF erf_vif; erf_vif.set_review_mode(&CGlobalInfo::m_options.preview); @@ -714,6 +715,7 @@ TEST_F(basic, latency2) { uint8_t mac[]={0,0,0,1,0,0}; + (void)mac; mac[0]=0; mac[1]=0; @@ -728,14 +730,13 @@ TEST_F(basic, latency2) { int i; for (i=0; i<100; i++) { - uint8_t *p; rte_mbuf_t * m=l.generate_pkt(0); - p=rte_pktmbuf_mtod(m, uint8_t*); + rte_pktmbuf_mtod(m, uint8_t*); //utl_DumpBuffer(stdout,p,l.get_pkt_size(),0); port0.update_packet(m); - p=rte_pktmbuf_mtod(m, uint8_t*); + rte_pktmbuf_mtod(m, uint8_t*); //utl_DumpBuffer(stdout,p,l.get_pkt_size(),0); //printf("offset is : %d \n",l.get_payload_offset()); @@ -763,6 +764,7 @@ TEST_F(basic, latency3) { uint8_t mac[]={0,0,0,1,0,0}; + (void)mac; mac[0]=0; @@ -850,6 +852,7 @@ public: TEST_F(basic, latency4) { uint8_t mac[]={0,0,0,1,0,0}; + (void)mac; mac[0]=0; mac[1]=0; @@ -2031,6 +2034,10 @@ public: virtual int send_node(CGenNode * node); + virtual int update_mac_addr_from_global_cfg(pkt_dir_t dir, rte_mbuf_t *m){ + return (0); + } + /** * flush all pending packets into the stream @@ -2105,7 +2112,7 @@ public: int i; for (i=0; i<m_threads; i++) { lpt=fl.m_threads_info[i]; - lpt->generate_erf("t1",CGlobalInfo::m_options.preview); + lpt->start_generate_stateful("t1",CGlobalInfo::m_options.preview); } fl.Delete(); return (true); @@ -2121,7 +2128,7 @@ class CRxCheck1 : public CRxCheckCallbackBase { public: virtual void handle_packet(rte_mbuf_t * m){ - char *mp=rte_pktmbuf_mtod(m, char*); + rte_pktmbuf_mtod(m, char*); CRx_check_header * rx_p; rte_mbuf_t * m2 = m->next; rx_p=(CRx_check_header *)rte_pktmbuf_mtod(m2, char*); @@ -2755,7 +2762,7 @@ TEST_F(gt_ring, ring1) { TEST_F(gt_ring, ring2) { CMessagingManager ringmg; - ringmg.Create(8); + ringmg.Create(8, "test"); int i; for (i=0; i<8; i++) { diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp index c3581c55..0c0cbb75 100755 --- a/src/bp_sim.cpp +++ b/src/bp_sim.cpp @@ -25,6 +25,7 @@ limitations under the License. #include "msg_manager.h" #include <common/basic_utils.h> +#include <trex_stream_node.h> #undef VALG @@ -71,11 +72,11 @@ void CGlobalMemory::Dump(FILE *fd){ c_size=c_size*2; } - fprintf(fd," %-40s : %lu \n",names[i].c_str(),m_mbuf[i]); + fprintf(fd," %-40s : %lu \n",names[i].c_str(),(ulong)m_mbuf[i]); } c_total += (m_mbuf[MBUF_DP_FLOWS] * sizeof(CGenNode)); - fprintf(fd," %-40s : %lu \n","get_each_core_dp_flows",get_each_core_dp_flows()); + fprintf(fd," %-40s : %lu \n","get_each_core_dp_flows",(ulong)get_each_core_dp_flows()); fprintf(fd," %-40s : %s \n","Total memory",double_to_human_str(c_total,"bytes",KBYE_1024).c_str() ); } @@ -239,7 +240,7 @@ bool CPlatformSocketInfoConfig::init(){ } if ( m_thread_phy_to_virtual[phy_thread] ){ - printf("ERROR physical thread %d defined twice %d \n",phy_thread); + printf("ERROR physical thread %d defined twice\n",phy_thread); exit(1); } m_thread_phy_to_virtual[phy_thread]=virt_thread; @@ -268,7 +269,7 @@ bool CPlatformSocketInfoConfig::init(){ void CPlatformSocketInfoConfig::dump(FILE *fd){ - fprintf(fd," core_mask %x \n",get_cores_mask()); + fprintf(fd," core_mask %llx \n",(unsigned long long)get_cores_mask()); fprintf(fd," sockets :"); int i; for (i=0; i<MAX_SOCKETS_SUPPORTED; i++) { @@ -279,7 +280,7 @@ void CPlatformSocketInfoConfig::dump(FILE *fd){ fprintf(fd," \n"); fprintf(fd," active sockets : %d \n",max_num_active_sockets()); - fprintf(fd," ports_sockets : \n",max_num_active_sockets()); + fprintf(fd," ports_sockets : %d \n",max_num_active_sockets()); for (i=0; i<(MAX_LATENCY_PORTS); i++) { fprintf(fd,"%d,",port_to_socket(i)); @@ -820,7 +821,6 @@ void CPacketIndication::UpdatePacketPadding(){ void CPacketIndication::RefreshPointers(){ char *pobase=getBasePtr(); - CPacketIndication * obj=this; m_ether = (EthernetHeader *) (pobase + m_ether_offset); l3.m_ipv4 = (IPHeader *) (pobase + m_ip_offset); @@ -1671,7 +1671,6 @@ char * CFlowPktInfo::push_ipv4_option_offline(uint8_t bytes){ void CFlowPktInfo::mask_as_learn(){ - char *p; CNatOption *lpNat; if ( m_pkt_indication.is_ipv6() ){ lpNat=(CNatOption *)push_ipv6_option_offline(CNatOption::noOPTION_LEN); @@ -2265,7 +2264,7 @@ void CCCapFileMemoryUsage::dump(FILE *fd){ int c_total=0; for (i=0; i<CCCapFileMemoryUsage::MASK_SIZE; i++) { - fprintf(fd," size_%-7d : %lu \n",c_size,m_buf[i]); + fprintf(fd," size_%-7d : %lu \n",c_size, (ulong)m_buf[i]); c_total +=m_buf[i]*c_size; c_size = c_size*2; } @@ -2440,7 +2439,6 @@ void operator >> (const YAML::Node& node, CFlowYamlInfo & fi) { if ( node.FindValue("dyn_pyload") ){ - int i; const YAML::Node& dyn_pyload = node["dyn_pyload"]; for(unsigned i=0;i<dyn_pyload.size();i++) { CFlowYamlDpPkt fd; @@ -2839,8 +2837,20 @@ void CFlowStats::DumpHeader(FILE *fd){ void CFlowStats::Dump(FILE *fd){ //"name","cps","f-pkts","f-bytes","Mb/sec","MB/sec","c-flows","PPS","total-Mbytes-duration","errors","flows" fprintf(fd," %02d, %-40s ,%4.2f,%4.2f, %5.0f , %7.0f ,%7.2f ,%7.2f , %7.2f , %10.0f , %5.0f , %7.0f , %llu , %llu \n", - m_id,m_name.c_str(),m_cps,get_normal_cps(), - m_pkt,m_bytes,duration_sec,m_mb_sec,m_mB_sec,m_c_flows,m_pps,m_total_Mbytes,m_errors,m_flows); + m_id, + m_name.c_str(), + m_cps, + get_normal_cps(), + m_pkt, + m_bytes, + duration_sec, + m_mb_sec, + m_mB_sec, + m_c_flows, + m_pps, + m_total_Mbytes, + (unsigned long long)m_errors, + (unsigned long long)m_flows); } bool CFlowGeneratorRecPerThread::Create(CTupleGeneratorSmart * global_gen, @@ -3045,21 +3055,20 @@ void CGenNode::DumpHeader(FILE *fd){ } void CGenNode::Dump(FILE *fd){ - fprintf(fd,"%.6f,%llx,%p,%llu,%d,%d,%d,%d,%d,%d,%x,%x,%d\n",m_time,m_flow_id,m_pkt_info, - m_pkt_info->m_pkt_indication.m_packet->pkt_cnt, - m_pkt_info->m_pkt_indication.m_packet->pkt_len, - m_pkt_info->m_pkt_indication.m_desc.getId(), - (m_pkt_info->m_pkt_indication.m_desc.IsInitSide()?1:0), - m_pkt_info->m_pkt_indication.m_desc.IsLastPkt(), + fprintf(fd,"%.6f,%llx,%p,%llu,%d,%d,%d,%d,%d,%d,%x,%x,%d\n", + m_time, + (unsigned long long)m_flow_id, + m_pkt_info, + (unsigned long long)m_pkt_info->m_pkt_indication.m_packet->pkt_cnt, + m_pkt_info->m_pkt_indication.m_packet->pkt_len, + m_pkt_info->m_pkt_indication.m_desc.getId(), + (m_pkt_info->m_pkt_indication.m_desc.IsInitSide()?1:0), + m_pkt_info->m_pkt_indication.m_desc.IsLastPkt(), m_type, m_thread_id, m_src_ip, m_dest_ip, - m_src_port - - - - ); + m_src_port); } @@ -3114,14 +3123,10 @@ int CNodeGenerator::close_file(CFlowGenListPerThread * thread){ return (0); } -int CNodeGenerator::flush_one_node_to_file(CGenNode * node){ - BP_ASSERT(m_v_if); - return (m_v_if->send_node(node)); -} int CNodeGenerator::update_stats(CGenNode * node){ if ( m_preview_mode.getVMode() >2 ){ - fprintf(stdout," %llu ,",m_cnt); + fprintf(stdout," %llu ,", (unsigned long long)m_cnt); node->Dump(stdout); m_cnt++; } @@ -3204,6 +3209,10 @@ bool CFlowGenListPerThread::Create(uint32_t thread_id, assert(m_ring_from_rx); assert(m_ring_to_rx); + + /* create the info required for stateless DP core */ + m_stateless_dp_info.create(thread_id, this); + return (true); } @@ -3351,6 +3360,7 @@ void CFlowGenListPerThread::Delete(){ m_node_gen.Delete(); Clean(); m_cpu_cp_u.Delete(); + } @@ -3397,15 +3407,24 @@ int CNodeGenerator::flush_file(dsec_t max_time, bool done=false; thread->m_cpu_dp_u.start_work(); - while (!m_p_queue.empty()) { + + /** + * if a positive value was given to max time + * schedule an exit node + */ + if ( (max_time > 0) && (!always) ) { + CGenNode *exit_node = thread->create_node(); + + exit_node->m_type = CGenNode::EXIT_SCHED; + exit_node->m_time = max_time; + add_node(exit_node); + } + + while (true) { + node = m_p_queue.top(); - n_time = node->m_time+ offset; + n_time = node->m_time + offset; - if (( (n_time) > max_time ) && - (always==false) ) { - /* nothing to do */ - break; - } events++; /*#ifdef VALG if (events > 1 ) { @@ -3416,7 +3435,6 @@ int CNodeGenerator::flush_file(dsec_t max_time, if ( likely ( m_is_realtime ) ){ dsec_t dt ; thread->m_cpu_dp_u.commit(); - bool once=false; while ( true ) { dt = now_sec() - n_time ; @@ -3425,12 +3443,6 @@ int CNodeGenerator::flush_file(dsec_t max_time, break; } - if (!once) { - /* check the msg queue once */ - thread->check_msgs(); - once=true; - } - rte_pause(); } thread->m_cpu_dp_u.start_work(); @@ -3449,55 +3461,72 @@ int CNodeGenerator::flush_file(dsec_t max_time, flush_time=now_sec(); } } + #ifndef RTE_DPDK - thread->check_msgs(); + thread->check_msgs(); #endif uint8_t type=node->m_type; - if ( likely( type == CGenNode::FLOW_PKT ) ) { - /* PKT */ - if ( !(node->is_repeat_flow()) || (always==false)) { - flush_one_node_to_file(node); - #ifdef _DEBUG - update_stats(node); - #endif - } - m_p_queue.pop(); - if ( node->is_last_in_flow() ) { - if ((node->is_repeat_flow()) && (always==false)) { - /* Flow is repeated, reschedule it */ - thread->reschedule_flow( node); - }else{ - /* Flow will not be repeated, so free node */ - thread->free_last_flow_node( node); - } - }else{ - node->update_next_pkt_in_flow(); - m_p_queue.push(node); - } + if ( type == CGenNode::STATELESS_PKT ) { + m_p_queue.pop(); + CGenNodeStateless *node_sl = (CGenNodeStateless *)node; + + /* if the stream has been deactivated - end */ + if (unlikely(!node_sl->is_active())) { + thread->free_node(node); + } else { + node_sl->handle(thread); + } + }else{ - if ((type == CGenNode::FLOW_FIF)) { - /* callback to our method */ + if ( likely( type == CGenNode::FLOW_PKT ) ) { + /* PKT */ + if ( !(node->is_repeat_flow()) || (always==false)) { + flush_one_node_to_file(node); + #ifdef _DEBUG + update_stats(node); + #endif + } m_p_queue.pop(); - if ( always == false) { - thread->m_cur_time_sec = node->m_time ; - - if ( thread->generate_flows_roundrobin(&done) <0){ - break; + if ( node->is_last_in_flow() ) { + if ((node->is_repeat_flow()) && (always==false)) { + /* Flow is repeated, reschedule it */ + thread->reschedule_flow( node); + }else{ + /* Flow will not be repeated, so free node */ + thread->free_last_flow_node( node); } - if (!done) { - node->m_time +=d_time; - m_p_queue.push(node); + }else{ + node->update_next_pkt_in_flow(); + m_p_queue.push(node); + } + }else{ + if ((type == CGenNode::FLOW_FIF)) { + /* callback to our method */ + m_p_queue.pop(); + if ( always == false) { + thread->m_cur_time_sec = node->m_time ; + + if ( thread->generate_flows_roundrobin(&done) <0){ + break; + } + if (!done) { + node->m_time +=d_time; + m_p_queue.push(node); + }else{ + thread->free_node(node); + } }else{ thread->free_node(node); } + }else{ - thread->free_node(node); + bool exit_sccheduler = handle_slow_messages(type,node,thread,always); + if (exit_sccheduler) { + break; + } } - - }else{ - handle_slow_messages(type,node,thread,always); } } } @@ -3512,17 +3541,21 @@ int CNodeGenerator::flush_file(dsec_t max_time, return (0); } -void CNodeGenerator::handle_slow_messages(uint8_t type, - CGenNode * node, - CFlowGenListPerThread * thread, - bool always){ +bool +CNodeGenerator::handle_slow_messages(uint8_t type, + CGenNode * node, + CFlowGenListPerThread * thread, + bool always){ + + /* should we continue after */ + bool exit_scheduler = false; if (unlikely (type == CGenNode::FLOW_DEFER_PORT_RELEASE) ) { m_p_queue.pop(); thread->handler_defer_job(node); thread->free_node(node); - }else{ - if (type == CGenNode::FLOW_PKT_NAT) { + + } else if (type == CGenNode::FLOW_PKT_NAT) { /*repeat and NAT is not supported */ if ( node->is_nat_first_state() ){ node->set_nat_wait_state(); @@ -3536,7 +3569,7 @@ void CNodeGenerator::handle_slow_messages(uint8_t type, m_p_queue.pop(); /* time out, need to free the flow and remove the association , we didn't get convertion yet*/ thread->terminate_nat_flows(node); - return; + return (exit_scheduler); }else{ flush_one_node_to_file(node); @@ -3556,24 +3589,39 @@ void CNodeGenerator::handle_slow_messages(uint8_t type, m_p_queue.push(node); } - }else{ - if ( type == CGenNode::FLOW_SYNC ){ - thread->check_msgs(); /* check messages */ - m_v_if->flush_tx_queue(); /* flush pkt each timeout */ - m_p_queue.pop(); - if ( always == false) { - node->m_time += SYNC_TIME_OUT; - m_p_queue.push(node); - }else{ - thread->free_node(node); - } + } else if ( type == CGenNode::FLOW_SYNC ) { - }else{ - printf(" ERROR type is not valid %d \n",type); - assert(0); + /* flow sync message is a sync point for time */ + thread->m_cur_time_sec = node->m_time; + + /* first pop the node */ + m_p_queue.pop(); + + thread->check_msgs(); /* check messages */ + m_v_if->flush_tx_queue(); /* flush pkt each timeout */ + + /* on always (clean queue path) and queue empty - exit */ + if ( always && (m_p_queue.empty()) ) { + thread->free_node(node); + exit_scheduler = true; + } else { + /* schedule for next maintenace */ + node->m_time += SYNC_TIME_OUT; + m_p_queue.push(node); } + + + } else if ( type == CGenNode::EXIT_SCHED ) { + m_p_queue.pop(); + thread->free_node(node); + exit_scheduler = true; + + } else { + printf(" ERROR type is not valid %d \n",type); + assert(0); } - } + + return exit_scheduler; } @@ -3809,11 +3857,15 @@ void CFlowGenListPerThread::handel_nat_msg(CGenNodeNatInfo * msg){ } } +void CFlowGenListPerThread::check_msgs(void) { + + /* inlined for performance */ + m_stateless_dp_info.periodic_check_for_cp_messages(); -void CFlowGenListPerThread::check_msgs(void){ - if ( likely ( m_ring_from_rx->isEmpty() ) ){ + if ( likely ( m_ring_from_rx->isEmpty() ) ) { return; } + #ifdef NAT_TRACE_ printf(" %.03f got message from RX \n",now_sec()); #endif @@ -3833,9 +3885,11 @@ void CFlowGenListPerThread::check_msgs(void){ case CGenNodeMsgBase::NAT_FIRST: handel_nat_msg((CGenNodeNatInfo * )msg); break; + case CGenNodeMsgBase::LATENCY_PKT: handel_latecy_pkt_msg((CGenNodeLatencyPktInfo *) msg); break; + default: printf("ERROR pkt-thread message type is not valid %d \n",msg_type); assert(0); @@ -3845,8 +3899,49 @@ void CFlowGenListPerThread::check_msgs(void){ } } +void delay(int msec); + -void CFlowGenListPerThread::generate_erf(std::string erf_file_name, +const uint8_t test_udp_pkt[]={ + 0x00,0x00,0x00,0x01,0x00,0x00, + 0x00,0x00,0x00,0x01,0x00,0x00, + 0x08,0x00, + + 0x45,0x00,0x00,0x81, + 0xaf,0x7e,0x00,0x00, + 0x12,0x11,0xd9,0x23, + 0x01,0x01,0x01,0x01, + 0x3d,0xad,0x72,0x1b, + + 0x11,0x11, + 0x11,0x11, + + 0x00,0x6d, + 0x00,0x00, + + 0x64,0x31,0x3a,0x61, + 0x64,0x32,0x3a,0x69,0x64, + 0x32,0x30,0x3a,0xd0,0x0e, + 0xa1,0x4b,0x7b,0xbd,0xbd, + 0x16,0xc6,0xdb,0xc4,0xbb,0x43, + 0xf9,0x4b,0x51,0x68,0x33,0x72, + 0x20,0x39,0x3a,0x69,0x6e,0x66,0x6f, + 0x5f,0x68,0x61,0x73,0x68,0x32,0x30,0x3a,0xee,0xc6,0xa3, + 0xd3,0x13,0xa8,0x43,0x06,0x03,0xd8,0x9e,0x3f,0x67,0x6f, + 0xe7,0x0a,0xfd,0x18,0x13,0x8d,0x65,0x31,0x3a,0x71,0x39, + 0x3a,0x67,0x65,0x74,0x5f,0x70,0x65,0x65,0x72,0x73,0x31, + 0x3a,0x74,0x38,0x3a,0x3d,0xeb,0x0c,0xbf,0x0d,0x6a,0x0d, + 0xa5,0x31,0x3a,0x79,0x31,0x3a,0x71,0x65,0x87,0xa6,0x7d, + 0xe7 +}; + +void CFlowGenListPerThread::start_stateless_daemon(){ + m_cur_time_sec = 0; + m_stateless_dp_info.start(); +} + + +void CFlowGenListPerThread::start_generate_stateful(std::string erf_file_name, CPreviewMode & preview){ /* now we are ready to generate*/ if ( m_cap_gen.size()==0 ){ @@ -3963,6 +4058,7 @@ int CFlowGenList::load_from_mac_file(std::string file_name) { exit(-1); } + return (0); } @@ -4435,9 +4531,12 @@ void CTupleTemplateGenerator::Generate(){ #endif +static uint32_t get_rand_32(uint32_t MinimumRange, + uint32_t MaximumRange) __attribute__ ((unused)); + +static uint32_t get_rand_32(uint32_t MinimumRange, + uint32_t MaximumRange) { -static uint32_t get_rand_32(uint32_t MinimumRange , - uint32_t MaximumRange ){ enum {RANDS_NUM = 2 , RAND_MAX_BITS = 0xf , UNSIGNED_INT_BITS = 0x20 , TWO_BITS_MASK = 0x3}; const double TWO_POWER_32_BITS = 0x10000000 * (double)0x10; @@ -4670,7 +4769,6 @@ void CCPortLatency::reset(){ static uint8_t nat_is_port_can_send(uint8_t port_id){ - uint8_t offset= ((port_id>>1)<<1); uint8_t client_index = (port_id %2); return (client_index ==0 ?1:0); } @@ -4792,7 +4890,7 @@ void CCPortLatency::dump_counters_json(std::string & json ){ } void CCPortLatency::DumpCounters(FILE *fd){ - #define DP_A1(f) if (f) fprintf(fd," %-40s : %llu \n",#f,f) + #define DP_A1(f) if (f) fprintf(fd," %-40s : %llu \n",#f, (unsigned long long)f) fprintf(fd," counter \n"); fprintf(fd," -----------\n"); @@ -4811,7 +4909,7 @@ void CCPortLatency::DumpCounters(FILE *fd){ fprintf(fd," -----------\n"); m_hist.Dump(fd); - fprintf(fd," %-40s : %llu \n","jitter",get_jitter_usec()); + fprintf(fd," %-40s : %lu \n","jitter", (ulong)get_jitter_usec()); } bool CCPortLatency::dump_packet(rte_mbuf_t * m){ @@ -4835,6 +4933,9 @@ bool CCPortLatency::dump_packet(rte_mbuf_t * m){ if ( unlikely( CGlobalInfo::m_options.preview.get_vlan_mode_enable() ) ){ vlan_offset=4; } + + (void)vlan_offset; + // utl_DumpBuffer(stdout,p,pkt_size,0); return (0); @@ -4870,9 +4971,7 @@ bool CCPortLatency::check_packet(rte_mbuf_t * m,CRx_check_header * & rx_p){ uint16_t vlan_offset=parser.m_vlan_offset; uint8_t *p=rte_pktmbuf_mtod(m, uint8_t*); - rx_p=(CRx_check_header *)0; - bool managed_by_ip_options=false; - bool is_rx_check=true; + rx_p = (CRx_check_header *)0; if ( !parser.IsLatencyPkt() ){ @@ -4989,7 +5088,7 @@ void CLatencyManager::Delete(){ static uint8_t swap_port(uint8_t port_id){ uint8_t offset= ((port_id>>1)<<1); uint8_t client_index = (port_id %2); - return (offset+client_index^1); + return (offset + (client_index ^ 1)); } @@ -5112,8 +5211,6 @@ void CLatencyManager::run_rx_queue_msgs(uint8_t thread_id, CGenNodeMsgBase * msg=(CGenNodeMsgBase *)node; - CGenNodeLatencyPktInfo * msg1=(CGenNodeLatencyPktInfo *)msg; - uint8_t msg_type = msg->m_msg_type; switch (msg_type ) { case CGenNodeMsgBase::LATENCY_PKT: @@ -5236,7 +5333,7 @@ void CLatencyManager::start(int iter){ } if ( iter>0 ){ if ( ( cnt>iter) ){ - printf("stop due iter %d %d \n",iter); + printf("stop due iter %d\n",iter); break; } } @@ -5405,8 +5502,8 @@ void CLatencyManager::DumpRxCheckVerification(FILE *fd, fprintf(fd," rx_checker is disabled \n"); return; } - fprintf(fd," rx_check Tx : %u \n",total_tx_rx_check); - fprintf(fd," rx_check Rx : %u \n",m_rx_check_manager.getTotalRx() ); + fprintf(fd," rx_check Tx : %llu \n", (unsigned long long)total_tx_rx_check); + fprintf(fd," rx_check Rx : %llu \n", (unsigned long long)m_rx_check_manager.getTotalRx() ); fprintf(fd," rx_check verification :" ); if (m_rx_check_manager.getTotalRx() == total_tx_rx_check) { fprintf(fd," OK \n" ); @@ -6659,7 +6756,6 @@ bool CSimplePacketParser::Parse(){ EthernetHeader *m_ether = (EthernetHeader *)p; IPHeader * ipv4=0; IPv6Header * ipv6=0; - uint16_t pkt_size=rte_pktmbuf_pkt_len(m); m_vlan_offset=0; m_option_offset=0; diff --git a/src/bp_sim.h b/src/bp_sim.h index b7cfb20b..36595581 100755 --- a/src/bp_sim.h +++ b/src/bp_sim.h @@ -57,6 +57,8 @@ limitations under the License. #include <arpa/inet.h> #include "platform_cfg.h" +#include <trex_stateless_dp_core.h> + #undef NAT_TRACE_ @@ -360,6 +362,25 @@ public: */ virtual int flush_tx_queue(void)=0; + + /** + * update the source and destination mac-addr of a given mbuf by global database + * + * @param dir + * @param m + * + * @return + */ + virtual int update_mac_addr_from_global_cfg(pkt_dir_t dir, rte_mbuf_t *m)=0; + + /** + * translate a port_id to the correct dir on the core + * + */ + virtual pkt_dir_t port_id_to_dir(uint8_t port_id) { + return (CS_INVALID); + } + public: @@ -721,6 +742,7 @@ public: m_run_mode = RUN_MODE_INVALID; } + CPreviewMode preview; float m_factor; float m_duration; @@ -741,9 +763,10 @@ public: uint16_t m_run_flags; uint8_t m_mac_splitter; uint8_t m_pad; - trex_run_mode_e m_run_mode; + + std::string cfg_file; std::string mac_file; std::string platform_cfg_file; @@ -778,6 +801,10 @@ public: return ( m_latency_rate == 0 ?true:false); } + bool is_stateless(){ + return (m_run_mode == RUN_MODE_INTERACTIVE ?true:false); + } + bool is_latency_enabled(){ return ( !is_latency_disabled() ); } @@ -867,6 +894,8 @@ public: /* number of main active sockets. socket #0 is always used */ virtual socket_id_t max_num_active_sockets()=0; + virtual ~CPlatformSocketInfoBase() {} + public: /* which socket to allocate memory to each port */ virtual socket_id_t port_to_socket(port_id_t port)=0; @@ -1181,12 +1210,15 @@ public: public: static CRteMemPool m_mem_pool[MAX_SOCKETS_SUPPORTED]; - static uint32_t m_nodes_pool_size; - static CParserOption m_options; - static CGlobalMemory m_memory_cfg; - static CPlatformSocketInfo m_socket; + static uint32_t m_nodes_pool_size; + static CParserOption m_options; + static CGlobalMemory m_memory_cfg; + static CPlatformSocketInfo m_socket; }; +static inline int get_is_stateless(){ + return (CGlobalInfo::m_options.is_stateless() ); +} static inline int get_is_rx_check_mode(){ return (CGlobalInfo::m_options.preview.get_is_rx_check_enable() ?1:0); @@ -1307,8 +1339,8 @@ public: -#define DP(f) if (f) printf(" %-40s: %llu \n",#f,f) -#define DP_name(n,f) if (f) printf(" %-40s: %llu \n",n,f) +#define DP(f) if (f) printf(" %-40s: %llu \n",#f,(unsigned long long)f) +#define DP_name(n,f) if (f) printf(" %-40s: %llu \n",n,(unsigned long long)f) #define DP_S(f,f_s) if (f) printf(" %-40s: %s \n",#f,f_s.c_str()) @@ -1333,15 +1365,18 @@ class CCapFileFlowInfo ; /* this is a simple struct, do not add constructor and destractor here! we are optimizing the allocation dealocation !!! */ -struct CGenNode { + +struct CGenNodeBase { public: enum { - FLOW_PKT=0, - FLOW_FIF=1, - FLOW_DEFER_PORT_RELEASE=2, - FLOW_PKT_NAT=3, - FLOW_SYNC=4 /* called evey 1 msec */ + FLOW_PKT =0, + FLOW_FIF =1, + FLOW_DEFER_PORT_RELEASE =2, + FLOW_PKT_NAT =3, + FLOW_SYNC =4, /* called evey 1 msec */ + STATELESS_PKT =5, + EXIT_SCHED =6 }; @@ -1349,7 +1384,7 @@ public: enum { NODE_FLAGS_DIR =1, NODE_FLAGS_MBUF_CACHE =2, - NODE_FLAGS_SAMPLE_RX_CHECK =4, + NODE_FLAGS_SAMPLE_RX_CHECK =4, NODE_FLAGS_LEARN_MODE =8, /* bits 3,4 MASK 0x18 wait for second direction packet */ NODE_FLAGS_LEARN_MSG_PROCESSED =0x10, /* got NAT msg */ @@ -1360,19 +1395,49 @@ public: NODE_FLAGS_INIT_START_FROM_SERVER_SIDE_SERVER_ADDR = 0x100 /* init packet start from server side with server addr */ }; + public: - /* C1 */ + /*********************************************/ + /* C1 must */ uint8_t m_type; uint8_t m_thread_id; /* zero base */ uint8_t m_socket_id; - uint8_t m_pad2; + uint8_t m_pad2; uint16_t m_src_port; uint16_t m_flags; /* BIT 0 - DIR , BIT 1 - mbug_cache BIT 2 - SAMPLE DUPLICATE */ - double m_time; + double m_time; /* can't change this header - size 16 bytes*/ + +public: + bool operator <(const CGenNodeBase * rsh ) const { + return (m_time<rsh->m_time); + } + bool operator ==(const CGenNodeBase * rsh ) const { + return (m_time==rsh->m_time); + } + bool operator >(const CGenNodeBase * rsh ) const { + return (m_time>rsh->m_time); + } + +public: + void set_socket_id(socket_id_t socket){ + m_socket_id=socket; + } + + socket_id_t get_socket_id(){ + return ( m_socket_id ); + } + + +}; + + +struct CGenNode : public CGenNodeBase { + +public: uint32_t m_src_ip; /* client ip */ uint32_t m_dest_ip; /* server ip */ @@ -1402,25 +1467,8 @@ public: uint32_t m_end_of_cache_line[6]; public: - bool operator <(const CGenNode * rsh ) const { - return (m_time<rsh->m_time); - } - bool operator ==(const CGenNode * rsh ) const { - return (m_time==rsh->m_time); - } - bool operator >(const CGenNode * rsh ) const { - return (m_time>rsh->m_time); - } -public: void Dump(FILE *fd); - void set_socket_id(socket_id_t socket){ - m_socket_id=socket; - } - - socket_id_t get_socket_id(){ - return ( m_socket_id ); - } static void DumpHeader(FILE *fd); @@ -1603,6 +1651,7 @@ public: } __rte_cache_aligned; + #if __x86_64__ /* size of 64 bytes */ #define DEFER_CLIENTS_NUM (16) @@ -1647,19 +1696,29 @@ public: need to clean this up and derive this objects from base object but require too much refactoring right now hhaim */ + +#define COMPARE_NODE_OBJECT(NODE_NAME) if ( sizeof(NODE_NAME) != sizeof(CGenNode) ) { \ + printf("ERROR sizeof(%s) %lu != sizeof(CGenNode) %lu must be the same size \n",#NODE_NAME,sizeof(NODE_NAME),sizeof(CGenNode)); \ + assert(0); \ + }\ + if ( (int)offsetof(struct NODE_NAME,m_type)!=offsetof(struct CGenNodeBase,m_type) ){\ + printf("ERROR offsetof(struct %s,m_type)!=offsetof(struct CGenNodeBase,m_type) \n",#NODE_NAME);\ + assert(0);\ + }\ + if ( (int)offsetof(struct CGenNodeDeferPort,m_time)!=offsetof(struct CGenNodeBase,m_time) ){\ + printf("ERROR offsetof(struct %s,m_time)!=offsetof(struct CGenNodeBase,m_time) \n",#NODE_NAME);\ + assert(0);\ + } + +#define COMPARE_NODE_OBJECT_SIZE(NODE_NAME) if ( sizeof(NODE_NAME) != sizeof(CGenNode) ) { \ + printf("ERROR sizeof(%s) %lu != sizeof(CGenNode) %lu must be the same size \n",#NODE_NAME,sizeof(NODE_NAME),sizeof(CGenNode)); \ + assert(0); \ + } + + + inline int check_objects_sizes(void){ - if ( sizeof(CGenNodeDeferPort) != sizeof(CGenNode) ) { - printf("ERROR sizeof(CGenNodeDeferPort) %lu != sizeof(CGenNode) %lu must be the same size \n",sizeof(CGenNodeDeferPort),sizeof(CGenNode)); - assert(0); - } - if ( (int)offsetof(struct CGenNodeDeferPort,m_type)!=offsetof(struct CGenNode,m_type) ){ - printf("ERROR offsetof(struct CGenNodeDeferPort,m_type)!=offsetof(struct CGenNode,m_type) \n"); - assert(0); - } - if ( (int)offsetof(struct CGenNodeDeferPort,m_time)!=offsetof(struct CGenNode,m_time) ){ - printf("ERROR offsetof(struct CGenNodeDeferPort,m_time)!=offsetof(struct CGenNode,m_time) \n"); - assert(0); - } + COMPARE_NODE_OBJECT(CGenNodeDeferPort); return (0); } @@ -1718,6 +1777,11 @@ public: virtual int write_pkt(CCapPktRaw *pkt_raw); virtual int close_file(void); + virtual int update_mac_addr_from_global_cfg(pkt_dir_t dir, rte_mbuf_t *m){ + return (0); + } + + /** * send one packet @@ -1779,6 +1843,10 @@ public: return (0); } + virtual int update_mac_addr_from_global_cfg(pkt_dir_t dir, rte_mbuf_t *m){ + return (0); + } + virtual int send_node(CGenNode * node); @@ -1799,6 +1867,7 @@ public: CFlowGenListPerThread * Parent(){ return (m_parent); } + public: void add_node(CGenNode * mynode); void remove_all(CFlowGenListPerThread * thread); @@ -1830,11 +1899,14 @@ public: private: - int flush_one_node_to_file(CGenNode * node); + inline int flush_one_node_to_file(CGenNode * node){ + return (m_v_if->send_node(node)); + } int update_stats(CGenNode * node); - FORCE_NO_INLINE void handle_slow_messages(uint8_t type, - CGenNode * node, - CFlowGenListPerThread * thread, + + FORCE_NO_INLINE bool handle_slow_messages(uint8_t type, + CGenNode * node, + CFlowGenListPerThread * thread, bool always); @@ -2310,6 +2382,7 @@ public: return (uint32_t)((uintptr_t)( ((char *)l3.m_ipv4)-getBasePtr()) ); }else{ BP_ASSERT(0); + return (0); } } @@ -3325,13 +3398,21 @@ public : inline CGenNode * create_node(void); + inline CGenNodeStateless * create_node_sl(void){ + return ((CGenNodeStateless*)create_node() ); + } + + inline void free_node(CGenNode *p); inline void free_last_flow_node(CGenNode *p); public: void Clean(); - void generate_erf(std::string erf_file_name,CPreviewMode &preview); + void start_generate_stateful(std::string erf_file_name,CPreviewMode &preview); + void start_stateless_daemon(); + + void Dump(FILE *fd); void DumpCsv(FILE *fd); void DumpStats(FILE *fd); @@ -3344,6 +3425,7 @@ public: private: void check_msgs(void); + void handel_nat_msg(CGenNodeNatInfo * msg); void handel_latecy_pkt_msg(CGenNodeLatencyPktInfo * msg); @@ -3421,7 +3503,12 @@ private: CNodeRing * m_ring_to_rx; /* ring dp -> latency thread */ flow_id_node_t m_flow_id_to_node_lookup; -}; + + TrexStatelessDpCore m_stateless_dp_info; + +private: + uint8_t m_cacheline_pad[RTE_CACHE_LINE_SIZE][19]; // improve prefech +} __rte_cache_aligned ; inline CGenNode * CFlowGenListPerThread::create_node(void){ CGenNode * res; diff --git a/src/common/Network/Packet/IPHeader.cpp b/src/common/Network/Packet/IPHeader.cpp index 3b90a1aa..c3363603 100755 --- a/src/common/Network/Packet/IPHeader.cpp +++ b/src/common/Network/Packet/IPHeader.cpp @@ -52,7 +52,7 @@ void IPHeader::dump(FILE *fd) { fprintf(fd, "\nIPHeader"); fprintf(fd, "\nSource 0x%.8lX, Destination 0x%.8lX, Protocol 0x%.1X", - getSourceIp(), getDestIp(), getProtocol()); + (ulong)getSourceIp(), (ulong)getDestIp(), (uint)getProtocol()); fprintf(fd, "\nTTL : %d, Id : 0x%.2X, Ver %d, Header Length %d, Total Length %d", getTimeToLive(), getId(), getVersion(), getHeaderLength(), getTotalLength()); if(isFragmented()) diff --git a/src/common/Network/Packet/TCPHeader.cpp b/src/common/Network/Packet/TCPHeader.cpp index bf28db2e..1826cef8 100755 --- a/src/common/Network/Packet/TCPHeader.cpp +++ b/src/common/Network/Packet/TCPHeader.cpp @@ -25,7 +25,7 @@ void TCPHeader::dump(FILE *fd) fprintf(fd, "\nSourcePort 0x%.4X, DestPort 0x%.4X", getSourcePort(), getDestPort()); fprintf(fd, "\nSeqNum 0x%.8lX, AckNum 0x%.8lX, Window %d", - getSeqNumber(), getAckNumber(), getWindowSize()); + (ulong)getSeqNumber(), (ulong)getAckNumber(), getWindowSize()); fprintf(fd, "\nHeader Length : %d, Checksum : 0x%.4X", getHeaderLength(), getChecksum()); fprintf(fd, "\nFlags : SYN - %d, FIN - %d, ACK - %d, URG - %d, RST - %d, PSH - %d", diff --git a/src/common/c_common.h b/src/common/c_common.h index d8320aaa..3e43644f 100755 --- a/src/common/c_common.h +++ b/src/common/c_common.h @@ -46,7 +46,7 @@ typedef void* c_pvoid; #ifdef _DEBUG #define BP_ASSERT(a) assert(a) #else - #define BP_ASSERT(a) + #define BP_ASSERT(a) (void (a)) #endif #endif diff --git a/src/gtest/rpc_test.cpp b/src/gtest/rpc_test.cpp index 250d5342..6b8e3eff 100644 --- a/src/gtest/rpc_test.cpp +++ b/src/gtest/rpc_test.cpp @@ -30,6 +30,8 @@ limitations under the License. using namespace std; +uint16_t gtest_get_mock_server_port(); + class RpcTest : public testing::Test { protected: @@ -44,7 +46,12 @@ protected: m_context = zmq_ctx_new (); m_socket = zmq_socket (m_context, ZMQ_REQ); - zmq_connect (m_socket, "tcp://localhost:5050"); + + std::stringstream ss; + ss << "tcp://localhost:"; + ss << gtest_get_mock_server_port(); + + zmq_connect (m_socket, ss.str().c_str()); } diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp index 0341516c..2bab4dff 100644 --- a/src/gtest/trex_stateless_gtest.cpp +++ b/src/gtest/trex_stateless_gtest.cpp @@ -82,7 +82,7 @@ private: void CTRexDpStreamModeSingleBurst::dump(FILE *fd){ fprintf (fd," pps : %f \n",m_pps); - fprintf (fd," total_packets : %llu \n",m_total_packets); + fprintf (fd," total_packets : %llu \n", (unsigned long long)m_total_packets); } @@ -130,9 +130,9 @@ private: void CTRexDpStreamModeMultiBurst::dump(FILE *fd){ fprintf (fd," pps : %f \n",m_pps); - fprintf (fd," total_packets : %llu \n",m_pkts_per_burst); + fprintf (fd," total_packets : %llu \n", (unsigned long long)m_pkts_per_burst); fprintf (fd," ibg : %f \n",m_ibg); - fprintf (fd," num_of_bursts : %llu \n",m_number_of_bursts); + fprintf (fd," num_of_bursts : %lu \n", (ulong)m_number_of_bursts); } diff --git a/src/gtest/tuple_gen_test.cpp b/src/gtest/tuple_gen_test.cpp index 8a774e38..f3b9fa1e 100755 --- a/src/gtest/tuple_gen_test.cpp +++ b/src/gtest/tuple_gen_test.cpp @@ -161,7 +161,6 @@ TEST(tuple_gen,clientPoolL) { 0,0); CTupleBase result; uint32_t result_src; - uint32_t result_dest; uint16_t result_port; for(int i=0;i<10;i++) { @@ -186,7 +185,6 @@ TEST(tuple_gen,clientPool) { 0,0); CTupleBase result; uint32_t result_src; - uint32_t result_dest; uint16_t result_port; for(int i=0;i<10;i++) { @@ -436,7 +434,6 @@ TEST(tuple_gen,template1) { template_1.GenerateTuple(result); uint32_t result_src = result.getClient(); uint32_t result_dest = result.getServer(); - uint16_t result_port = result.getClientPort(); //printf(" %x %x %x \n",result_src,result_dest,result_port); EXPECT_EQ(result_src, (uint32_t)(0x10000001+i)); EXPECT_EQ(result_dest, (uint32_t)(((0x12121212)) )); @@ -489,9 +486,6 @@ TEST(tuple_gen,no_free) { int i; for (i=0; i<65557; i++) { template_1.GenerateTuple(result); - uint32_t result_src = result.getClient(); - uint32_t result_dest = result.getServer(); - uint16_t result_port = result.getClientPort(); } // should have error EXPECT_TRUE((gen.getErrorAllocationCounter()>0)?true:false); @@ -514,8 +508,6 @@ TEST(tuple_gen,try_to_free) { int i; for (i=0; i<65557; i++) { template_1.GenerateTuple(result); - uint32_t result_src = result.getClient(); - uint32_t result_dest = result.getServer(); uint16_t result_port = result.getClientPort(); gen.FreePort(0,result.getClientId(),result_port); } diff --git a/src/internal_api/trex_platform_api.h b/src/internal_api/trex_platform_api.h new file mode 100644 index 00000000..5890a965 --- /dev/null +++ b/src/internal_api/trex_platform_api.h @@ -0,0 +1,134 @@ +/* + Itay Marom + Cisco Systems, Inc. +*/ + +/* +Copyright (c) 2015-2015 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef __TREX_PLATFORM_API_H__ +#define __TREX_PLATFORM_API_H__ + +#include <stdint.h> +#include <vector> + +/** + * Global stats + * + * @author imarom (06-Oct-15) + */ +class TrexPlatformGlobalStats { +public: + TrexPlatformGlobalStats() { + m_stats = {0}; + } + + struct { + double m_cpu_util; + + double m_tx_bps; + double m_rx_bps; + + double m_tx_pps; + double m_rx_pps; + + uint64_t m_total_tx_pkts; + uint64_t m_total_rx_pkts; + + uint64_t m_total_tx_bytes; + uint64_t m_total_rx_bytes; + + uint64_t m_tx_rx_errors; + } m_stats; +}; + +/** + * Per Interface stats + * + * @author imarom (26-Oct-15) + */ +class TrexPlatformInterfaceStats { + +public: + TrexPlatformInterfaceStats() { + m_stats = {0}; + } + +public: + + struct { + + double m_tx_bps; + double m_rx_bps; + + double m_tx_pps; + double m_rx_pps; + + uint64_t m_total_tx_pkts; + uint64_t m_total_rx_pkts; + + uint64_t m_total_tx_bytes; + uint64_t m_total_rx_bytes; + + uint64_t m_tx_rx_errors; + } m_stats; +}; + + +/** + * low level API interface + * can be implemented by DPDK or mock + * + * @author imarom (25-Oct-15) + */ + +class TrexPlatformApi { +public: + virtual void port_id_to_cores(uint8_t port_id, std::vector<std::pair<uint8_t, uint8_t>> &cores_id_list) const = 0; + virtual void get_global_stats(TrexPlatformGlobalStats &stats) const = 0; + virtual void get_interface_stats(uint8_t interface_id, TrexPlatformInterfaceStats &stats) const = 0; + virtual uint8_t get_dp_core_count() const = 0; + virtual ~TrexPlatformApi() {} +}; + + +/** + * DPDK implementation of the platform API + * + * @author imarom (26-Oct-15) + */ +class TrexDpdkPlatformApi : public TrexPlatformApi { +public: + void port_id_to_cores(uint8_t port_id, std::vector<std::pair<uint8_t, uint8_t>> &cores_id_list) const; + void get_global_stats(TrexPlatformGlobalStats &stats) const; + void get_interface_stats(uint8_t interface_id, TrexPlatformInterfaceStats &stats) const; + uint8_t get_dp_core_count() const; +}; + +/** + * MOCK implementation of the platform API + * + * @author imarom (26-Oct-15) + */ +class TrexMockPlatformApi : public TrexPlatformApi { +public: + void port_id_to_cores(uint8_t port_id, std::vector<std::pair<uint8_t, uint8_t>> &cores_id_list) const {} + void get_global_stats(TrexPlatformGlobalStats &stats) const; + void get_interface_stats(uint8_t interface_id, TrexPlatformInterfaceStats &stats) const; + uint8_t get_dp_core_count() const; +}; + +#endif /* __TREX_PLATFORM_API_H__ */ diff --git a/src/main.cpp b/src/main.cpp index 96789cdd..df9d8b40 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -185,25 +185,6 @@ int curent_time(){ #include <pthread.h> -void delay(int msec){ - - if (msec == 0) - {//user that requested that probebly wanted the minimal delay - //but because of scaling problem he have got 0 so we will give the min delay - //printf("\n\n\nERROR-Task delay ticks == 0 found in task %s task id = %d\n\n\n\n", - // SANB_TaskName(SANB_TaskIdSelf()), SANB_TaskIdSelf()); - msec =1; - - } - - struct timespec time1, remain; // 2 sec max delay - time1.tv_sec=msec/1000; - time1.tv_nsec=(msec - (time1.tv_sec*1000))*1000000; - - nanosleep(&time1,&remain); -} - - struct per_thread_t { pthread_t tid; }; @@ -233,11 +214,12 @@ void * thread_task(void *info){ char buf[100]; sprintf(buf,"my%d.erf",obj->thread_id); - volatile int i; - lpt->generate_erf(buf,*obj->preview_info); + lpt->start_generate_stateful(buf,*obj->preview_info); lpt->m_node_gen.DumpHist(stdout); printf("end thread %d \n",obj->thread_id); } + + return (NULL); } @@ -325,7 +307,7 @@ void test_load_list_of_cap_files(CParserOption * op){ lpt=fl.m_threads_info[i]; char buf[100]; sprintf(buf,"my%d.erf",i); - lpt->generate_erf(buf,op->preview); + lpt->start_generate_stateful(buf,op->preview); lpt->m_node_gen.DumpHist(stdout); } //sprintf(buf,"my%d.erf",7); @@ -353,7 +335,7 @@ int load_list_of_cap_files(CParserOption * op){ lpt->set_vif(&erf_vif); if ( (op->preview.getVMode() >1) || op->preview.getFileWrite() ) { - lpt->generate_erf(op->out_file,op->preview); + lpt->start_generate_stateful(op->out_file,op->preview); } lpt->m_node_gen.DumpHist(stdout); @@ -424,8 +406,6 @@ void update_tcp_seq_num(CCapFileFlowInfo * obj, int i; for (i=pkt_id+1; i<s; i++) { - uint32_t seq; - uint32_t ack; pkt=obj->GetPacket(i); tcp=pkt->m_pkt_indication.l4.m_tcp; @@ -509,7 +489,7 @@ int manipolate_capfile() { CCapFileFlowInfo flow_info; flow_info.Create(); - int res=flow_info.load_cap_file("avl/delay_10_rtsp_0.pcap",0,0); + flow_info.load_cap_file("avl/delay_10_rtsp_0.pcap",0,0); change_pkt_len(&flow_info,4-1 ,6); change_pkt_len(&flow_info,5-1 ,6); @@ -534,7 +514,7 @@ int manipolate_capfile_sip() { CCapFileFlowInfo flow_info; flow_info.Create(); - int res=flow_info.load_cap_file("avl/delay_10_sip_0.pcap",0,0); + flow_info.load_cap_file("avl/delay_10_sip_0.pcap",0,0); change_pkt_len(&flow_info,1-1 ,6+6); change_pkt_len(&flow_info,2-1 ,6+6); @@ -551,8 +531,8 @@ int manipolate_capfile_sip1() { CCapFileFlowInfo flow_info; flow_info.Create(); - int res=flow_info.load_cap_file("avl/delay_sip_0.pcap",0,0); - CFlowPktInfo * pkt=flow_info.GetPacket(1); + flow_info.load_cap_file("avl/delay_sip_0.pcap",0,0); + flow_info.GetPacket(1); change_pkt_len(&flow_info,1-1 ,6+6+10); @@ -588,7 +568,7 @@ public: void CMergeCapFileRec::Dump(FILE *fd,int _id){ - double time; + double time = 0.0; bool stop=GetCurPacket(time); fprintf (fd," id:%2d stop : %d index:%4d %3.4f \n",_id,stop?1:0,m_index,time); } @@ -639,6 +619,8 @@ bool CMergeCapFileRec::Create(std::string cap_file, m_limit_number_of_packets =0; m_start_time = pkt->m_packet->get_time() ; m_offset = offset; + + return (true); } @@ -682,12 +664,12 @@ bool CMergeCapFile::run_merge(std::string to_cap_file){ int min_index=0; double min_time; - fprintf(stdout," --------------\n",cnt); + fprintf(stdout," --------------\n"); fprintf(stdout," pkt : %d \n",cnt); for (i=0; i<MERGE_CAP_FILES; i++) { m[i].Dump(stdout,i); } - fprintf(stdout," --------------\n",cnt); + fprintf(stdout," --------------\n"); bool valid = false; for (i=0; i<MERGE_CAP_FILES; i++) { @@ -721,6 +703,8 @@ bool CMergeCapFile::run_merge(std::string to_cap_file){ }; m_results.save_to_erf(to_cap_file,1); + + return (true); } diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp index a0af9fdf..c4ecb97d 100755 --- a/src/main_dpdk.cpp +++ b/src/main_dpdk.cpp @@ -55,7 +55,10 @@ limitations under the License. #include <common/arg/SimpleGlob.h> #include <common/arg/SimpleOpt.h> #include <common/basic_utils.h> + #include <stateless/cp/trex_stateless.h> +#include <stateless/dp/trex_stream_node.h> + #include <../linux_dpdk/version.h> extern "C" { @@ -73,6 +76,7 @@ extern "C" { #include "msg_manager.h" #include "platform_cfg.h" +#include <internal_api/trex_platform_api.h> #define RX_CHECK_MIX_SAMPLE_RATE 8 #define RX_CHECK_MIX_SAMPLE_RATE_1G 2 @@ -104,8 +108,6 @@ extern "C" int vmxnet3_xmit_set_callback(rte_mbuf_convert_to_one_seg_t cb); #define RTE_TEST_TX_DESC_DEFAULT 512 #define RTE_TEST_RX_DESC_DROP 0 - - static inline int get_vm_one_queue_enable(){ return (CGlobalInfo::m_options.preview.get_vm_one_queue_enable() ?1:0); } @@ -686,12 +688,13 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t CSimpleOpt args(argc, argv, parser_options); bool latency_was_set=false; + (void)latency_was_set; + int a=0; int node_dump=0; po->preview.setFileWrite(true); po->preview.setRealTime(true); - int res1; uint32_t tmp_data; po->m_run_mode = CParserOption::RUN_MODE_INVALID; @@ -928,40 +931,30 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t } } - return 0; -} - - -int main_test(int argc , char * argv[]); - - - - -void delay(int msec){ - - if (msec == 0) - {//user that requested that probebly wanted the minimal delay - //but because of scaling problem he have got 0 so we will give the min delay - //printf("\n\n\nERROR-Task delay ticks == 0 found in task %s task id = %d\n\n\n\n", - // SANB_TaskName(SANB_TaskIdSelf()), SANB_TaskIdSelf()); - msec =1; + if ( get_is_stateless() ) { + if ( po->preview.get_is_rx_check_enable() ) { + parse_err("Rx check is not supported with interactive mode "); + } - } + if ( (! po->is_latency_disabled()) || (po->preview.getOnlyLatency()) ){ + parse_err("Latecny check is not supported with interactive mode "); + } - struct timespec time1, remain; // 2 sec max delay - time1.tv_sec=msec/1000; - time1.tv_nsec=(msec - (time1.tv_sec*1000))*1000000; + if ( po->preview.getSingleCore() ){ + parse_err("single core is not supported with interactive mode "); + } - nanosleep(&time1,&remain); + } + return 0; } - -static const char * default_argv[] = {"xx","-c", "0x7", "-n","2","-b","0000:0b:01.01"}; -static int argv_num = 7; - +int main_test(int argc , char * argv[]); +//static const char * default_argv[] = {"xx","-c", "0x7", "-n","2","-b","0000:0b:01.01"}; +//static int argv_num = 7; + #define RX_PTHRESH 8 /**< Default values of RX prefetch threshold reg. */ @@ -1145,8 +1138,8 @@ void CPhyEthIFStats::Clear(){ void CPhyEthIFStats::DumpAll(FILE *fd){ - #define DP_A4(f) printf(" %-40s : %llu \n",#f,f) - #define DP_A(f) if (f) printf(" %-40s : %llu \n",#f,f) + #define DP_A4(f) printf(" %-40s : %llu \n",#f, (unsigned long long)f) + #define DP_A(f) if (f) printf(" %-40s : %llu \n",#f, (unsigned long long)f) DP_A4(opackets); DP_A4(obytes); DP_A4(ipackets); @@ -1185,7 +1178,7 @@ public: m_port_id = portid; m_last_rx_rate = 0.0; m_last_tx_rate = 0.0; - m_last_pps=0.0; + m_last_tx_pps = 0.0; return (true); } void Delete(); @@ -1261,8 +1254,12 @@ public: return (m_last_rx_rate); } - float get_last_pps_rate(){ - return (m_last_pps); + float get_last_tx_pps_rate(){ + return (m_last_tx_pps); + } + + float get_last_rx_pps_rate(){ + return (m_last_rx_pps); } CPhyEthIFStats & get_stats(){ @@ -1315,12 +1312,14 @@ private: CBwMeasure m_bw_tx; CBwMeasure m_bw_rx; CPPSMeasure m_pps_tx; + CPPSMeasure m_pps_rx; CPhyEthIFStats m_stats; - float m_last_rx_rate; float m_last_tx_rate; - float m_last_pps; + float m_last_rx_rate; + float m_last_tx_pps; + float m_last_rx_pps; public: struct rte_eth_dev_info m_dev_info; }; @@ -1615,10 +1614,6 @@ void CPhyEthIF::macaddr_get(struct ether_addr *mac_addr){ void CPhyEthIF::get_stats_1g(CPhyEthIFStats *stats){ - int i; - uint64_t t=0; - - stats->ipackets += pci_reg_read(E1000_GPRC) ; stats->ibytes += (pci_reg_read(E1000_GORCL) ); @@ -1656,7 +1651,8 @@ void CPhyEthIF::get_stats_1g(CPhyEthIFStats *stats){ m_last_tx_rate = m_bw_tx.add(stats->obytes); m_last_rx_rate = m_bw_rx.add(stats->ibytes); - m_last_pps = m_pps_tx.add(stats->opackets); + m_last_tx_pps = m_pps_tx.add(stats->opackets); + m_last_rx_pps = m_pps_rx.add(stats->ipackets); } @@ -1666,14 +1662,15 @@ void CPhyEthIF::get_stats(CPhyEthIFStats *stats){ m_last_tx_rate = m_bw_tx.add(stats->obytes); m_last_rx_rate = m_bw_rx.add(stats->ibytes); - m_last_pps = m_pps_tx.add(stats->opackets); + m_last_tx_pps = m_pps_tx.add(stats->opackets); + m_last_rx_pps = m_pps_rx.add(stats->ipackets); } void dump_hw_state(FILE *fd,struct ixgbe_hw_stats *hs ){ - #define DP_A1(f) if (hs->f) fprintf(fd," %-40s : %llu \n",#f,hs->f) - #define DP_A2(f,m) for (i=0;i<m; i++) { if (hs->f[i]) fprintf(fd," %-40s[%d] : %llu \n",#f,i,hs->f[i]); } + #define DP_A1(f) if (hs->f) fprintf(fd," %-40s : %llu \n",#f, (unsigned long long)hs->f) + #define DP_A2(f,m) for (i=0;i<m; i++) { if (hs->f[i]) fprintf(fd," %-40s[%d] : %llu \n",#f,i, (unsigned long long)hs->f[i]); } int i; //for (i=0;i<8; i++) { if (hs->mpc[i]) fprintf(fd," %-40s[%d] : %llu \n","mpc",i,hs->mpc[i]); } @@ -1855,6 +1852,9 @@ public: bool process_rx_pkt(pkt_dir_t dir,rte_mbuf_t * m); + virtual int update_mac_addr_from_global_cfg(pkt_dir_t dir, rte_mbuf_t *m); + + virtual pkt_dir_t port_id_to_dir(uint8_t port_id); public: void GetCoreCounters(CVirtualIFPerSideStats *stats); @@ -1867,7 +1867,11 @@ public: return ( CGlobalInfo::m_socket.port_to_socket( m_ports[0].m_port->get_port_id() ) ); } -private: + const CCorePerPort * get_ports() { + return m_ports; + } + +protected: int send_burst(CCorePerPort * lp_port, uint16_t len, @@ -1878,13 +1882,21 @@ private: -private: +protected: uint8_t m_core_id; uint16_t m_mbuf_cache; CCorePerPort m_ports[CS_NUM]; /* each core has 2 tx queues 1. client side and server side */ CNodeRing * m_ring_to_rx; + +} __rte_cache_aligned; ; + +class CCoreEthIFStateless : public CCoreEthIF { +public: + virtual int send_node(CGenNode * node); }; + + bool CCoreEthIF::Create(uint8_t core_id, uint16_t tx_client_queue_id, CPhyEthIF * tx_client_port, @@ -1985,6 +1997,7 @@ void CCoreEthIF::flush_rx_queue(void){ } } + int CCoreEthIF::flush_tx_queue(void){ /* flush both sides */ pkt_dir_t dir ; @@ -2084,6 +2097,8 @@ int CCoreEthIF::send_burst(CCorePerPort * lp_port, rte_pktmbuf_free(m); } } + + return (0); } @@ -2104,6 +2119,8 @@ int CCoreEthIF::send_pkt(CCorePerPort * lp_port, len = 0; } lp_port->m_len = len; + + return (0); } @@ -2140,6 +2157,23 @@ void CCoreEthIF::update_mac_addr(CGenNode * node,uint8_t *p){ } + +int CCoreEthIFStateless::send_node(CGenNode * no){ + CGenNodeStateless * node_sl=(CGenNodeStateless *) no; + + /* check that we have mbuf */ + rte_mbuf_t * m=node_sl->get_cache_mbuf(); + assert( m ); + pkt_dir_t dir=(pkt_dir_t)node_sl->get_mbuf_cache_dir(); + CCorePerPort * lp_port=&m_ports[dir]; + CVirtualIFPerSideStats * lp_stats = &m_stats[dir]; + rte_pktmbuf_refcnt_update(m,1); + send_pkt(lp_port,m,lp_stats); + return (0); +}; + + + int CCoreEthIF::send_node(CGenNode * node){ if ( unlikely( node->get_cache_mbuf() !=NULL ) ) { @@ -2233,6 +2267,29 @@ int CCoreEthIF::send_node(CGenNode * node){ } +int CCoreEthIF::update_mac_addr_from_global_cfg(pkt_dir_t dir, + rte_mbuf_t *m){ + assert(m); + assert(dir<2); + CCorePerPort * lp_port=&m_ports[dir]; + uint8_t *p=rte_pktmbuf_mtod(m, uint8_t*); + uint8_t p_id=lp_port->m_port->get_port_id(); + + memcpy(p,CGlobalInfo::m_options.get_dst_src_mac_addr(p_id),12); + return (0); +} + +pkt_dir_t +CCoreEthIF::port_id_to_dir(uint8_t port_id) { + + for (pkt_dir_t dir = 0; dir < CS_NUM; dir++) { + if (m_ports[dir].m_port->get_port_id() == port_id) { + return dir; + } + } + + return (CS_INVALID); +} class CLatencyHWPort : public CPortLatencyHWBase { public: @@ -2420,6 +2477,10 @@ public: uint64_t oerrors; float m_total_tx_bps; + float m_total_tx_pps; + + float m_total_rx_bps; + float m_total_rx_pps; }; class CGlobalStats { @@ -2456,6 +2517,7 @@ public: float m_tx_bps; float m_rx_bps; float m_tx_pps; + float m_rx_pps; float m_tx_cps; float m_tx_expected_cps; float m_tx_expected_pps; @@ -2488,7 +2550,7 @@ std::string CGlobalStats::get_field(std::string name,float &f){ std::string CGlobalStats::get_field(std::string name,uint64_t &f){ char buff[200]; - sprintf(buff,"\"%s\":%llu,",name.c_str(),f); + sprintf(buff,"\"%s\":%llu,",name.c_str(), (unsigned long long)f); return (std::string(buff)); } @@ -2500,7 +2562,7 @@ std::string CGlobalStats::get_field_port(int port,std::string name,float &f){ std::string CGlobalStats::get_field_port(int port,std::string name,uint64_t &f){ char buff[200]; - sprintf(buff,"\"%s-%d\":%llu,",name.c_str(),port,f); + sprintf(buff,"\"%s-%d\":%llu,",name.c_str(),port, (unsigned long long)f); return (std::string(buff)); } @@ -2516,6 +2578,7 @@ void CGlobalStats::dump_json(std::string & json){ json+=GET_FIELD(m_tx_bps); json+=GET_FIELD(m_rx_bps); json+=GET_FIELD(m_tx_pps); + json+=GET_FIELD(m_rx_pps); json+=GET_FIELD(m_tx_cps); json+=GET_FIELD(m_tx_expected_cps); json+=GET_FIELD(m_tx_expected_pps); @@ -2550,6 +2613,9 @@ void CGlobalStats::dump_json(std::string & json){ json+=GET_FIELD_PORT(i,ierrors) ; json+=GET_FIELD_PORT(i,oerrors) ; json+=GET_FIELD_PORT(i,m_total_tx_bps); + json+=GET_FIELD_PORT(i,m_total_tx_pps); + json+=GET_FIELD_PORT(i,m_total_rx_bps); + json+=GET_FIELD_PORT(i,m_total_rx_pps); } json+=m_template.dump_as_json("template"); json+="\"unknown\":0}}" ; @@ -2569,7 +2635,7 @@ void CGlobalStats::DumpAllPorts(FILE *fd){ fprintf (fd," Platform_factor : %2.1f \n",m_platform_factor); fprintf (fd," Total-Tx : %s ",double_to_human_str(m_tx_bps,"bps",KBYE_1000).c_str()); if ( CGlobalInfo::is_learn_mode() ) { - fprintf (fd," Nat_time_out : %8llu \n",m_total_nat_time_out); + fprintf (fd," Nat_time_out : %8llu \n", (unsigned long long)m_total_nat_time_out); }else{ fprintf (fd,"\n"); } @@ -2577,49 +2643,52 @@ void CGlobalStats::DumpAllPorts(FILE *fd){ fprintf (fd," Total-Rx : %s ",double_to_human_str(m_rx_bps,"bps",KBYE_1000).c_str()); if ( CGlobalInfo::is_learn_mode() ) { - fprintf (fd," Nat_no_fid : %8llu \n",m_total_nat_no_fid); + fprintf (fd," Nat_no_fid : %8llu \n", (unsigned long long)m_total_nat_no_fid); }else{ fprintf (fd,"\n"); } fprintf (fd," Total-PPS : %s ",double_to_human_str(m_tx_pps,"pps",KBYE_1000).c_str()); if ( CGlobalInfo::is_learn_mode() ) { - fprintf (fd," Total_nat_active: %8llu \n",m_total_nat_active); + fprintf (fd," Total_nat_active: %8llu \n", (unsigned long long)m_total_nat_active); }else{ fprintf (fd,"\n"); } fprintf (fd," Total-CPS : %s ",double_to_human_str(m_tx_cps,"cps",KBYE_1000).c_str()); if ( CGlobalInfo::is_learn_mode() ) { - fprintf (fd," Total_nat_open : %8llu \n",m_total_nat_open); + fprintf (fd," Total_nat_open : %8llu \n", (unsigned long long)m_total_nat_open); }else{ fprintf (fd,"\n"); } fprintf (fd,"\n"); fprintf (fd," Expected-PPS : %s ",double_to_human_str(m_tx_expected_pps,"pps",KBYE_1000).c_str()); if ( CGlobalInfo::is_learn_verify_mode() ) { - fprintf (fd," Nat_learn_errors: %8llu \n",m_total_nat_learn_error); + fprintf (fd," Nat_learn_errors: %8llu \n", (unsigned long long)m_total_nat_learn_error); }else{ fprintf (fd,"\n"); } fprintf (fd," Expected-CPS : %s \n",double_to_human_str(m_tx_expected_cps,"cps",KBYE_1000).c_str()); fprintf (fd," Expected-BPS : %s \n",double_to_human_str(m_tx_expected_bps,"bps",KBYE_1000).c_str()); fprintf (fd,"\n"); - fprintf (fd," Active-flows : %8llu Clients : %8llu Socket-util : %3.4f %% \n",(uint64_t)m_active_flows,m_total_clients,m_socket_util); + fprintf (fd," Active-flows : %8llu Clients : %8llu Socket-util : %3.4f %% \n", + (unsigned long long)m_active_flows, + (unsigned long long)m_total_clients, + m_socket_util); fprintf (fd," Open-flows : %8llu Servers : %8llu Socket : %8llu Socket/Clients : %.1f \n", - (uint64_t)m_open_flows, - m_total_servers, - m_active_sockets, + (unsigned long long)m_open_flows, + (unsigned long long)m_total_servers, + (unsigned long long)m_active_sockets, (float)m_active_sockets/(float)m_total_clients); if (m_total_alloc_error) { - fprintf (fd," Total_alloc_err : %llu \n",(uint64_t)m_total_alloc_error); + fprintf (fd," Total_alloc_err : %llu \n", (unsigned long long)m_total_alloc_error); } if ( m_total_queue_full ){ - fprintf (fd," Total_queue_full : %llu \n",(uint64_t)m_total_queue_full); + fprintf (fd," Total_queue_full : %llu \n", (unsigned long long)m_total_queue_full); } if (m_total_queue_drop) { - fprintf (fd," Total_queue_drop : %llu \n",(uint64_t)m_total_queue_drop); + fprintf (fd," Total_queue_drop : %llu \n", (unsigned long long)m_total_queue_drop); } //m_template.Dump(fd); @@ -2643,8 +2712,8 @@ void CGlobalStats::Dump(FILE *fd,DumpFormat mode){ CPerPortStats * lp=&m_port[i]; fprintf(fd,"port : %d \n",(int)i); fprintf(fd,"------------\n"); - #define GS_DP_A4(f) fprintf(fd," %-40s : %llu \n",#f,lp->f) - #define GS_DP_A(f) if (lp->f) fprintf(fd," %-40s : %llu \n",#f,lp->f) + #define GS_DP_A4(f) fprintf(fd," %-40s : %llu \n",#f, (unsigned long long)lp->f) + #define GS_DP_A(f) if (lp->f) fprintf(fd," %-40s : %llu \n",#f, (unsigned long long)lp->f) GS_DP_A4(opackets); GS_DP_A4(obytes); GS_DP_A4(ipackets); @@ -2719,10 +2788,10 @@ void CGlobalStats::Dump(FILE *fd,DumpFormat mode){ -struct CGlobalPortCfg { +struct CGlobalTRex { public: - CGlobalPortCfg (){ + CGlobalTRex (){ m_max_ports=4; m_max_cores=1; m_cores_to_dual_ports=0; @@ -2732,10 +2801,11 @@ public: m_expected_pps=0.0; m_expected_cps=0.0; m_expected_bps=0.0; + m_trex_stateless = NULL; } public: - bool Create(bool is_stateless); + bool Create(); void Delete(); int ixgbe_prob_init(); @@ -2754,6 +2824,8 @@ public: public: int start_send_master(); + int start_master_stateless(); + int run_in_core(virtual_thread_id_t virt_core_id); int stop_core(virtual_thread_id_t virt_core_id); @@ -2800,7 +2872,6 @@ public: - int test_send1(); int rcv_send(int port,int queue_id); int rcv_send_all(int queue_id); @@ -2866,7 +2937,9 @@ public: CPhyEthIF m_ports[BP_MAX_PORTS]; - CCoreEthIF m_cores_vif[BP_MAX_CORES]; /* counted from 1 , 2,3 core zero is reserve*/ + CCoreEthIF m_cores_vif_sf[BP_MAX_CORES]; /* counted from 1 , 2,3 core zero is reserve - stateful */ + CCoreEthIFStateless m_cores_vif_sl[BP_MAX_CORES]; /* counted from 1 , 2,3 core zero is reserve - stateless*/ + CCoreEthIF * m_cores_vif[BP_MAX_CORES]; CParserOption m_po ; @@ -2889,54 +2962,14 @@ private: CLatencyPktInfo m_latency_pkt; CZMqPublisher m_zmq_publisher; -}; - - -int CGlobalPortCfg::test_send1(){ - - CParserOption po ; - CFlowGenList fl; - - po.cfg_file = "cap2/dns.yaml"; - //po.cfg_file = "cap2/sfr3.yaml"; - //po.cfg_file = "cap2/sfr4.yaml"; - //po.cfg_file = "cap2/sfr.yaml"; - - po.preview.setVMode(3); - po.preview.setFileWrite(true); - - fl.Create(); - - fl.load_from_yaml(po.cfg_file,1); - //fl.DumpPktSize(); - - fl.generate_p_thread_info(1); - CFlowGenListPerThread * lpt; - - int i; - for (i=0; i<1; i++) { - lpt = fl.m_threads_info[i]; - //CNullIF * erf_vif = new CNullIF(); - CVirtualIF * erf_vif = &m_cores_vif[0]; - lpt->set_vif(erf_vif); - lpt->generate_erf("hey",po.preview); - lpt->m_node_gen.DumpHist(stdout); - lpt->DumpStats(stdout); - } +public: + TrexStateless *m_trex_stateless; +}; - m_cores_vif[0].flush_tx_queue(); - delay(1000); - //fprintf(stdout," drop : %llu \n",m_test_drop); - m_cores_vif[0].DumpCoreStats(stdout); - m_cores_vif[0].DumpIfStats(stdout); - fl.Delete(); -} - - -int CGlobalPortCfg::rcv_send(int port,int queue_id){ +int CGlobalTRex::rcv_send(int port,int queue_id){ CPhyEthIF * lp=&m_ports[port]; rte_mbuf_t * rx_pkts[32]; @@ -2955,7 +2988,7 @@ int CGlobalPortCfg::rcv_send(int port,int queue_id){ return (0); } -int CGlobalPortCfg::rcv_send_all(int queue_id){ +int CGlobalTRex::rcv_send_all(int queue_id){ int i; for (i=0; i<m_max_ports; i++) { rcv_send(i,queue_id); @@ -2966,16 +2999,16 @@ int CGlobalPortCfg::rcv_send_all(int queue_id){ -int CGlobalPortCfg::test_send(){ +int CGlobalTRex::test_send(){ int i; - CPhyEthIF * lp=&m_ports[0]; - //set_promisc_all(true); //create_sctp_pkt(); create_udp_pkt(); CRx_check_header rx_check_header; + (void)rx_check_header; + rx_check_header.m_time_stamp=0x1234567; rx_check_header.m_option_type=RX_CHECK_V4_OPT_TYPE; rx_check_header.m_option_len=RX_CHECK_V4_OPT_LEN; @@ -3049,7 +3082,7 @@ int CGlobalPortCfg::test_send(){ }*/ #endif - fprintf(stdout," drop : %llu \n",m_test_drop); + fprintf(stdout," drop : %llu \n", (unsigned long long)m_test_drop); return (0); } @@ -3118,7 +3151,7 @@ const uint8_t sctp_pkt1[]={ -int CGlobalPortCfg::create_pkt(uint8_t *pkt,int pkt_size){ +int CGlobalTRex::create_pkt(uint8_t *pkt,int pkt_size){ rte_mempool_t * mp= CGlobalInfo::m_mem_pool[0].m_big_mbuf_pool ; rte_mbuf_t * m=rte_pktmbuf_alloc(mp); @@ -3138,17 +3171,17 @@ int CGlobalPortCfg::create_pkt(uint8_t *pkt,int pkt_size){ return (0); } -int CGlobalPortCfg::create_udp_pkt(){ +int CGlobalTRex::create_udp_pkt(){ return (create_pkt((uint8_t*)udp_pkt,sizeof(udp_pkt))); } -int CGlobalPortCfg::create_sctp_pkt(){ +int CGlobalTRex::create_sctp_pkt(){ return (create_pkt((uint8_t*)sctp_pkt1,sizeof(sctp_pkt1))); } /* test by sending 10 packets ...*/ -int CGlobalPortCfg::test_send_pkts(uint16_t queue_id, +int CGlobalTRex::test_send_pkts(uint16_t queue_id, int pkt, int port){ @@ -3174,26 +3207,30 @@ int CGlobalPortCfg::test_send_pkts(uint16_t queue_id, -int CGlobalPortCfg::set_promisc_all(bool enable){ +int CGlobalTRex::set_promisc_all(bool enable){ int i; for (i=0; i<m_max_ports; i++) { CPhyEthIF * _if=&m_ports[i]; _if->set_promiscuous(enable); } + + return (0); } -int CGlobalPortCfg::reset_counters(){ +int CGlobalTRex::reset_counters(){ int i; for (i=0; i<m_max_ports; i++) { CPhyEthIF * _if=&m_ports[i]; _if->stats_clear(); } + + return (0); } -bool CGlobalPortCfg::is_all_links_are_up(bool dump){ +bool CGlobalTRex::is_all_links_are_up(bool dump){ bool all_link_are=true; int i; for (i=0; i<m_max_ports; i++) { @@ -3212,7 +3249,7 @@ bool CGlobalPortCfg::is_all_links_are_up(bool dump){ -int CGlobalPortCfg::ixgbe_rx_queue_flush(){ +int CGlobalTRex::ixgbe_rx_queue_flush(){ int i; for (i=0; i<m_max_ports; i++) { CPhyEthIF * _if=&m_ports[i]; @@ -3222,7 +3259,7 @@ int CGlobalPortCfg::ixgbe_rx_queue_flush(){ } -int CGlobalPortCfg::ixgbe_configure_mg(void){ +int CGlobalTRex::ixgbe_configure_mg(void){ int i; CLatencyManagerCfg mg_cfg; mg_cfg.m_max_ports = m_max_ports; @@ -3262,10 +3299,12 @@ int CGlobalPortCfg::ixgbe_configure_mg(void){ m_mg.Create(&mg_cfg); m_mg.set_mask(CGlobalInfo::m_options.m_latency_mask); + + return (0); } -int CGlobalPortCfg::ixgbe_start(void){ +int CGlobalTRex::ixgbe_start(void){ int i; for (i=0; i<m_max_ports; i++) { @@ -3384,11 +3423,15 @@ int CGlobalPortCfg::ixgbe_start(void){ */ int port_offset=0; - int queue_offset=0; for (i=0; i<get_cores_tx(); i++) { int j=(i+1); int queue_id=((j-1)/get_base_num_cores() ); /* for the first min core queue 0 , then queue 1 etc */ - m_cores_vif[j].Create(j, + if ( get_is_stateless() ){ + m_cores_vif[j]=&m_cores_vif_sl[j]; + }else{ + m_cores_vif[j]=&m_cores_vif_sf[j]; + } + m_cores_vif[j]->Create(j, queue_id, &m_ports[port_offset], /* 0,2*/ queue_id, @@ -3403,28 +3446,39 @@ int CGlobalPortCfg::ixgbe_start(void){ fprintf(stdout," -------------------------------\n"); CCoreEthIF::DumpIfCfgHeader(stdout); for (i=0; i<get_cores_tx(); i++) { - m_cores_vif[i+1].DumpIfCfg(stdout); + m_cores_vif[i+1]->DumpIfCfg(stdout); } fprintf(stdout," -------------------------------\n"); + + return (0); } -bool CGlobalPortCfg::Create(bool is_stateless){ +bool CGlobalTRex::Create(){ + CFlowsYamlInfo pre_yaml_info; - /* hack - need to refactor */ - if (!is_stateless) { - if ( !m_zmq_publisher.Create( CGlobalInfo::m_options.m_zmq_port, - !CGlobalInfo::m_options.preview.get_zmq_publish_enable() ) ){ - return (false); - } + if (get_is_stateless()) { + + TrexStatelessCfg cfg; + + TrexRpcServerConfig rpc_req_resp_cfg(TrexRpcServerConfig::RPC_PROT_TCP, global_platform_cfg_info.m_zmq_rpc_port); + + cfg.m_port_count = CGlobalInfo::m_options.m_expected_portd; + cfg.m_rpc_req_resp_cfg = &rpc_req_resp_cfg; + cfg.m_rpc_async_cfg = NULL; + cfg.m_rpc_server_verbose = false; + cfg.m_platform_api = new TrexDpdkPlatformApi(); + + m_trex_stateless = new TrexStateless(cfg); + + } else { + pre_yaml_info.load_from_yaml_file(CGlobalInfo::m_options.cfg_file); } - /* We load the YAML twice, - this is the first time. to update global flags */ - CFlowsYamlInfo pre_yaml_info; - if (!is_stateless) { - pre_yaml_info.load_from_yaml_file(CGlobalInfo::m_options.cfg_file); - } + if ( !m_zmq_publisher.Create( CGlobalInfo::m_options.m_zmq_port, + !CGlobalInfo::m_options.preview.get_zmq_publish_enable() ) ){ + return (false); + } if ( pre_yaml_info.m_vlan_info.m_enable ){ CGlobalInfo::m_options.preview.set_vlan_mode_enable(true); @@ -3434,16 +3488,17 @@ bool CGlobalPortCfg::Create(bool is_stateless){ ixgbe_prob_init(); cores_prob_init(); queues_prob_init(); - /* allocate rings */ - assert( CMsgIns::Ins()->Create(get_cores_tx()) ); - if ( sizeof(CGenNodeNatInfo) != sizeof(CGenNode) ) { - printf("ERROR sizeof(CGenNodeNatInfo) %d != sizeof(CGenNode) %d must be the same size \n",sizeof(CGenNodeNatInfo),sizeof(CGenNode)); - assert(0); - } + /* allocate rings */ + assert( CMsgIns::Ins()->Create(get_cores_tx()) ); + + if ( sizeof(CGenNodeNatInfo) != sizeof(CGenNode) ) { + printf("ERROR sizeof(CGenNodeNatInfo) %lu != sizeof(CGenNode) %lu must be the same size \n",sizeof(CGenNodeNatInfo),sizeof(CGenNode)); + assert(0); + } if ( sizeof(CGenNodeLatencyPktInfo) != sizeof(CGenNode) ) { - printf("ERROR sizeof(CGenNodeLatencyPktInfo) %d != sizeof(CGenNode) %d must be the same size \n",sizeof(CGenNodeLatencyPktInfo),sizeof(CGenNode)); + printf("ERROR sizeof(CGenNodeLatencyPktInfo) %lu != sizeof(CGenNode) %lu must be the same size \n",sizeof(CGenNodeLatencyPktInfo),sizeof(CGenNode)); assert(0); } @@ -3463,16 +3518,13 @@ bool CGlobalPortCfg::Create(bool is_stateless){ return (true); } -void CGlobalPortCfg::Delete(){ +void CGlobalTRex::Delete(){ m_zmq_publisher.Delete(); } -int CGlobalPortCfg::ixgbe_prob_init(void){ - - uint8_t nb_ports; - +int CGlobalTRex::ixgbe_prob_init(void){ m_max_ports = rte_eth_dev_count(); if (m_max_ports == 0) @@ -3561,13 +3613,13 @@ int CGlobalPortCfg::ixgbe_prob_init(void){ return (0); } -int CGlobalPortCfg::cores_prob_init(){ +int CGlobalTRex::cores_prob_init(){ m_max_cores = rte_lcore_count(); assert(m_max_cores>0); return (0); } -int CGlobalPortCfg::queues_prob_init(){ +int CGlobalTRex::queues_prob_init(){ if (m_max_cores < 2) { rte_exit(EXIT_FAILURE, "number of cores should be at least 3 \n"); @@ -3608,7 +3660,7 @@ int CGlobalPortCfg::queues_prob_init(){ } -void CGlobalPortCfg::dump_config(FILE *fd){ +void CGlobalTRex::dump_config(FILE *fd){ fprintf(fd," number of ports : %u \n",m_max_ports); fprintf(fd," max cores for 2 ports : %u \n",m_cores_to_dual_ports); fprintf(fd," max queue per port : %u \n",m_max_queues_per_port); @@ -3616,7 +3668,7 @@ void CGlobalPortCfg::dump_config(FILE *fd){ -void CGlobalPortCfg::dump_post_test_stats(FILE *fd){ +void CGlobalTRex::dump_post_test_stats(FILE *fd){ uint64_t pkt_out=0; uint64_t pkt_out_bytes=0; uint64_t pkt_in_bytes=0; @@ -3627,7 +3679,7 @@ void CGlobalPortCfg::dump_post_test_stats(FILE *fd){ int i; for (i=0; i<get_cores_tx(); i++) { - CCoreEthIF * erf_vif = &m_cores_vif[i+1]; + CCoreEthIF * erf_vif = m_cores_vif[i+1]; CVirtualIFPerSideStats stats; erf_vif->GetCoreCounters(&stats); sw_pkt_out += stats.m_tx_pkt; @@ -3652,17 +3704,17 @@ void CGlobalPortCfg::dump_post_test_stats(FILE *fd){ fprintf (fd," summary stats \n"); fprintf (fd," -------------- \n"); - fprintf (fd," Total-pkt-drop : %d pkts \n",(int64_t)(pkt_out-pkt_in)); - fprintf (fd," Total-tx-bytes : %llu bytes \n",pkt_out_bytes); - fprintf (fd," Total-tx-sw-bytes : %llu bytes \n",sw_pkt_out_bytes); - fprintf (fd," Total-rx-bytes : %llu byte \n",pkt_in_bytes); + fprintf (fd," Total-pkt-drop : %llu pkts \n",(unsigned long long)(pkt_out-pkt_in)); + fprintf (fd," Total-tx-bytes : %llu bytes \n", (unsigned long long)pkt_out_bytes); + fprintf (fd," Total-tx-sw-bytes : %llu bytes \n", (unsigned long long)sw_pkt_out_bytes); + fprintf (fd," Total-rx-bytes : %llu byte \n", (unsigned long long)pkt_in_bytes); fprintf (fd," \n"); - fprintf (fd," Total-tx-pkt : %llu pkts \n",pkt_out); - fprintf (fd," Total-rx-pkt : %llu pkts \n",pkt_in); - fprintf (fd," Total-sw-tx-pkt : %llu pkts \n",sw_pkt_out); - fprintf (fd," Total-sw-err : %llu pkts \n",sw_pkt_out_err); + fprintf (fd," Total-tx-pkt : %llu pkts \n", (unsigned long long)pkt_out); + fprintf (fd," Total-rx-pkt : %llu pkts \n", (unsigned long long)pkt_in); + fprintf (fd," Total-sw-tx-pkt : %llu pkts \n", (unsigned long long)sw_pkt_out); + fprintf (fd," Total-sw-err : %llu pkts \n", (unsigned long long)sw_pkt_out_err); if ( !CGlobalInfo::m_options.is_latency_disabled() ){ @@ -3675,7 +3727,7 @@ void CGlobalPortCfg::dump_post_test_stats(FILE *fd){ } -void CGlobalPortCfg::update_stats(){ +void CGlobalTRex::update_stats(){ int i; for (i=0; i<m_max_ports; i++) { @@ -3696,12 +3748,13 @@ void CGlobalPortCfg::update_stats(){ } -void CGlobalPortCfg::get_stats(CGlobalStats & stats){ +void CGlobalTRex::get_stats(CGlobalStats & stats){ int i; float total_tx=0.0; float total_rx=0.0; - float total_pps=0.0; + float total_tx_pps=0.0; + float total_rx_pps=0.0; stats.m_total_tx_pkts = 0; stats.m_total_rx_pkts = 0; @@ -3729,6 +3782,9 @@ void CGlobalPortCfg::get_stats(CGlobalStats & stats){ stp->ierrors = st.ierrors; stp->oerrors = st.oerrors; stp->m_total_tx_bps = _if->get_last_tx_rate()*_1Mb_DOUBLE; + stp->m_total_tx_pps = _if->get_last_tx_pps_rate(); + stp->m_total_rx_bps = _if->get_last_rx_rate()*_1Mb_DOUBLE; + stp->m_total_rx_pps = _if->get_last_rx_pps_rate(); stats.m_total_tx_pkts += st.opackets; stats.m_total_rx_pkts += st.ipackets; @@ -3737,7 +3793,8 @@ void CGlobalPortCfg::get_stats(CGlobalStats & stats){ total_tx +=_if->get_last_tx_rate(); total_rx +=_if->get_last_rx_rate(); - total_pps +=_if->get_last_pps_rate(); + total_tx_pps +=_if->get_last_tx_pps_rate(); + total_rx_pps +=_if->get_last_rx_pps_rate(); } @@ -3798,7 +3855,13 @@ void CGlobalPortCfg::get_stats(CGlobalStats & stats){ stats.m_total_clients = total_clients; stats.m_total_servers = total_servers; stats.m_active_sockets = active_sockets; - stats.m_socket_util =100.0*(double)active_sockets/(double)total_sockets; + + if (total_sockets != 0) { + stats.m_socket_util =100.0*(double)active_sockets/(double)total_sockets; + } else { + stats.m_socket_util = 0; + } + float drop_rate=total_tx-total_rx; @@ -3814,7 +3877,8 @@ void CGlobalPortCfg::get_stats(CGlobalStats & stats){ stats.m_tx_bps = total_tx*pf*_1Mb_DOUBLE; stats.m_rx_bps = total_rx*pf*_1Mb_DOUBLE; - stats.m_tx_pps = total_pps*pf; + stats.m_tx_pps = total_tx_pps*pf; + stats.m_rx_pps = total_rx_pps*pf; stats.m_tx_cps = m_last_total_cps*pf; stats.m_tx_expected_cps = m_expected_cps*pf; @@ -3822,7 +3886,7 @@ void CGlobalPortCfg::get_stats(CGlobalStats & stats){ stats.m_tx_expected_bps = m_expected_bps*pf; } -bool CGlobalPortCfg::sanity_check(){ +bool CGlobalTRex::sanity_check(){ CFlowGenListPerThread * lpt; uint32_t errors=0; @@ -3842,7 +3906,7 @@ bool CGlobalPortCfg::sanity_check(){ /* dump the template info */ -void CGlobalPortCfg::dump_template_info(std::string & json){ +void CGlobalTRex::dump_template_info(std::string & json){ CFlowGenListPerThread * lpt = m_fl.m_threads_info[0]; CFlowsYamlInfo * yaml_info=&lpt->m_yaml_info; @@ -3857,7 +3921,7 @@ void CGlobalPortCfg::dump_template_info(std::string & json){ json+="]}" ; } -void CGlobalPortCfg::dump_stats(FILE *fd,std::string & json, +void CGlobalTRex::dump_stats(FILE *fd,std::string & json, CGlobalStats::DumpFormat format){ CGlobalStats stats; update_stats(); @@ -3897,11 +3961,15 @@ void CGlobalPortCfg::dump_stats(FILE *fd,std::string & json, } -int CGlobalPortCfg::run_in_master(){ +int CGlobalTRex::run_in_master(){ std::string json; bool was_stopped=false; + if ( get_is_stateless() ) { + m_trex_stateless->launch_control_plane(); + } + while ( true ) { if ( CGlobalInfo::m_options.preview.get_no_keyboard() ==false ){ @@ -3953,10 +4021,10 @@ int CGlobalPortCfg::run_in_master(){ m_fl.m_threads_info[0]->m_node_gen.dump_json(json); m_zmq_publisher.publish_json(json); - dump_template_info(json); - m_zmq_publisher.publish_json(json); - - + if ( !get_is_stateless() ){ + dump_template_info(json); + m_zmq_publisher.publish_json(json); + } if ( !CGlobalInfo::m_options.is_latency_disabled() ){ m_mg.update(); @@ -4009,6 +4077,10 @@ int CGlobalPortCfg::run_in_master(){ } + /* stateless info */ + m_trex_stateless->generate_publish_snapshot(json); + m_zmq_publisher.publish_json(json); + delay(500); if ( is_all_cores_finished() ) { @@ -4027,7 +4099,7 @@ int CGlobalPortCfg::run_in_master(){ -int CGlobalPortCfg::run_in_laterncy_core(void){ +int CGlobalTRex::run_in_laterncy_core(void){ if ( !CGlobalInfo::m_options.is_latency_disabled() ){ m_mg.start(0); } @@ -4035,12 +4107,12 @@ int CGlobalPortCfg::run_in_laterncy_core(void){ } -int CGlobalPortCfg::stop_core(virtual_thread_id_t virt_core_id){ +int CGlobalTRex::stop_core(virtual_thread_id_t virt_core_id){ m_signal[virt_core_id]=1; return (0); } -int CGlobalPortCfg::run_in_core(virtual_thread_id_t virt_core_id){ +int CGlobalTRex::run_in_core(virtual_thread_id_t virt_core_id){ CPreviewMode *lp=&CGlobalInfo::m_options.preview; if ( lp->getSingleCore() && @@ -4051,19 +4123,23 @@ int CGlobalPortCfg::run_in_core(virtual_thread_id_t virt_core_id){ return (0); } + assert(m_fl_was_init); CFlowGenListPerThread * lpt; lpt = m_fl.m_threads_info[virt_core_id-1]; - lpt->generate_erf(CGlobalInfo::m_options.out_file,*lp); - //lpt->m_node_gen.DumpHist(stdout); - //lpt->DumpStats(stdout); + + if (get_is_stateless()) { + lpt->start_stateless_daemon(); + }else{ + lpt->start_generate_stateful(CGlobalInfo::m_options.out_file,*lp); + } m_signal[virt_core_id]=1; return (0); } -int CGlobalPortCfg::stop_master(){ +int CGlobalTRex::stop_master(){ delay(1000); std::string json; @@ -4084,7 +4160,7 @@ int CGlobalPortCfg::stop_master(){ int i; for (i=0; i<get_cores_tx(); i++) { lpt = m_fl.m_threads_info[i]; - CCoreEthIF * erf_vif = &m_cores_vif[i+1]; + CCoreEthIF * erf_vif = m_cores_vif[i+1]; erf_vif->DumpCoreStats(stdout); erf_vif->DumpIfStats(stdout); @@ -4115,9 +4191,10 @@ int CGlobalPortCfg::stop_master(){ dump_post_test_stats(stdout); m_fl.Delete(); + return (0); } -bool CGlobalPortCfg::is_all_cores_finished(){ +bool CGlobalTRex::is_all_cores_finished(){ int i; for (i=0; i<get_cores_tx(); i++) { if ( m_signal[i+1]==0){ @@ -4128,8 +4205,34 @@ bool CGlobalPortCfg::is_all_cores_finished(){ } +int CGlobalTRex::start_master_stateless(){ + int i; + for (i=0; i<BP_MAX_CORES; i++) { + m_signal[i]=0; + } + m_fl.Create(); + m_expected_pps = 0; + m_expected_cps = 0; + m_expected_bps = 0; + + m_fl.generate_p_thread_info(get_cores_tx()); + CFlowGenListPerThread * lpt; + + for (i=0; i<get_cores_tx(); i++) { + lpt = m_fl.m_threads_info[i]; + CVirtualIF * erf_vif = m_cores_vif[i+1]; + lpt->set_vif(erf_vif); + lpt->m_node_gen.m_socket_id =m_cores_vif[i+1]->get_socket_id(); + } + m_fl_was_init=true; + + return (0); +} + -int CGlobalPortCfg::start_send_master(){ + + +int CGlobalTRex::start_send_master(){ int i; for (i=0; i<BP_MAX_CORES; i++) { m_signal[i]=0; @@ -4174,20 +4277,26 @@ int CGlobalPortCfg::start_send_master(){ for (i=0; i<get_cores_tx(); i++) { lpt = m_fl.m_threads_info[i]; //CNullIF * erf_vif = new CNullIF(); - CVirtualIF * erf_vif = &m_cores_vif[i+1]; + CVirtualIF * erf_vif = m_cores_vif[i+1]; lpt->set_vif(erf_vif); /* socket id */ - lpt->m_node_gen.m_socket_id =m_cores_vif[i+1].get_socket_id(); + lpt->m_node_gen.m_socket_id =m_cores_vif[i+1]->get_socket_id(); } m_fl_was_init=true; + return (0); } //////////////////////////////////////////// -static CGlobalPortCfg ports_cfg; +static CGlobalTRex g_trex; + + +TrexStateless * get_stateless_obj() { + return g_trex.m_trex_stateless; +} static int latency_one_lcore(__attribute__((unused)) void *dummy) { @@ -4196,34 +4305,22 @@ static int latency_one_lcore(__attribute__((unused)) void *dummy) if ( lpsock->thread_phy_is_latency( phy_id ) ){ - ports_cfg.run_in_laterncy_core(); + g_trex.run_in_laterncy_core(); }else{ if ( lpsock->thread_phy_is_master( phy_id ) ) { - ports_cfg.run_in_master(); + g_trex.run_in_master(); delay(1); }else{ delay((uint32_t)(1000.0*CGlobalInfo::m_options.m_duration)); /* this core has stopped */ - ports_cfg.m_signal[ lpsock->thread_phy_to_virt( phy_id ) ]=1; + g_trex.m_signal[ lpsock->thread_phy_to_virt( phy_id ) ]=1; } } return 0; } -static int stateless_entry(__attribute__((unused)) void *dummy) { - CPlatformSocketInfo * lpsock=&CGlobalInfo::m_socket; - physical_thread_id_t phy_id = rte_lcore_id(); - - if (lpsock->thread_phy_is_master( phy_id )) { - TrexStateless::get_instance().launch_control_plane(); - } else { - TrexStateless::get_instance().launch_on_dp_core(phy_id); - } - - return (0); -} static int slave_one_lcore(__attribute__((unused)) void *dummy) { @@ -4232,13 +4329,13 @@ static int slave_one_lcore(__attribute__((unused)) void *dummy) if ( lpsock->thread_phy_is_latency( phy_id ) ){ - ports_cfg.run_in_laterncy_core(); + g_trex.run_in_laterncy_core(); }else{ if ( lpsock->thread_phy_is_master( phy_id ) ) { - ports_cfg.run_in_master(); + g_trex.run_in_master(); delay(1); }else{ - ports_cfg.run_in_core( lpsock->thread_phy_to_virt( phy_id ) ); + g_trex.run_in_core( lpsock->thread_phy_to_virt( phy_id ) ); } } return 0; @@ -4329,7 +4426,6 @@ int update_global_info_from_platform_file(){ int update_dpdk_args(void){ - uint32_t cores_number; CPlatformSocketInfo * lpsock=&CGlobalInfo::m_socket; CParserOption * lpop= &CGlobalInfo::m_options; @@ -4346,7 +4442,7 @@ int update_dpdk_args(void){ } - sprintf(global_cores_str,"0x%x",lpsock->get_cores_mask()); + sprintf(global_cores_str,"0x%llx",(unsigned long long)lpsock->get_cores_mask()); /* set the DPDK options */ global_dpdk_args_num =7; @@ -4397,6 +4493,7 @@ int update_dpdk_args(void){ printf(" %s \n",global_dpdk_args[i]); } } + return (0); } @@ -4418,7 +4515,7 @@ int sim_load_list_of_cap_files(CParserOption * op){ lpt->set_vif(&erf_vif); if ( (op->preview.getVMode() >1) || op->preview.getFileWrite() ) { - lpt->generate_erf(op->out_file,op->preview); + lpt->start_generate_stateful(op->out_file,op->preview); } lpt->m_node_gen.DumpHist(stdout); @@ -4430,42 +4527,6 @@ int sim_load_list_of_cap_files(CParserOption * op){ } - - -static int -launch_stateless_trex() { - CPlatformSocketInfo *lpsock=&CGlobalInfo::m_socket; - CParserOption *lpop= &CGlobalInfo::m_options; - CPlatformYamlInfo *cg=&global_platform_cfg_info; - - TrexStatelessCfg cfg; - - TrexRpcServerConfig rpc_req_resp_cfg(TrexRpcServerConfig::RPC_PROT_TCP, 5050); - TrexRpcServerConfig rpc_async_cfg(TrexRpcServerConfig::RPC_PROT_TCP, 5051); - - cfg.m_dp_core_count = lpop->preview.getCores(); - cfg.m_port_count = lpop->m_expected_portd; - cfg.m_rpc_req_resp_cfg = &rpc_req_resp_cfg; - cfg.m_rpc_async_cfg = &rpc_async_cfg; - cfg.m_rpc_server_verbose = true; - - TrexStateless::configure(cfg); - - printf("\nStarting T-Rex Stateless\n"); - printf("Starting RPC Server...\n\n"); - - rte_eal_mp_remote_launch(stateless_entry, NULL, CALL_MASTER); - - unsigned lcore_id; - RTE_LCORE_FOREACH_SLAVE(lcore_id) { - if (rte_eal_wait_lcore(lcore_id) < 0) - return -1; - } - return (0); -} - - - int main_test(int argc , char * argv[]){ utl_termio_init(); @@ -4525,78 +4586,62 @@ int main_test(int argc , char * argv[]){ return ( sim_load_list_of_cap_files(&CGlobalInfo::m_options) ); } - bool is_stateless = (CGlobalInfo::m_options.m_run_mode == CParserOption::RUN_MODE_INTERACTIVE); - - if ( !ports_cfg.Create(is_stateless) ){ + if ( !g_trex.Create() ){ exit(1); } - /* patch here */ - if (is_stateless) { - return launch_stateless_trex(); - } - - if (po->preview.get_is_rx_check_enable() && (po->m_rx_check_sampe< get_min_sample_rate()) ) { po->m_rx_check_sampe = get_min_sample_rate(); printf("Warning rx check sample rate should be lower than %d setting it to %d\n",get_min_sample_rate(),get_min_sample_rate()); } /* set dump mode */ - ports_cfg.m_io_modes.set_mode((CTrexGlobalIoMode::CliDumpMode)CGlobalInfo::m_options.m_io_mode); + g_trex.m_io_modes.set_mode((CTrexGlobalIoMode::CliDumpMode)CGlobalInfo::m_options.m_io_mode); if ( !CGlobalInfo::m_options.is_latency_disabled() && (CGlobalInfo::m_options.m_latency_prev>0) ){ uint32_t pkts = CGlobalInfo::m_options.m_latency_prev* CGlobalInfo::m_options.m_latency_rate; printf("Start prev latency check - hack for Keren for %d sec \n",CGlobalInfo::m_options.m_latency_prev); - ports_cfg.m_mg.start(pkts); + g_trex.m_mg.start(pkts); printf("Delay now you can call command \n"); delay(CGlobalInfo::m_options.m_latency_prev* 1000); printf("Finish wating \n"); - ports_cfg.m_mg.reset(); - ports_cfg.reset_counters(); + g_trex.m_mg.reset(); + g_trex.reset_counters(); } - ports_cfg.start_send_master(); + if ( get_is_stateless() ) { + g_trex.start_master_stateless(); - // TBD remove - //ports_cfg.test_latency(); - /* test seding */ - //while (1) { - //} + }else{ + g_trex.start_send_master(); + } /* TBD_FDIR */ #if 0 printf(" test_send \n"); - ports_cfg.test_send(); + g_trex.test_send(); while (1) { delay(10000); } #endif - - - - //ports_cfg.test_latency(); - //return (0); - - if ( CGlobalInfo::m_options.preview.getOnlyLatency() ){ rte_eal_mp_remote_launch(latency_one_lcore, NULL, CALL_MASTER); RTE_LCORE_FOREACH_SLAVE(lcore_id) { if (rte_eal_wait_lcore(lcore_id) < 0) return -1; } - ports_cfg.stop_master(); + g_trex.stop_master(); return (0); } if ( CGlobalInfo::m_options.preview.getSingleCore() ) { - ports_cfg.run_in_core(1); - ports_cfg.stop_master(); + g_trex.run_in_core(1); + g_trex.stop_master(); return (0); } @@ -4606,8 +4651,8 @@ int main_test(int argc , char * argv[]){ return -1; } - ports_cfg.stop_master(); - ports_cfg.Delete(); + g_trex.stop_master(); + g_trex.Delete(); utl_termio_reset(); return (0); @@ -4732,14 +4777,13 @@ int CTRexExtendedDriverBase1G::configure_rx_filter_rules(CPhyEthIF * _if){ /* enable all rules */ _if->pci_reg_write(E1000_WUFC, (mask<<16) | (1<<14) ); + + return (0); } void CTRexExtendedDriverBase1G::get_extended_stats(CPhyEthIF * _if,CPhyEthIFStats *stats){ - int i; - uint64_t t=0; - stats->ipackets += _if->pci_reg_read(E1000_GPRC) ; stats->ibytes += (_if->pci_reg_read(E1000_GORCL) ); @@ -4869,6 +4913,7 @@ int CTRexExtendedDriverBase10G::configure_rx_filter_rules(CPhyEthIF * _if){ rte_exit(EXIT_FAILURE, " ERROR rte_eth_dev_fdir_add_perfect_filter : %d\n",res); } } + return (0); } int CTRexExtendedDriverBase10G::configure_drop_queue(CPhyEthIF * _if){ @@ -4991,6 +5036,8 @@ int CTRexExtendedDriverBase40G::configure_rx_filter_rules(CPhyEthIF * _if){ add_rules(_if,RTE_ETH_FLOW_TYPE_UDPV6,ttl); add_rules(_if,RTE_ETH_FLOW_TYPE_TCPV6,ttl); } + + return (0); } @@ -5146,3 +5193,54 @@ struct rte_mbuf * rte_mbuf_convert_to_one_seg(struct rte_mbuf *m){ } +/*********************************************************** + * platfrom API object + * TODO: REMOVE THIS TO A SEPERATE FILE + * + **********************************************************/ +void +TrexDpdkPlatformApi::get_global_stats(TrexPlatformGlobalStats &stats) const { + CGlobalStats trex_stats; + g_trex.get_stats(trex_stats); + + stats.m_stats.m_cpu_util = trex_stats.m_cpu_util; + + stats.m_stats.m_tx_bps = trex_stats.m_tx_bps; + stats.m_stats.m_tx_pps = trex_stats.m_tx_pps; + stats.m_stats.m_total_tx_pkts = trex_stats.m_total_tx_pkts; + stats.m_stats.m_total_tx_bytes = trex_stats.m_total_tx_bytes; + + stats.m_stats.m_rx_bps = trex_stats.m_rx_bps; + stats.m_stats.m_rx_pps = /*trex_stats.m_rx_pps*/ 0; /* missing */ + stats.m_stats.m_total_rx_pkts = trex_stats.m_total_rx_pkts; + stats.m_stats.m_total_rx_bytes = trex_stats.m_total_rx_bytes; +} + +void +TrexDpdkPlatformApi::get_interface_stats(uint8_t interface_id, TrexPlatformInterfaceStats &stats) const { + +} + +uint8_t +TrexDpdkPlatformApi::get_dp_core_count() const { + return CGlobalInfo::m_options.preview.getCores(); +} + + +void +TrexDpdkPlatformApi::port_id_to_cores(uint8_t port_id, std::vector<std::pair<uint8_t, uint8_t>> &cores_id_list) const { + + cores_id_list.clear(); + + /* iterate over all DP cores */ + for (uint8_t core_id = 0; core_id < g_trex.get_cores_tx(); core_id++) { + + /* iterate over all the directions*/ + for (uint8_t dir = 0 ; dir < CS_NUM; dir++) { + if (g_trex.m_cores_vif[core_id + 1]->get_ports()[dir].m_port->get_port_id() == port_id) { + cores_id_list.push_back(std::make_pair(core_id, dir)); + } + } + } +} + diff --git a/src/mock/trex_platform_api_mock.cpp b/src/mock/trex_platform_api_mock.cpp new file mode 100644 index 00000000..54f71e10 --- /dev/null +++ b/src/mock/trex_platform_api_mock.cpp @@ -0,0 +1,49 @@ +/* + Itay Marom + Cisco Systems, Inc. +*/ + +/* +Copyright (c) 2015-2015 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include <internal_api/trex_platform_api.h> + +void +TrexMockPlatformApi::get_global_stats(TrexPlatformGlobalStats &stats) const { + + stats.m_stats.m_cpu_util = 0; + + stats.m_stats.m_tx_bps = 0; + stats.m_stats.m_tx_pps = 0; + stats.m_stats.m_total_tx_pkts = 0; + stats.m_stats.m_total_tx_bytes = 0; + + stats.m_stats.m_rx_bps = 0; + stats.m_stats.m_rx_pps = 0; + stats.m_stats.m_total_rx_pkts = 0; + stats.m_stats.m_total_rx_bytes = 0; +} + +void +TrexMockPlatformApi::get_interface_stats(uint8_t interface_id, TrexPlatformInterfaceStats &stats) const { + +} + +uint8_t +TrexMockPlatformApi::get_dp_core_count() const { + return (1); +} + diff --git a/src/mock/trex_rpc_server_mock.cpp b/src/mock/trex_rpc_server_mock.cpp index de43f92f..0bdf6cf1 100644 --- a/src/mock/trex_rpc_server_mock.cpp +++ b/src/mock/trex_rpc_server_mock.cpp @@ -21,12 +21,71 @@ limitations under the License. #include <trex_rpc_server_api.h> #include <trex_stateless.h> +#include <trex_stateless_dp_core.h> + +#include <msg_manager.h> #include <iostream> +#include <sstream> #include <unistd.h> +#include <string.h> +#include <zmq.h> +#include <bp_sim.h> using namespace std; +static TrexStateless *g_trex_stateless; +static uint16_t g_rpc_port; + +static bool +verify_tcp_port_is_free(uint16_t port) { + void *m_context = zmq_ctx_new(); + void *m_socket = zmq_socket (m_context, ZMQ_REP); + std::stringstream ss; + ss << "tcp://*:"; + ss << port; + + int rc = zmq_bind (m_socket, ss.str().c_str()); + + zmq_close(m_socket); + zmq_term(m_context); + + return (rc == 0); +} + +static uint16_t +find_free_tcp_port(uint16_t start_port = 5050) { + void *m_context = zmq_ctx_new(); + void *m_socket = zmq_socket (m_context, ZMQ_REP); + + uint16_t port = start_port; + while (true) { + std::stringstream ss; + ss << "tcp://*:"; + ss << port; + + int rc = zmq_bind (m_socket, ss.str().c_str()); + if (rc == 0) { + break; + } + + port++; + } + + zmq_close(m_socket); + zmq_term(m_context); + + return port; +} + +TrexStateless * get_stateless_obj() { + return g_trex_stateless; +} + +uint16_t gtest_get_mock_server_port() { + return g_rpc_port; +} + /** * on simulation this is not rebuild every version * (improved stub) @@ -42,44 +101,87 @@ extern "C" const char * get_build_time(void){ int gtest_main(int argc, char **argv); -int main(int argc, char *argv[]) { +static bool parse_uint16(const string arg, uint16_t &port) { + stringstream ss(arg); + + bool x = (ss >> port); + + return (x); +} + +static void +run_dummy_core() { + //TODO: connect this to the scheduler + + //CFlowGenList fl; + //fl.Create(); + //CFlowGenListPerThread *lp = new CFlowGenListPerThread(); + //lp->Create(0, 0, NULL, 0); + //TrexStatelessDpCore dummy_core(0, lp); + //lp->start_stateless_daemon(); +} +int main(int argc, char *argv[]) { bool is_gtest = false; + time_init(); + CGlobalInfo::m_socket.Create(0); + + CGlobalInfo::init_pools(1000); + assert( CMsgIns::Ins()->Create(1)); + + std::thread *m_thread = new std::thread(run_dummy_core); + (void)m_thread; + // gtest ? if (argc > 1) { - if (string(argv[1]) != "--ut") { - cout << "\n[Usage] " << argv[0] << ": " << " [--ut]\n\n"; + string arg = string(argv[1]); + + if (arg == "--ut") { + g_rpc_port = find_free_tcp_port(); + is_gtest = true; + } else if (parse_uint16(arg, g_rpc_port)) { + bool rc = verify_tcp_port_is_free(g_rpc_port); + if (!rc) { + cout << "port " << g_rpc_port << " is not available to use\n"; + exit(-1); + } + } else { + + cout << "\n[Usage] " << argv[0] << ": " << " [--ut] or [port number < 65535]\n\n"; exit(-1); } - is_gtest = true; + + } else { + g_rpc_port = find_free_tcp_port(); } /* configure the stateless object with 4 ports */ TrexStatelessCfg cfg; - TrexRpcServerConfig rpc_req_resp_cfg(TrexRpcServerConfig::RPC_PROT_TCP, 5050); - TrexRpcServerConfig rpc_async_cfg(TrexRpcServerConfig::RPC_PROT_TCP, 5051); + TrexRpcServerConfig rpc_req_resp_cfg(TrexRpcServerConfig::RPC_PROT_TCP, g_rpc_port); + //TrexRpcServerConfig rpc_async_cfg(TrexRpcServerConfig::RPC_PROT_TCP, 5051); cfg.m_port_count = 4; - cfg.m_dp_core_count = 2; cfg.m_rpc_req_resp_cfg = &rpc_req_resp_cfg; - cfg.m_rpc_async_cfg = &rpc_async_cfg; + cfg.m_rpc_async_cfg = NULL; cfg.m_rpc_server_verbose = (is_gtest ? false : true); + cfg.m_platform_api = new TrexMockPlatformApi(); - TrexStateless::configure(cfg); + g_trex_stateless = new TrexStateless(cfg); - TrexStateless::get_instance().launch_control_plane(); + g_trex_stateless->launch_control_plane(); /* gtest handling */ if (is_gtest) { int rc = gtest_main(argc, argv); - TrexStateless::destroy(); + delete g_trex_stateless; + g_trex_stateless = NULL; return rc; } cout << "\n-= Starting RPC Server Mock =-\n\n"; - cout << "Listening on tcp://localhost:5050 [ZMQ]\n\n"; + cout << "Listening on tcp://localhost:" << g_rpc_port << " [ZMQ]\n\n"; cout << "Server Started\n\n"; @@ -87,6 +189,7 @@ int main(int argc, char *argv[]) { sleep(1); } - TrexStateless::destroy(); + delete g_trex_stateless; + g_trex_stateless = NULL; } diff --git a/src/msg_manager.cpp b/src/msg_manager.cpp index 4db96583..9f41d08c 100755 --- a/src/msg_manager.cpp +++ b/src/msg_manager.cpp @@ -26,7 +26,7 @@ limitations under the License. /*TBD: need to fix socket_id for NUMA */ -bool CMessagingManager::Create(uint8_t num_dp_threads){ +bool CMessagingManager::Create(uint8_t num_dp_threads,std::string a_name){ m_num_dp_threads=num_dp_threads; assert(m_dp_to_cp==0); assert(m_cp_to_dp==0); @@ -38,11 +38,11 @@ bool CMessagingManager::Create(uint8_t num_dp_threads){ char name[100]; lp=getRingCpToDp(i); - sprintf(name,"cp_to_dp_%d",i); + sprintf(name,"%s_to_%d",(char *)a_name.c_str(),i); assert(lp->Create(std::string(name),1024,0)==true); lp=getRingDpToCp(i); - sprintf(name,"dp_to_cp_%d",i); + sprintf(name,"%s_from_%d",(char *)a_name.c_str(),i); assert(lp->Create(std::string(name),1024,0)==true); } @@ -89,7 +89,12 @@ CMsgIns * CMsgIns::Ins(void){ } bool CMsgIns::Create(uint8_t num_threads){ - return ( m_rx_dp.Create(num_threads) ); + + bool res = m_cp_dp.Create(num_threads,"cp_dp"); + if (!res) { + return (res); + } + return (m_rx_dp.Create(num_threads,"rx_dp")); } diff --git a/src/msg_manager.h b/src/msg_manager.h index b25660bb..8958f826 100755 --- a/src/msg_manager.h +++ b/src/msg_manager.h @@ -23,12 +23,20 @@ limitations under the License. #include "CRing.h" +#include <string> /* messages from CP->DP Ids */ -#define NAT_MSG (7) -#define LATENCY_PKT_SEND_MSG (8) +struct CGenNodeMsgBase { + enum { + NAT_FIRST = 7, + LATENCY_PKT = 8, + } msg_types; + +public: + uint8_t m_msg_type; /* msg type */ +}; /* @@ -71,7 +79,7 @@ public: m_dp_to_cp=0; m_num_dp_threads=0; } - bool Create(uint8_t num_dp_threads); + bool Create(uint8_t num_dp_threads,std::string name); void Delete(); CNodeRing * getRingCpToDp(uint8_t thread_id); CNodeRing * getRingDpToCp(uint8_t thread_id); @@ -94,12 +102,18 @@ public: CMessagingManager * getRxDp(){ return (&m_rx_dp); } + CMessagingManager * getCpDp(){ + return (&m_cp_dp); + } + uint8_t get_num_threads(){ return (m_rx_dp.get_num_threads()); } private: CMessagingManager m_rx_dp; + CMessagingManager m_cp_dp; + private: /* one instance */ diff --git a/src/nat_check.cpp b/src/nat_check.cpp index 676c1292..170d2de6 100755 --- a/src/nat_check.cpp +++ b/src/nat_check.cpp @@ -171,8 +171,8 @@ void CNatRxManager::handle_packet_ipv4(CNatOption * option, } -#define MYDP(f) if (f) fprintf(fd," %-40s: %llu \n",#f,f) -#define MYDP_A(f) fprintf(fd," %-40s: %llu \n",#f,f) +#define MYDP(f) if (f) fprintf(fd," %-40s: %llu \n",#f,(unsigned long long)f) +#define MYDP_A(f) fprintf(fd," %-40s: %llu \n",#f, (unsigned long long)f) diff --git a/src/nat_check.h b/src/nat_check.h index b67c523c..a500ddaf 100755 --- a/src/nat_check.h +++ b/src/nat_check.h @@ -59,16 +59,6 @@ struct CNatFlowInfo { this struct should be in the same size of CGenNode beacuse allocator is global . */ -struct CGenNodeMsgBase { - enum { - NAT_FIRST = NAT_MSG, - LATENCY_PKT = LATENCY_PKT_SEND_MSG - } msg_types; - -public: - uint8_t m_msg_type; /* msg type */ -}; - struct CGenNodeNatInfo : public CGenNodeMsgBase { uint8_t m_pad; diff --git a/src/os_time.h b/src/os_time.h index 153ee3e3..0e732abf 100755 --- a/src/os_time.h +++ b/src/os_time.h @@ -22,6 +22,7 @@ limitations under the License. */ #include <stdint.h> +#include <time.h> typedef uint64_t hr_time_t; // time in high res tick typedef uint32_t hr_time_32_t; // time in high res tick @@ -129,6 +130,25 @@ static inline dsec_t now_sec(void){ } +static inline +void delay(int msec){ + + if (msec == 0) + {//user that requested that probebly wanted the minimal delay + //but because of scaling problem he have got 0 so we will give the min delay + //printf("\n\n\nERROR-Task delay ticks == 0 found in task %s task id = %d\n\n\n\n", + // SANB_TaskName(SANB_TaskIdSelf()), SANB_TaskIdSelf()); + msec =1; + + } + + struct timespec time1, remain; // 2 sec max delay + time1.tv_sec=msec/1000; + time1.tv_nsec=(msec - (time1.tv_sec*1000))*1000000; + + nanosleep(&time1,&remain); +} + #endif diff --git a/src/pal/linux/mbuf.h b/src/pal/linux/mbuf.h index 693b095a..35a442bf 100755 --- a/src/pal/linux/mbuf.h +++ b/src/pal/linux/mbuf.h @@ -185,8 +185,9 @@ static inline void utl_rte_pktmbuf_add_last(rte_mbuf_t *m,rte_mbuf_t *m_last){ #define __rte_cache_aligned -#define CACHE_LINE_SIZE 64 +#define CACHE_LINE_SIZE 64 +#define RTE_CACHE_LINE_SIZE 64 #define SOCKET_ID_ANY 0 #endif diff --git a/src/platform_cfg.cpp b/src/platform_cfg.cpp index f0911611..df04cd89 100755 --- a/src/platform_cfg.cpp +++ b/src/platform_cfg.cpp @@ -127,7 +127,7 @@ void CPlatformMemoryYamlInfo::Dump(FILE *fd){ int i=0; for (i=0; i<MBUF_SIZE; i++) { - fprintf(fd," %-40s : %lu \n",names[i].c_str(),m_mbuf[i]); + fprintf(fd," %-40s : %lu \n",names[i].c_str(), (ulong)m_mbuf[i]); } } @@ -300,6 +300,10 @@ void operator >> (const YAML::Node& node, CPlatformYamlInfo & plat_info) { plat_info.m_telnet_exist=true; } + if ( node.FindValue("zmq_rpc_port") ){ + node["zmq_rpc_port"] >> plat_info.m_zmq_rpc_port; + } + if ( node.FindValue("port_bandwidth_gb") ){ node["port_bandwidth_gb"] >> plat_info.m_port_bandwidth_gb; } @@ -375,7 +379,7 @@ void CPlatformYamlInfo::Dump(FILE *fd){ }else{ fprintf(fd," port limit : not configured \n"); } - fprintf(fd," port_bandwidth_gb : %lu \n",m_port_bandwidth_gb); + fprintf(fd," port_bandwidth_gb : %lu \n", (ulong)m_port_bandwidth_gb); if ( m_if_mask_exist && m_if_mask.size() ) { fprintf(fd," if_mask : "); @@ -383,7 +387,7 @@ void CPlatformYamlInfo::Dump(FILE *fd){ for (i=0; i<(int)m_if_mask.size(); i++) { fprintf(fd," %s,",m_if_mask[i].c_str()); } - fprintf(fd,"\n",m_if_mask[i].c_str()); + fprintf(fd,"\n"); }else{ fprintf(fd," if_mask : None \n"); diff --git a/src/platform_cfg.h b/src/platform_cfg.h index 2f335471..b4b03b10 100755 --- a/src/platform_cfg.h +++ b/src/platform_cfg.h @@ -184,6 +184,7 @@ public: m_telnet_exist=false; m_telnet_port=4502 ; + m_zmq_rpc_port = 5050; m_mac_info_exist=false; m_port_bandwidth_gb = 10; @@ -209,15 +210,17 @@ public: std::string m_limit_memory; uint32_t m_thread_per_dual_if; - uint32_t m_port_bandwidth_gb; + uint32_t m_port_bandwidth_gb; - bool m_enable_zmq_pub_exist; - bool m_enable_zmq_pub; - uint16_t m_zmq_pub_port; + bool m_enable_zmq_pub_exist; + bool m_enable_zmq_pub; + uint16_t m_zmq_pub_port; - bool m_telnet_exist; - uint16_t m_telnet_port; + bool m_telnet_exist; + uint16_t m_telnet_port; + + uint16_t m_zmq_rpc_port; bool m_mac_info_exist; std::vector <CMacYamlInfo> m_mac_info; diff --git a/src/rpc-server/commands/trex_rpc_cmd_general.cpp b/src/rpc-server/commands/trex_rpc_cmd_general.cpp index ae87d749..b40e996f 100644 --- a/src/rpc-server/commands/trex_rpc_cmd_general.cpp +++ b/src/rpc-server/commands/trex_rpc_cmd_general.cpp @@ -145,7 +145,7 @@ trex_rpc_cmd_rc_e TrexRpcCmdGetSysInfo::_run(const Json::Value ¶ms, Json::Value &result) { string hostname; - TrexStateless & instance = TrexStateless::get_instance(); + TrexStateless * main = get_stateless_obj(); Json::Value §ion = result["result"]; @@ -155,21 +155,21 @@ TrexRpcCmdGetSysInfo::_run(const Json::Value ¶ms, Json::Value &result) { section["uptime"] = TrexRpcServer::get_server_uptime(); /* FIXME: core count */ - section["dp_core_count"] = instance.get_dp_core_count(); + section["dp_core_count"] = main->get_dp_core_count(); section["core_type"] = get_cpu_model(); /* ports */ - section["port_count"] = instance.get_port_count(); + section["port_count"] = main->get_port_count(); section["ports"] = Json::arrayValue; - for (int i = 0; i < instance.get_port_count(); i++) { + for (int i = 0; i < main->get_port_count(); i++) { string driver; string speed; - TrexStatelessPort *port = instance.get_port_by_id(i); + TrexStatelessPort *port = main->get_port_by_id(i); port->get_properties(driver, speed); section["ports"][i]["index"] = i; @@ -201,7 +201,7 @@ TrexRpcCmdGetOwner::_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); + TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); section["owner"] = port->get_owner(); return (TREX_RPC_CMD_OK); @@ -220,7 +220,7 @@ TrexRpcCmdAcquire::_run(const Json::Value ¶ms, Json::Value &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); + TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); if ( (!port->is_free_to_aquire()) && (port->get_owner() != new_owner) && (!force)) { generate_execute_err(result, "port is already taken by '" + port->get_owner() + "'"); @@ -242,7 +242,7 @@ 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); + TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); if (port->get_state() == TrexStatelessPort::PORT_STATE_TRANSMITTING) { generate_execute_err(result, "cannot release a port during transmission"); @@ -264,7 +264,7 @@ 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); + TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); if (port->get_state() == TrexStatelessPort::PORT_STATE_DOWN) { generate_execute_err(result, "cannot get stats - port is down"); @@ -277,3 +277,42 @@ TrexRpcCmdGetPortStats::_run(const Json::Value ¶ms, Json::Value &result) { return (TREX_RPC_CMD_OK); } +/** + * request the server a sync about a specific user + * + */ +trex_rpc_cmd_rc_e +TrexRpcCmdSyncUser::_run(const Json::Value ¶ms, Json::Value &result) { + + const string &user = parse_string(params, "user", result); + bool sync_streams = parse_bool(params, "sync_streams", result); + + result["result"] = Json::arrayValue; + + for (auto port : get_stateless_obj()->get_port_list()) { + if (port->get_owner() == user) { + + Json::Value owned_port; + + owned_port["port_id"] = port->get_port_id(); + owned_port["handler"] = port->get_owner_handler(); + owned_port["state"] = port->get_state_as_string(); + + /* if sync streams was asked - sync all the streams */ + if (sync_streams) { + owned_port["streams"] = Json::arrayValue; + + std::vector <TrexStream *> streams; + port->get_stream_table()->get_object_list(streams); + + for (auto stream : streams) { + owned_port["streams"].append(stream->get_stream_json()); + } + } + + result["result"].append(owned_port); + } + } + + 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 20107411..4fa0956d 100644 --- a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp +++ b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp @@ -114,7 +114,7 @@ TrexRpcCmdAddStream::_run(const Json::Value ¶ms, Json::Value &result) { /* make sure this is a valid stream to add */ validate_stream(stream, result); - TrexStatelessPort *port = TrexStateless::get_instance().get_port_by_id(stream->m_port_id); + TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(stream->m_port_id); port->get_stream_table()->add_stream(stream); result["result"] = "ACK"; @@ -127,7 +127,7 @@ TrexRpcCmdAddStream::_run(const Json::Value ¶ms, Json::Value &result) { TrexStream * TrexRpcCmdAddStream::allocate_new_stream(const Json::Value §ion, uint8_t port_id, uint32_t stream_id, Json::Value &result) { - TrexStream *stream; + TrexStream *stream = NULL; const Json::Value &mode = parse_object(section, "mode", result); std::string type = parse_string(mode, "type", result); @@ -200,9 +200,9 @@ TrexRpcCmdAddStream::parse_vm_instr_flow_var(const Json::Value &inst, TrexStream std::string min_value_str = parse_string(inst, "min_value", result); std::string max_value_str = parse_string(inst, "max_value", result); - uint64_t init_value; - uint64_t min_value; - uint64_t max_value; + uint64_t init_value = 0; + uint64_t min_value = 0; + uint64_t max_value = 0; try { init_value = str2num(init_value_str); @@ -282,15 +282,15 @@ TrexRpcCmdAddStream::validate_stream(const TrexStream *stream, Json::Value &resu } /* port id should be between 0 and count - 1 */ - if (stream->m_port_id >= TrexStateless::get_instance().get_port_count()) { + if (stream->m_port_id >= get_stateless_obj()->get_port_count()) { std::stringstream ss; - ss << "invalid port id - should be between 0 and " << (int)TrexStateless::get_instance().get_port_count() - 1; + ss << "invalid port id - should be between 0 and " << (int)get_stateless_obj()->get_port_count() - 1; delete stream; generate_execute_err(result, ss.str()); } /* add the stream to the port's stream table */ - TrexStatelessPort * port = TrexStateless::get_instance().get_port_by_id(stream->m_port_id); + TrexStatelessPort * port = get_stateless_obj()->get_port_by_id(stream->m_port_id); /* does such a stream exists ? */ if (port->get_stream_table()->get_stream_by_id(stream->m_stream_id)) { @@ -312,13 +312,13 @@ TrexRpcCmdRemoveStream::_run(const Json::Value ¶ms, Json::Value &result) { uint32_t stream_id = parse_int(params, "stream_id", result); - if (port_id >= TrexStateless::get_instance().get_port_count()) { + if (port_id >= get_stateless_obj()->get_port_count()) { std::stringstream ss; - ss << "invalid port id - should be between 0 and " << (int)TrexStateless::get_instance().get_port_count() - 1; + ss << "invalid port id - should be between 0 and " << (int)get_stateless_obj()->get_port_count() - 1; generate_execute_err(result, ss.str()); } - TrexStatelessPort *port = TrexStateless::get_instance().get_port_by_id(port_id); + TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); TrexStream *stream = port->get_stream_table()->get_stream_by_id(stream_id); if (!stream) { @@ -344,13 +344,13 @@ trex_rpc_cmd_rc_e TrexRpcCmdRemoveAllStreams::_run(const Json::Value ¶ms, Json::Value &result) { uint8_t port_id = parse_byte(params, "port_id", result); - if (port_id >= TrexStateless::get_instance().get_port_count()) { + if (port_id >= get_stateless_obj()->get_port_count()) { std::stringstream ss; - ss << "invalid port id - should be between 0 and " << (int)TrexStateless::get_instance().get_port_count() - 1; + ss << "invalid port id - should be between 0 and " << (int)get_stateless_obj()->get_port_count() - 1; generate_execute_err(result, ss.str()); } - TrexStatelessPort *port = TrexStateless::get_instance().get_port_by_id(port_id); + TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); port->get_stream_table()->remove_and_delete_all_streams(); result["result"] = "ACK"; @@ -369,15 +369,15 @@ TrexRpcCmdGetStreamList::_run(const Json::Value ¶ms, Json::Value &result) { uint8_t port_id = parse_byte(params, "port_id", result); - if (port_id >= TrexStateless::get_instance().get_port_count()) { + if (port_id >= get_stateless_obj()->get_port_count()) { std::stringstream ss; - ss << "invalid port id - should be between 0 and " << (int)TrexStateless::get_instance().get_port_count() - 1; + ss << "invalid port id - should be between 0 and " << (int)get_stateless_obj()->get_port_count() - 1; generate_execute_err(result, ss.str()); } - TrexStatelessPort *port = TrexStateless::get_instance().get_port_by_id(port_id); + TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); - port->get_stream_table()->get_stream_list(stream_list); + port->get_stream_table()->get_id_list(stream_list); Json::Value json_list = Json::arrayValue; @@ -397,17 +397,17 @@ TrexRpcCmdGetStreamList::_run(const Json::Value ¶ms, Json::Value &result) { **************************/ trex_rpc_cmd_rc_e TrexRpcCmdGetStream::_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); + bool get_pkt = parse_bool(params, "get_pkt", result); uint32_t stream_id = parse_int(params, "stream_id", result); - if (port_id >= TrexStateless::get_instance().get_port_count()) { + if (port_id >= get_stateless_obj()->get_port_count()) { std::stringstream ss; - ss << "invalid port id - should be between 0 and " << (int)TrexStateless::get_instance().get_port_count() - 1; + ss << "invalid port id - should be between 0 and " << (int)get_stateless_obj()->get_port_count() - 1; generate_execute_err(result, ss.str()); } - TrexStatelessPort *port = TrexStateless::get_instance().get_port_by_id(port_id); + TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); TrexStream *stream = port->get_stream_table()->get_stream_by_id(stream_id); @@ -418,7 +418,12 @@ TrexRpcCmdGetStream::_run(const Json::Value ¶ms, Json::Value &result) { } /* return the stored stream json (instead of decoding it all over again) */ - result["result"]["stream"] = stream->get_stream_json(); + Json::Value j = stream->get_stream_json(); + if (!get_pkt) { + j.removeMember("packet"); + } + + result["result"]["stream"] = j; return (TREX_RPC_CMD_OK); @@ -432,16 +437,17 @@ trex_rpc_cmd_rc_e TrexRpcCmdStartTraffic::_run(const Json::Value ¶ms, Json::Value &result) { uint8_t port_id = parse_byte(params, "port_id", result); + double mul = parse_double(params, "mul", result); - if (port_id >= TrexStateless::get_instance().get_port_count()) { + if (port_id >= get_stateless_obj()->get_port_count()) { std::stringstream ss; - ss << "invalid port id - should be between 0 and " << (int)TrexStateless::get_instance().get_port_count() - 1; + ss << "invalid port id - should be between 0 and " << (int)get_stateless_obj()->get_port_count() - 1; generate_execute_err(result, ss.str()); } - TrexStatelessPort *port = TrexStateless::get_instance().get_port_by_id(port_id); + TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); - TrexStatelessPort::rc_e rc = port->start_traffic(); + TrexStatelessPort::rc_e rc = port->start_traffic(mul); if (rc == TrexStatelessPort::RC_OK) { result["result"] = "ACK"; @@ -462,7 +468,7 @@ TrexRpcCmdStartTraffic::_run(const Json::Value ¶ms, Json::Value &result) { generate_execute_err(result, ss.str()); } - return (TREX_RPC_CMD_OK); + return (TREX_RPC_CMD_OK); } /*************************** @@ -473,13 +479,13 @@ trex_rpc_cmd_rc_e TrexRpcCmdStopTraffic::_run(const Json::Value ¶ms, Json::Value &result) { uint8_t port_id = parse_byte(params, "port_id", result); - if (port_id >= TrexStateless::get_instance().get_port_count()) { + if (port_id >= get_stateless_obj()->get_port_count()) { std::stringstream ss; - ss << "invalid port id - should be between 0 and " << (int)TrexStateless::get_instance().get_port_count() - 1; + ss << "invalid port id - should be between 0 and " << (int)get_stateless_obj()->get_port_count() - 1; generate_execute_err(result, ss.str()); } - TrexStatelessPort *port = TrexStateless::get_instance().get_port_by_id(port_id); + TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); port->stop_traffic(); result["result"] = "ACK"; @@ -487,3 +493,43 @@ TrexRpcCmdStopTraffic::_run(const Json::Value ¶ms, Json::Value &result) { return (TREX_RPC_CMD_OK); } +/*************************** + * get all streams + * + **************************/ +trex_rpc_cmd_rc_e +TrexRpcCmdGetAllStreams::_run(const Json::Value ¶ms, Json::Value &result) { + uint8_t port_id = parse_byte(params, "port_id", result); + bool get_pkt = parse_bool(params, "get_pkt", result); + + if (port_id >= get_stateless_obj()->get_port_count()) { + std::stringstream ss; + ss << "invalid port id - should be between 0 and " << (int)get_stateless_obj()->get_port_count() - 1; + generate_execute_err(result, ss.str()); + } + + TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id); + + std::vector <TrexStream *> streams; + port->get_stream_table()->get_object_list(streams); + + Json::Value streams_json = Json::objectValue; + for (auto stream : streams) { + + Json::Value j = stream->get_stream_json(); + + /* should we include the packet as well ? */ + if (!get_pkt) { + j.removeMember("packet"); + } + + std::stringstream ss; + ss << stream->m_stream_id; + + streams_json[ss.str()] = j; + } + + result["result"]["streams"] = streams_json; + + 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 5926a8d8..a604d9a1 100644 --- a/src/rpc-server/commands/trex_rpc_cmds.h +++ b/src/rpc-server/commands/trex_rpc_cmds.h @@ -99,11 +99,16 @@ void parse_vm_instr_write_flow_var(const Json::Value &inst, TrexStream *stream, TREX_RPC_CMD_DEFINE(TrexRpcCmdGetStreamList, "get_stream_list", 1, true); +TREX_RPC_CMD_DEFINE(TrexRpcCmdGetAllStreams, "get_all_streams", 2, true); -TREX_RPC_CMD_DEFINE(TrexRpcCmdGetStream, "get_stream", 2, true); +TREX_RPC_CMD_DEFINE(TrexRpcCmdGetStream, "get_stream", 3, true); -TREX_RPC_CMD_DEFINE(TrexRpcCmdStartTraffic, "start_traffic", 1, true); + + +TREX_RPC_CMD_DEFINE(TrexRpcCmdStartTraffic, "start_traffic", 2, true); TREX_RPC_CMD_DEFINE(TrexRpcCmdStopTraffic, "stop_traffic", 1, true); +TREX_RPC_CMD_DEFINE(TrexRpcCmdSyncUser, "sync_user", 2, false); + #endif /* __TREX_RPC_CMD_H__ */ diff --git a/src/rpc-server/trex_rpc_async_server.cpp b/src/rpc-server/trex_rpc_async_server.cpp index f4d21f2f..46fe499b 100644 --- a/src/rpc-server/trex_rpc_async_server.cpp +++ b/src/rpc-server/trex_rpc_async_server.cpp @@ -79,7 +79,7 @@ TrexRpcServerAsync::_rpc_thread_cb() { } /* trigger a full update for stats */ - TrexStateless::get_instance().update_stats(); + //get_stateless_obj()->update_stats(); /* done with the lock */ if (m_lock) { @@ -87,7 +87,7 @@ TrexRpcServerAsync::_rpc_thread_cb() { } /* encode them to JSON */ - TrexStateless::get_instance().encode_stats(snapshot); + get_stateless_obj()->encode_stats(snapshot); /* write to string and publish */ std::string snapshot_str = writer.write(snapshot); diff --git a/src/rpc-server/trex_rpc_cmd.cpp b/src/rpc-server/trex_rpc_cmd.cpp index 920a8d30..af0db3f4 100644 --- a/src/rpc-server/trex_rpc_cmd.cpp +++ b/src/rpc-server/trex_rpc_cmd.cpp @@ -61,7 +61,7 @@ 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); + TrexStatelessPort *port = get_stateless_obj()->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"); @@ -78,9 +78,9 @@ TrexRpcCommand::parse_port(const Json::Value ¶ms, Json::Value &result) { void TrexRpcCommand::validate_port_id(uint8_t port_id, Json::Value &result) { - if (port_id >= TrexStateless::get_instance().get_port_count()) { + if (port_id >= get_stateless_obj()->get_port_count()) { std::stringstream ss; - ss << "invalid port id - should be between 0 and " << (int)TrexStateless::get_instance().get_port_count() - 1; + ss << "invalid port id - should be between 0 and " << (int)get_stateless_obj()->get_port_count() - 1; generate_execute_err(result, ss.str()); } } diff --git a/src/rpc-server/trex_rpc_cmds_table.cpp b/src/rpc-server/trex_rpc_cmds_table.cpp index c1c546f3..e3bd7848 100644 --- a/src/rpc-server/trex_rpc_cmds_table.cpp +++ b/src/rpc-server/trex_rpc_cmds_table.cpp @@ -42,12 +42,15 @@ TrexRpcCommandsTable::TrexRpcCommandsTable() { register_command(new TrexRpcCmdRelease()); register_command(new TrexRpcCmdGetPortStats()); + register_command(new TrexRpcCmdSyncUser()); + /* stream commands */ register_command(new TrexRpcCmdAddStream()); register_command(new TrexRpcCmdRemoveStream()); register_command(new TrexRpcCmdRemoveAllStreams()); register_command(new TrexRpcCmdGetStreamList()); register_command(new TrexRpcCmdGetStream()); + register_command(new TrexRpcCmdGetAllStreams()); register_command(new TrexRpcCmdStartTraffic()); register_command(new TrexRpcCmdStopTraffic()); } diff --git a/src/rx_check.cpp b/src/rx_check.cpp index 3a67ca23..59b42e1a 100755 --- a/src/rx_check.cpp +++ b/src/rx_check.cpp @@ -45,8 +45,8 @@ void CRxCheckFlowTableStats::Clear(){ } -#define MYDP(f) if (f) fprintf(fd," %-40s: %llu \n",#f,f) -#define MYDP_A(f) fprintf(fd," %-40s: %llu \n",#f,f) +#define MYDP(f) if (f) fprintf(fd," %-40s: %llu \n",#f,(unsigned long long)f) +#define MYDP_A(f) fprintf(fd," %-40s: %llu \n",#f,(unsigned long long)f) #define MYDP_J(f) json+=add_json(#f,f); #define MYDP_J_LAST(f) json+=add_json(#f,f,true); @@ -146,7 +146,7 @@ void CRxCheckFlowTableMap::dump_all(FILE *fd){ rx_check_flow_map_iter_t it; for (it= m_map.begin(); it != m_map.end(); ++it) { CRxCheckFlow *lp = it->second; - printf ("flow_id: %d \n",lp->m_flow_id); + printf ("flow_id: %llu \n",(unsigned long long)lp->m_flow_id); } } @@ -208,7 +208,7 @@ std::string CPerTxthreadTemplateInfo::dump_as_json(std::string name){ int i; for (i=0;i<MAX_TEMPLATES_STATS;i++){ char buff[200]; - sprintf(buff,"%llu",m_template_info[i]); + sprintf(buff,"%llu", (unsigned long long)m_template_info[i]); json+=std::string(buff); if ( i < MAX_TEMPLATES_STATS-1) { json+=std::string(","); @@ -231,7 +231,7 @@ void CPerTxthreadTemplateInfo::Dump(FILE *fd){ int i; for (i=0; i<MAX_TEMPLATES_STATS; i++) { if (m_template_info[i]) { - fprintf (fd," template id: %llu %llu \n",i,m_template_info[i]); + fprintf (fd," template id: %d %llu \n",i, (unsigned long long)m_template_info[i]); } } } @@ -484,7 +484,7 @@ void RxCheckManager::DumpTemplate(FILE *fd,bool verbose){ if (cnt==0){ fprintf(fd,"\n"); } - fprintf(fd,"[id:%2d val:%8d,rx:%8d], ",i,lp->get_error_counter(),lp->get_rx_counter()); + fprintf(fd,"[id:%2d val:%8llu,rx:%8llu], ",i, (unsigned long long)lp->get_error_counter(), (unsigned long long)lp->get_rx_counter()); cnt++; if (cnt>5) { cnt=0; @@ -500,7 +500,11 @@ void RxCheckManager::DumpTemplateFull(FILE *fd){ int i; for (i=0; i<MAX_TEMPLATES_STATS;i++ ) { CPerTemplateInfo * lp=get_template(i); - fprintf(fd," template_id_%2d , errors:%8d, jitter: %lu rx : %lu \n",i,lp->get_error_counter(),lp->get_jitter_usec(),lp->get_rx_counter() ); + fprintf(fd," template_id_%2d , errors:%8llu, jitter: %llu rx : %llu \n", + i, + (unsigned long long)lp->get_error_counter(), + (unsigned long long)lp->get_jitter_usec(), + (unsigned long long)lp->get_rx_counter() ); } } @@ -514,7 +518,11 @@ void RxCheckManager::DumpShort(FILE *fd){ DumpTemplate(fd,false); fprintf(fd,"\n"); fprintf(fd,"---\n"); - fprintf(fd," active flows: %8d, fif: %8d, drop: %8d, errors: %8d \n",m_stats.m_active,m_stats.m_fif,m_stats.m_err_drop,m_stats.get_total_err()); + fprintf(fd," active flows: %8llu, fif: %8llu, drop: %8llu, errors: %8llu \n", + (unsigned long long)m_stats.m_active, + (unsigned long long)m_stats.m_fif, + (unsigned long long)m_stats.m_err_drop, + (unsigned long long)m_stats.get_total_err()); fprintf(fd,"------------------------------------------------------------------------------------------------------------\n"); } diff --git a/src/rx_check.h b/src/rx_check.h index 6f9763a2..07f5684c 100755 --- a/src/rx_check.h +++ b/src/rx_check.h @@ -30,9 +30,10 @@ limitations under the License. typedef enum { - CLIENT_SIDE=0, - SERVER_SIDE=1, - CS_NUM=2 + CLIENT_SIDE = 0, + SERVER_SIDE = 1, + CS_NUM = 2, + CS_INVALID = 255 } pkt_dir_enum_t; typedef uint8_t pkt_dir_t ; diff --git a/src/rx_check_header.cpp b/src/rx_check_header.cpp index 8ee580db..5934ee15 100755 --- a/src/rx_check_header.cpp +++ b/src/rx_check_header.cpp @@ -42,11 +42,11 @@ void CRx_check_header::dump(FILE *fd){ void CNatOption::dump(FILE *fd){ - fprintf(fd," op : %lx \n",get_option_type()); - fprintf(fd," ol : %lx \n",get_option_len()); - fprintf(fd," thread_id : %lx \n",get_thread_id()); - fprintf(fd," magic : %lx \n",get_magic()); - fprintf(fd," fid : %lx \n",get_fid()); + fprintf(fd," op : %x \n",get_option_type()); + fprintf(fd," ol : %x \n",get_option_len()); + fprintf(fd," thread_id : %x \n",get_thread_id()); + fprintf(fd," magic : %x \n",get_magic()); + fprintf(fd," fid : %x \n",get_fid()); utl_DumpBuffer(stdout,(void *)&u.m_data[0],8,0); } diff --git a/src/stateless/cp/trex_stateless.cpp b/src/stateless/cp/trex_stateless.cpp index 72762e26..e0e95450 100644 --- a/src/stateless/cp/trex_stateless.cpp +++ b/src/stateless/cp/trex_stateless.cpp @@ -31,55 +31,58 @@ using namespace std; * Trex stateless object * **********************************************************/ -TrexStateless::TrexStateless() { - m_is_configured = false; -} - /** - * configure the singleton stateless object * */ -void TrexStateless::configure(const TrexStatelessCfg &cfg) { - - TrexStateless& instance = get_instance_internal(); - - /* check status */ - if (instance.m_is_configured) { - throw TrexException("re-configuration of stateless object is not allowed"); - } +TrexStateless::TrexStateless(const TrexStatelessCfg &cfg) { /* create RPC servers */ /* set both servers to mutex each other */ - instance.m_rpc_server = new TrexRpcServer(cfg.m_rpc_req_resp_cfg, cfg.m_rpc_async_cfg, &instance.m_global_cp_lock); - instance.m_rpc_server->set_verbose(cfg.m_rpc_server_verbose); + m_rpc_server = new TrexRpcServer(cfg.m_rpc_req_resp_cfg, cfg.m_rpc_async_cfg, &m_global_cp_lock); + m_rpc_server->set_verbose(cfg.m_rpc_server_verbose); /* configure ports */ + m_port_count = cfg.m_port_count; - instance.m_port_count = cfg.m_port_count; - - for (int i = 0; i < instance.m_port_count; i++) { - instance.m_ports.push_back(new TrexStatelessPort(i)); + for (int i = 0; i < m_port_count; i++) { + m_ports.push_back(new TrexStatelessPort(i)); } - /* cores */ - instance.m_dp_core_count = cfg.m_dp_core_count; - for (int i = 0; i < instance.m_dp_core_count; i++) { - instance.m_dp_cores.push_back(new TrexStatelessDpCore(i)); + m_platform_api = cfg.m_platform_api; +} + +/** + * release all memory + * + * @author imarom (08-Oct-15) + */ +TrexStateless::~TrexStateless() { + + /* release memory for ports */ + for (auto port : m_ports) { + delete port; } + m_ports.clear(); + + /* stops the RPC server */ + m_rpc_server->stop(); + delete m_rpc_server; + + m_rpc_server = NULL; - /* done */ - instance.m_is_configured = true; + delete m_platform_api; + m_platform_api = NULL; } + /** * starts the control plane side * */ void TrexStateless::launch_control_plane() { - //std::cout << "\n on control/master core \n"; /* pin this process to the current running CPU any new thread will be called on the same CPU @@ -94,39 +97,6 @@ TrexStateless::launch_control_plane() { m_rpc_server->start(); } -void -TrexStateless::launch_on_dp_core(uint8_t core_id) { - m_dp_cores[core_id - 1]->run(); -} - -/** - * destroy the singleton and release all memory - * - * @author imarom (08-Oct-15) - */ -void -TrexStateless::destroy() { - TrexStateless& instance = get_instance_internal(); - - if (!instance.m_is_configured) { - return; - } - - /* release memory for ports */ - for (auto port : instance.m_ports) { - delete port; - } - instance.m_ports.clear(); - - /* stops the RPC server */ - instance.m_rpc_server->stop(); - delete instance.m_rpc_server; - - instance.m_rpc_server = NULL; - - /* done */ - instance.m_is_configured = false; -} /** * fetch a port by ID @@ -148,57 +118,32 @@ TrexStateless::get_port_count() { uint8_t TrexStateless::get_dp_core_count() { - return m_dp_core_count; -} - -void -TrexStateless::update_stats() { - - /* update CPU util. - TODO - */ - m_stats.m_stats.m_cpu_util = 0; - - /* for every port update and accumulate */ - for (uint8_t i = 0; i < m_port_count; i++) { - m_ports[i]->update_stats(); - - const TrexPortStats & port_stats = m_ports[i]->get_stats(); - - m_stats.m_stats.m_tx_bps += port_stats.m_stats.m_tx_bps; - m_stats.m_stats.m_rx_bps += port_stats.m_stats.m_rx_bps; - - m_stats.m_stats.m_tx_pps += port_stats.m_stats.m_tx_pps; - m_stats.m_stats.m_rx_pps += port_stats.m_stats.m_rx_pps; - - m_stats.m_stats.m_total_tx_pkts += port_stats.m_stats.m_total_tx_pkts; - m_stats.m_stats.m_total_rx_pkts += port_stats.m_stats.m_total_rx_pkts; - - m_stats.m_stats.m_total_tx_bytes += port_stats.m_stats.m_total_tx_bytes; - m_stats.m_stats.m_total_rx_bytes += port_stats.m_stats.m_total_rx_bytes; - - m_stats.m_stats.m_tx_rx_errors += port_stats.m_stats.m_tx_rx_errors; - } + return m_platform_api->get_dp_core_count(); } void TrexStateless::encode_stats(Json::Value &global) { - global["cpu_util"] = m_stats.m_stats.m_cpu_util; + const TrexPlatformApi *api = get_stateless_obj()->get_platform_api(); + + TrexPlatformGlobalStats stats; + api->get_global_stats(stats); - global["tx_bps"] = m_stats.m_stats.m_tx_bps; - global["rx_bps"] = m_stats.m_stats.m_rx_bps; + global["cpu_util"] = stats.m_stats.m_cpu_util; - global["tx_pps"] = m_stats.m_stats.m_tx_pps; - global["rx_pps"] = m_stats.m_stats.m_rx_pps; + global["tx_bps"] = stats.m_stats.m_tx_bps; + global["rx_bps"] = stats.m_stats.m_rx_bps; - global["total_tx_pkts"] = Json::Value::UInt64(m_stats.m_stats.m_total_tx_pkts); - global["total_rx_pkts"] = Json::Value::UInt64(m_stats.m_stats.m_total_rx_pkts); + global["tx_pps"] = stats.m_stats.m_tx_pps; + global["rx_pps"] = stats.m_stats.m_rx_pps; - global["total_tx_bytes"] = Json::Value::UInt64(m_stats.m_stats.m_total_tx_bytes); - global["total_rx_bytes"] = Json::Value::UInt64(m_stats.m_stats.m_total_rx_bytes); + global["total_tx_pkts"] = Json::Value::UInt64(stats.m_stats.m_total_tx_pkts); + global["total_rx_pkts"] = Json::Value::UInt64(stats.m_stats.m_total_rx_pkts); - global["tx_rx_errors"] = Json::Value::UInt64(m_stats.m_stats.m_tx_rx_errors); + global["total_tx_bytes"] = Json::Value::UInt64(stats.m_stats.m_total_tx_bytes); + global["total_rx_bytes"] = Json::Value::UInt64(stats.m_stats.m_total_rx_bytes); + + global["tx_rx_errors"] = Json::Value::UInt64(stats.m_stats.m_tx_rx_errors); for (uint8_t i = 0; i < m_port_count; i++) { std::stringstream ss; @@ -210,3 +155,20 @@ TrexStateless::encode_stats(Json::Value &global) { } } +/** + * generate a snapshot for publish (async publish) + * + */ +void +TrexStateless::generate_publish_snapshot(std::string &snapshot) { + Json::FastWriter writer; + Json::Value root; + + root["name"] = "trex-stateless-info"; + root["type"] = 0; + + /* stateless specific info goes here */ + root["data"] = Json::nullValue; + + snapshot = writer.write(root); +} diff --git a/src/stateless/cp/trex_stateless.h b/src/stateless/cp/trex_stateless.h index 649b25dd..57c6ef1d 100644 --- a/src/stateless/cp/trex_stateless.h +++ b/src/stateless/cp/trex_stateless.h @@ -29,9 +29,10 @@ limitations under the License. #include <trex_stream.h> #include <trex_stateless_port.h> -#include <trex_stateless_dp_core.h> #include <trex_rpc_server_api.h> +#include <internal_api/trex_platform_api.h> + /** * generic exception for errors * TODO: move this to a better place @@ -88,17 +89,17 @@ public: /* default values */ TrexStatelessCfg() { m_port_count = 0; - m_dp_core_count = 0; m_rpc_req_resp_cfg = NULL; m_rpc_async_cfg = NULL; - m_rpc_server_verbose = false; + m_rpc_server_verbose = false; + m_platform_api = NULL; } const TrexRpcServerConfig *m_rpc_req_resp_cfg; const TrexRpcServerConfig *m_rpc_async_cfg; + const TrexPlatformApi *m_platform_api; bool m_rpc_server_verbose; uint8_t m_port_count; - uint8_t m_dp_core_count; }; /** @@ -113,27 +114,8 @@ public: * reconfiguration is not allowed * an exception will be thrown */ - static void configure(const TrexStatelessCfg &cfg); - - /** - * destroy the instance - * - */ - static void destroy(); - - /** - * singleton public get instance - * - */ - static TrexStateless& get_instance() { - TrexStateless& instance = get_instance_internal(); - - if (!instance.m_is_configured) { - throw TrexException("object is not configured"); - } - - return instance; - } + TrexStateless(const TrexStatelessCfg &cfg); + ~TrexStateless(); /** * starts the control plane side @@ -152,12 +134,6 @@ public: uint8_t get_dp_core_count(); - /** - * update all the stats (deep update) - * (include all the ports and global stats) - * - */ - void update_stats(); /** * fetch all the stats @@ -165,22 +141,25 @@ public: */ void encode_stats(Json::Value &global); + /** + * generate a snapshot for publish + */ + void generate_publish_snapshot(std::string &snapshot); -protected: - TrexStateless(); + const TrexPlatformApi * get_platform_api() { + return (m_platform_api); + } - static TrexStateless& get_instance_internal () { - static TrexStateless instance; - return instance; + const std::vector <TrexStatelessPort *> get_port_list() { + return m_ports; } - /* c++ 2011 style singleton */ +protected: + + /* no copy or assignment */ TrexStateless(TrexStateless const&) = delete; void operator=(TrexStateless const&) = delete; - /* status */ - bool m_is_configured; - /* RPC server array */ TrexRpcServer *m_rpc_server; @@ -188,15 +167,20 @@ protected: std::vector <TrexStatelessPort *> m_ports; uint8_t m_port_count; - /* cores */ - std::vector <TrexStatelessDpCore *> m_dp_cores; - uint8_t m_dp_core_count; - - /* stats */ - TrexStatelessStats m_stats; + /* platform API */ + const TrexPlatformApi *m_platform_api; std::mutex m_global_cp_lock; }; +/** + * an anchor function + * + * @author imarom (25-Oct-15) + * + * @return TrexStateless& + */ +TrexStateless * get_stateless_obj(); + #endif /* __TREX_STATELESS_H__ */ diff --git a/src/stateless/cp/trex_stateless_port.cpp b/src/stateless/cp/trex_stateless_port.cpp index a31847a5..cb6fcc0e 100644 --- a/src/stateless/cp/trex_stateless_port.cpp +++ b/src/stateless/cp/trex_stateless_port.cpp @@ -18,20 +18,34 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ + #include <trex_stateless.h> #include <trex_stateless_port.h> +#include <trex_stateless_messaging.h> +#include <trex_streams_compiler.h> + #include <string> #ifndef TREX_RPC_MOCK_SERVER + // DPDK c++ issue -#define UINT8_MAX 255 -#define UINT16_MAX 0xFFFF +#ifndef UINT8_MAX + #define UINT8_MAX 255 +#endif + +#ifndef UINT16_MAX + #define UINT16_MAX 0xFFFF +#endif + // DPDK c++ issue #endif #include <rte_ethdev.h> #include <os_time.h> +void +port_id_to_cores(uint8_t port_id, std::vector<std::pair<uint8_t, uint8_t>> &cores_id_list); + using namespace std; /*************************** @@ -49,7 +63,7 @@ TrexStatelessPort::TrexStatelessPort(uint8_t port_id) : m_port_id(port_id) { * */ TrexStatelessPort::rc_e -TrexStatelessPort::start_traffic(void) { +TrexStatelessPort::start_traffic(double mul) { if (m_port_state != PORT_STATE_UP_IDLE) { return (RC_ERR_BAD_STATE_FOR_OP); @@ -59,19 +73,46 @@ TrexStatelessPort::start_traffic(void) { return (RC_ERR_NO_STREAMS); } + /* fetch all the streams from the table */ + vector<TrexStream *> streams; + get_stream_table()->get_object_list(streams); + + /* compiler it */ + TrexStreamsCompiler compiler; + TrexStreamsCompiledObj *compiled_obj = new TrexStreamsCompiledObj(m_port_id, mul); + + bool rc = compiler.compile(streams, *compiled_obj); + if (!rc) { + return (RC_ERR_FAILED_TO_COMPILE_STREAMS); + } + + /* generate a message to all the relevant DP cores to start transmitting */ + TrexStatelessCpToDpMsgBase *start_msg = new TrexStatelessDpStart(compiled_obj); + + send_message_to_dp(start_msg); + + /* move the state to transmiting */ m_port_state = PORT_STATE_TRANSMITTING; - /* real code goes here */ return (RC_OK); } -void +TrexStatelessPort::rc_e TrexStatelessPort::stop_traffic(void) { /* real code goes here */ - if (m_port_state == PORT_STATE_TRANSMITTING) { - m_port_state = PORT_STATE_UP_IDLE; + if (m_port_state != PORT_STATE_TRANSMITTING) { + return (RC_ERR_BAD_STATE_FOR_OP); } + + /* generate a message to all the relevant DP cores to start transmitting */ + TrexStatelessCpToDpMsgBase *stop_msg = new TrexStatelessDpStop(m_port_id); + + send_message_to_dp(stop_msg); + + m_port_state = PORT_STATE_UP_IDLE; + + return (RC_OK); } /** @@ -130,99 +171,42 @@ TrexStatelessPort::generate_handler() { return (ss.str()); } -/** - * update stats for the port - * - */ -void -TrexStatelessPort::update_stats() { - struct rte_eth_stats stats; - rte_eth_stats_get(m_port_id, &stats); - - /* copy straight values */ - m_stats.m_stats.m_total_tx_bytes = stats.obytes; - m_stats.m_stats.m_total_rx_bytes = stats.ibytes; - - m_stats.m_stats.m_total_tx_pkts = stats.opackets; - m_stats.m_stats.m_total_rx_pkts = stats.ipackets; - - /* calculate stats */ - m_stats.m_stats.m_tx_bps = m_stats.m_bw_tx_bps.add(stats.obytes); - m_stats.m_stats.m_rx_bps = m_stats.m_bw_rx_bps.add(stats.ibytes); - - m_stats.m_stats.m_tx_pps = m_stats.m_bw_tx_pps.add(stats.opackets); - m_stats.m_stats.m_rx_pps = m_stats.m_bw_rx_pps.add(stats.ipackets); - -} - -const TrexPortStats & -TrexStatelessPort::get_stats() { - return m_stats; -} void TrexStatelessPort::encode_stats(Json::Value &port) { - port["tx_bps"] = m_stats.m_stats.m_tx_bps; - port["rx_bps"] = m_stats.m_stats.m_rx_bps; + const TrexPlatformApi *api = get_stateless_obj()->get_platform_api(); - port["tx_pps"] = m_stats.m_stats.m_tx_pps; - port["rx_pps"] = m_stats.m_stats.m_rx_pps; + TrexPlatformInterfaceStats stats; + api->get_interface_stats(m_port_id, stats); - port["total_tx_pkts"] = Json::Value::UInt64(m_stats.m_stats.m_total_tx_pkts); - port["total_rx_pkts"] = Json::Value::UInt64(m_stats.m_stats.m_total_rx_pkts); + port["tx_bps"] = stats.m_stats.m_tx_bps; + port["rx_bps"] = stats.m_stats.m_rx_bps; - port["total_tx_bytes"] = Json::Value::UInt64(m_stats.m_stats.m_total_tx_bytes); - port["total_rx_bytes"] = Json::Value::UInt64(m_stats.m_stats.m_total_rx_bytes); - - port["tx_rx_errors"] = Json::Value::UInt64(m_stats.m_stats.m_tx_rx_errors); -} + port["tx_pps"] = stats.m_stats.m_tx_pps; + port["rx_pps"] = stats.m_stats.m_rx_pps; + port["total_tx_pkts"] = Json::Value::UInt64(stats.m_stats.m_total_tx_pkts); + port["total_rx_pkts"] = Json::Value::UInt64(stats.m_stats.m_total_rx_pkts); - -/*************************** - * BW measurement - * - **************************/ -/* TODO: move this to a common place */ -BWMeasure::BWMeasure() { - reset(); + port["total_tx_bytes"] = Json::Value::UInt64(stats.m_stats.m_total_tx_bytes); + port["total_rx_bytes"] = Json::Value::UInt64(stats.m_stats.m_total_rx_bytes); + + port["tx_rx_errors"] = Json::Value::UInt64(stats.m_stats.m_tx_rx_errors); } -void BWMeasure::reset(void) { - m_start=false; - m_last_time_msec=0; - m_last_bytes=0; - m_last_result=0.0; -}; - -double BWMeasure::calc_MBsec(uint32_t dtime_msec, - uint64_t dbytes){ - double rate=0.000008*( ( (double)dbytes*(double)os_get_time_freq())/((double)dtime_msec) ); - return(rate); -} +void +TrexStatelessPort::send_message_to_dp(TrexStatelessCpToDpMsgBase *msg) { -double BWMeasure::add(uint64_t size) { - if ( false == m_start ) { - m_start=true; - m_last_time_msec = os_get_time_msec() ; - m_last_bytes=size; - return(0.0); - } + std::vector<std::pair<uint8_t, uint8_t>> cores_id_list; - uint32_t ctime=os_get_time_msec(); - if ((ctime - m_last_time_msec) <os_get_time_freq() ) { - return(m_last_result); - } + get_stateless_obj()->get_platform_api()->port_id_to_cores(m_port_id, cores_id_list); - uint32_t dtime_msec = ctime-m_last_time_msec; - uint64_t dbytes = size - m_last_bytes; + for (auto core_pair : cores_id_list) { - m_last_time_msec = ctime; - m_last_bytes = size; + /* send the message to the core */ + CNodeRing *ring = CMsgIns::Ins()->getCpDp()->getRingCpToDp(core_pair.first); + ring->Enqueue((CGenNode *)msg->clone()); + } - m_last_result= 0.5*calc_MBsec(dtime_msec,dbytes) +0.5*(m_last_result); - return( m_last_result ); } - - diff --git a/src/stateless/cp/trex_stateless_port.h b/src/stateless/cp/trex_stateless_port.h index 428d5aee..09183768 100644 --- a/src/stateless/cp/trex_stateless_port.h +++ b/src/stateless/cp/trex_stateless_port.h @@ -23,70 +23,7 @@ limitations under the License. #include <trex_stream.h> -/** - * bandwidth measurement class - * - */ -class BWMeasure { -public: - BWMeasure(); - void reset(void); - double add(uint64_t size); - -private: - double calc_MBsec(uint32_t dtime_msec, - uint64_t dbytes); - -public: - bool m_start; - uint32_t m_last_time_msec; - uint64_t m_last_bytes; - double m_last_result; -}; - -/** - * TRex stateless port stats - * - * @author imarom (24-Sep-15) - */ -class TrexPortStats { - -public: - TrexPortStats() { - m_stats = {0}; - - m_bw_tx_bps.reset(); - m_bw_rx_bps.reset(); - - m_bw_tx_pps.reset(); - m_bw_rx_pps.reset(); - } - -public: - - BWMeasure m_bw_tx_bps; - BWMeasure m_bw_rx_bps; - - BWMeasure m_bw_tx_pps; - BWMeasure m_bw_rx_pps; - - struct { - - double m_tx_bps; - double m_rx_bps; - - double m_tx_pps; - double m_rx_pps; - - uint64_t m_total_tx_pkts; - uint64_t m_total_rx_pkts; - - uint64_t m_total_tx_bytes; - uint64_t m_total_rx_bytes; - - uint64_t m_tx_rx_errors; - } m_stats; -}; +class TrexStatelessCpToDpMsgBase; /** * describes a stateless port @@ -121,13 +58,13 @@ public: * start traffic * */ - rc_e start_traffic(void); + rc_e start_traffic(double mul); /** * stop traffic * */ - void stop_traffic(void); + rc_e stop_traffic(void); /** * access the stream table @@ -203,28 +140,25 @@ public: } /** - * update the values of the stats - * - */ - void update_stats(); - - const TrexPortStats & get_stats(); - - /** * encode stats as JSON */ void encode_stats(Json::Value &port); + uint8_t get_port_id() { + return m_port_id; + } + private: std::string generate_handler(); + void send_message_to_dp(TrexStatelessCpToDpMsgBase *msg); + TrexStreamTable m_stream_table; uint8_t m_port_id; port_state_e m_port_state; std::string m_owner; std::string m_owner_handler; - TrexPortStats m_stats; }; #endif /* __TREX_STATELESS_PORT_H__ */ diff --git a/src/stateless/cp/trex_stream.cpp b/src/stateless/cp/trex_stream.cpp index 182036f1..ba306137 100644 --- a/src/stateless/cp/trex_stream.cpp +++ b/src/stateless/cp/trex_stream.cpp @@ -20,6 +20,7 @@ limitations under the License. */ #include <trex_stream.h> #include <cstddef> +#include <string.h> /************************************** * stream @@ -103,14 +104,24 @@ TrexStream * TrexStreamTable::get_stream_by_id(uint32_t stream_id) { } } -void TrexStreamTable::get_stream_list(std::vector<uint32_t> &stream_list) { - stream_list.clear(); +void TrexStreamTable::get_id_list(std::vector<uint32_t> &id_list) { + id_list.clear(); for (auto stream : m_stream_table) { - stream_list.push_back(stream.first); + id_list.push_back(stream.first); } } +void TrexStreamTable::get_object_list(std::vector<TrexStream *> &object_list) { + object_list.clear(); + + for (auto stream : m_stream_table) { + object_list.push_back(stream.second); + } + +} + int TrexStreamTable::size() { return m_stream_table.size(); } + diff --git a/src/stateless/cp/trex_stream.h b/src/stateless/cp/trex_stream.h index f5bc96ef..c8a15240 100644 --- a/src/stateless/cp/trex_stream.h +++ b/src/stateless/cp/trex_stream.h @@ -37,10 +37,6 @@ class TrexRpcCmdAddStream; * */ class TrexStream { - /* provide the RPC parser a way to access private fields */ - friend class TrexRpcCmdAddStream; - friend class TrexRpcCmdGetStream; - friend class TrexStreamTable; public: TrexStream(uint8_t port_id, uint32_t stream_id); @@ -56,7 +52,7 @@ public: /* access the stream json */ const Json::Value & get_stream_json(); -protected: +public: /* basic */ uint8_t m_port_id; uint32_t m_stream_id; @@ -189,7 +185,13 @@ public: * * @param stream_list */ - void get_stream_list(std::vector<uint32_t> &stream_list); + void get_id_list(std::vector<uint32_t> &id_list); + + /** + * populate a list with all the stream objects + * + */ + void get_object_list(std::vector<TrexStream *> &object_list); /** * get the table size @@ -197,6 +199,9 @@ public: */ int size(); + std::unordered_map<int, TrexStream *>::iterator begin() {return m_stream_table.begin();} + std::unordered_map<int, TrexStream *>::iterator end() {return m_stream_table.end();} + private: /** * holds all the stream in a hash table by stream id diff --git a/src/stateless/cp/trex_streams_compiler.cpp b/src/stateless/cp/trex_streams_compiler.cpp new file mode 100644 index 00000000..06c0119a --- /dev/null +++ b/src/stateless/cp/trex_streams_compiler.cpp @@ -0,0 +1,106 @@ +/* + Itay Marom + Cisco Systems, Inc. +*/ + +/* +Copyright (c) 2015-2015 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include <string.h> +#include <trex_streams_compiler.h> +#include <trex_stream.h> + +/************************************** + * stream compiled object + *************************************/ +TrexStreamsCompiledObj::TrexStreamsCompiledObj(uint8_t port_id, double mul) : m_port_id(port_id), m_mul(mul) { +} + +TrexStreamsCompiledObj::~TrexStreamsCompiledObj() { + for (auto &obj : m_objs) { + delete obj.m_pkt; + } + m_objs.clear(); +} + +void +TrexStreamsCompiledObj::add_compiled_stream(double isg_usec, double pps, uint8_t *pkt, uint16_t pkt_len) { + obj_st obj; + + obj.m_isg_usec = isg_usec; + obj.m_port_id = m_port_id; + obj.m_pps = pps * m_mul; + obj.m_pkt_len = pkt_len; + + obj.m_pkt = new uint8_t[pkt_len]; + memcpy(obj.m_pkt, pkt, pkt_len); + + m_objs.push_back(obj); +} + +TrexStreamsCompiledObj * +TrexStreamsCompiledObj::clone() { + + TrexStreamsCompiledObj *new_compiled_obj = new TrexStreamsCompiledObj(m_port_id, m_mul); + + /** + * clone each element + */ + for (auto obj : m_objs) { + new_compiled_obj->add_compiled_stream(obj.m_isg_usec, + obj.m_pps, + obj.m_pkt, + obj.m_pkt_len); + } + + return new_compiled_obj; +} + +/************************************** + * stream compiler + *************************************/ +bool +TrexStreamsCompiler::compile(const std::vector<TrexStream *> &streams, TrexStreamsCompiledObj &obj) { + /* for now we do something trivial, */ + for (auto stream : streams) { + + /* skip non-enabled streams */ + if (!stream->m_enabled) { + continue; + } + + /* for now skip also non self started streams */ + if (!stream->m_self_start) { + continue; + } + + /* for now support only continous ... */ + TrexStreamContinuous *cont_stream = dynamic_cast<TrexStreamContinuous *>(stream); + if (!cont_stream) { + continue; + } + + /* add it */ + obj.add_compiled_stream(cont_stream->m_isg_usec, + cont_stream->get_pps(), + cont_stream->m_pkt.binary, + cont_stream->m_pkt.len); + } + + return true; +} + + diff --git a/src/stateless/cp/trex_streams_compiler.h b/src/stateless/cp/trex_streams_compiler.h new file mode 100644 index 00000000..404fdd21 --- /dev/null +++ b/src/stateless/cp/trex_streams_compiler.h @@ -0,0 +1,79 @@ +/* + Itay Marom + Cisco Systems, Inc. +*/ + +/* +Copyright (c) 2015-2015 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +#ifndef __TREX_STREAMS_COMPILER_H__ +#define __TREX_STREAMS_COMPILER_H__ + +#include <stdint.h> +#include <vector> + +class TrexStreamsCompiler; +class TrexStream; + +/** + * compiled object for a table of streams + * + * @author imarom (28-Oct-15) + */ +class TrexStreamsCompiledObj { + friend class TrexStreamsCompiler; +public: + + TrexStreamsCompiledObj(uint8_t port_id, double m_mul); + ~TrexStreamsCompiledObj(); + + struct obj_st { + double m_isg_usec; + double m_pps; + uint8_t *m_pkt; + uint16_t m_pkt_len; + uint8_t m_port_id; + }; + + const std::vector<obj_st> & get_objects() { + return m_objs; + } + + /** + * clone the compiled object + * + */ + TrexStreamsCompiledObj * clone(); + +private: + void add_compiled_stream(double isg_usec, double pps, uint8_t *pkt, uint16_t pkt_len); + std::vector<obj_st> m_objs; + + uint8_t m_port_id; + double m_mul; +}; + +class TrexStreamsCompiler { +public: + /** + * compiles a vector of streams to an object passable to the DP + * + * @author imarom (28-Oct-15) + * + */ + bool compile(const std::vector<TrexStream *> &streams, TrexStreamsCompiledObj &obj); +}; + +#endif /* __TREX_STREAMS_COMPILER_H__ */ diff --git a/src/stateless/dp/trex_stateless_dp_core.cpp b/src/stateless/dp/trex_stateless_dp_core.cpp index 3755b82c..b2bd0152 100644 --- a/src/stateless/dp/trex_stateless_dp_core.cpp +++ b/src/stateless/dp/trex_stateless_dp_core.cpp @@ -18,118 +18,186 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ - #include <trex_stateless_dp_core.h> -#include <stdio.h> -#include <unistd.h> -#include <trex_stateless.h> +#include <trex_stateless_messaging.h> +#include <trex_streams_compiler.h> +#include <trex_stream_node.h> #include <bp_sim.h> -#ifndef TREX_RPC_MOCK_SERVER +static inline double +usec_to_sec(double usec) { + return (usec / (1000 * 1000)); +} + -// DPDK c++ issue -#define UINT8_MAX 255 -#define UINT16_MAX 0xFFFF -// DPDK c++ issue -#endif +void +TrexStatelessDpCore::create(uint8_t thread_id, CFlowGenListPerThread *core) { + m_thread_id = thread_id; + m_core = core; -#include <rte_ethdev.h> -#include "mbuf.h" + CMessagingManager * cp_dp = CMsgIns::Ins()->getCpDp(); + + m_ring_from_cp = cp_dp->getRingCpToDp(thread_id); + m_ring_to_cp = cp_dp->getRingDpToCp(thread_id); + + m_state = STATE_IDLE; +} /** - * TEST + * in idle state loop, the processor most of the time sleeps + * and periodically checks for messages * + * @author imarom (01-Nov-15) */ -static const uint8_t udp_pkt[]={ - 0x00,0x00,0x00,0x01,0x00,0x00, - 0x00,0x00,0x00,0x01,0x00,0x00, - 0x08,0x00, - - 0x45,0x00,0x00,0x81, - 0xaf,0x7e,0x00,0x00, - 0x12,0x11,0xd9,0x23, - 0x01,0x01,0x01,0x01, - 0x3d,0xad,0x72,0x1b, - - 0x11,0x11, - 0x11,0x11, - - 0x00,0x6d, - 0x00,0x00, - - 0x64,0x31,0x3a,0x61, - 0x64,0x32,0x3a,0x69,0x64, - 0x32,0x30,0x3a,0xd0,0x0e, - 0xa1,0x4b,0x7b,0xbd,0xbd, - 0x16,0xc6,0xdb,0xc4,0xbb,0x43, - 0xf9,0x4b,0x51,0x68,0x33,0x72, - 0x20,0x39,0x3a,0x69,0x6e,0x66,0x6f, - 0x5f,0x68,0x61,0x73,0x68,0x32,0x30,0x3a,0xee,0xc6,0xa3, - 0xd3,0x13,0xa8,0x43,0x06,0x03,0xd8,0x9e,0x3f,0x67,0x6f, - 0xe7,0x0a,0xfd,0x18,0x13,0x8d,0x65,0x31,0x3a,0x71,0x39, - 0x3a,0x67,0x65,0x74,0x5f,0x70,0x65,0x65,0x72,0x73,0x31, - 0x3a,0x74,0x38,0x3a,0x3d,0xeb,0x0c,0xbf,0x0d,0x6a,0x0d, - 0xa5,0x31,0x3a,0x79,0x31,0x3a,0x71,0x65,0x87,0xa6,0x7d, - 0xe7 -}; - -static int -test_inject_pkt(uint8_t *pkt, uint32_t pkt_size) { - - #ifndef TREX_RPC_MOCK_SERVER - rte_mempool_t * mp= CGlobalInfo::m_mem_pool[0].m_big_mbuf_pool ; - #else - rte_mempool_t * mp = NULL; - #endif - - rte_mbuf_t *m = rte_pktmbuf_alloc(mp); - if ( unlikely(m==0) ) { - printf("ERROR no packets \n"); - return (-1); +void +TrexStatelessDpCore::idle_state_loop() { + + while (m_state == STATE_IDLE) { + periodic_check_for_cp_messages(); + delay(200); } +} + +/** + * scehduler runs when traffic exists + * it will return when no more transmitting is done on this + * core + * + * @author imarom (01-Nov-15) + */ +void +TrexStatelessDpCore::start_scheduler() { + /* creates a maintenace job using the scheduler */ + CGenNode * node_sync = m_core->create_node() ; + node_sync->m_type = CGenNode::FLOW_SYNC; + node_sync->m_time = m_core->m_cur_time_sec + SYNC_TIME_OUT; + m_core->m_node_gen.add_node(node_sync); + + double old_offset = 0.0; + m_core->m_node_gen.flush_file(-1, 0.0, false, m_core, old_offset); + m_core->m_node_gen.close_file(m_core); +} + +void +TrexStatelessDpCore::start() { + + while (true) { + idle_state_loop(); + + start_scheduler(); + } +} + +void +TrexStatelessDpCore::add_cont_stream(uint8_t port_id, + double isg_usec, + double pps, + const uint8_t *pkt, + uint16_t pkt_len) { + + CGenNodeStateless *node = m_core->create_node_sl(); + + /* add periodic */ + node->m_type = CGenNode::STATELESS_PKT; + + node->m_time = m_core->m_cur_time_sec + usec_to_sec(isg_usec); + + pkt_dir_t dir = m_core->m_node_gen.m_v_if->port_id_to_dir(port_id); + node->m_flags = 0; + + /* set socket id */ + node->set_socket_id(m_core->m_node_gen.m_socket_id); + + /* build a mbuf from a packet */ + uint16_t pkt_size = pkt_len; + const uint8_t *stream_pkt = pkt; + + /* stateless specific fields */ + node->m_next_time_offset = 1.0 / pps; + node->m_is_stream_active = 1; + node->m_port_id = port_id; + + /* allocate const mbuf */ + rte_mbuf_t *m = CGlobalInfo::pktmbuf_alloc(node->get_socket_id(), pkt_size); + assert(m); + char *p = rte_pktmbuf_append(m, pkt_size); assert(p); - /* set pkt data */ - memcpy(p,pkt,pkt_size); + /* copy the packet */ + memcpy(p,stream_pkt,pkt_size); - rte_mbuf_t *tx_pkts[32]; - tx_pkts[0] = m; - uint8_t nb_pkts = 1; - uint16_t ret = rte_eth_tx_burst(0, 0, tx_pkts, nb_pkts); - (void)ret; - rte_pktmbuf_free(m); + /* set dir 0 or 1 client or server */ + node->set_mbuf_cache_dir(dir); - return (0); -} + /* TBD repace the mac if req we should add flag */ + m_core->m_node_gen.m_v_if->update_mac_addr_from_global_cfg(dir, m); + + /* set the packet as a readonly */ + node->set_cache_mbuf(m); + + /* keep track */ + m_active_nodes.push_back(node); + + /* schedule */ + m_core->m_node_gen.add_node((CGenNode *)node); + + m_state = TrexStatelessDpCore::STATE_TRANSMITTING; -static int -test_inject_udp_pkt(){ - return (test_inject_pkt((uint8_t*)udp_pkt,sizeof(udp_pkt))); } void -TrexStatelessDpCore::test_inject_dummy_pkt() { - test_inject_udp_pkt(); +TrexStatelessDpCore::start_traffic(TrexStreamsCompiledObj *obj) { + for (auto single_stream : obj->get_objects()) { + add_cont_stream(single_stream.m_port_id, + single_stream.m_isg_usec, + single_stream.m_pps, + single_stream.m_pkt, + single_stream.m_pkt_len); + } } -/*************************** - * DP core - * - **************************/ -TrexStatelessDpCore::TrexStatelessDpCore(uint8_t core_id) : m_core_id(core_id) { +void +TrexStatelessDpCore::stop_traffic(uint8_t port_id) { + /* we cannot remove nodes not from the top of the queue so + for every active node - make sure next time + the scheduler invokes it, it will be free */ + for (auto node : m_active_nodes) { + if (node->m_port_id == port_id) { + node->m_is_stream_active = 0; + } + } + + /* remove all the non active nodes */ + auto pred = std::remove_if(m_active_nodes.begin(), + m_active_nodes.end(), + [](CGenNodeStateless *node) { return (!node->m_is_stream_active); }); + + m_active_nodes.erase(pred, m_active_nodes.end()); + + if (m_active_nodes.size() == 0) { + m_state = STATE_IDLE; + /* stop the scheduler */ + + CGenNode *node = m_core->create_node() ; + + node->m_type = CGenNode::EXIT_SCHED; + + /* make sure it will be scheduled after the current node */ + node->m_time = m_core->m_cur_time_sec + 0.0001; + + m_core->m_node_gen.add_node(node); + } + } /** - * main function for DP core + * handle a message from CP to DP * */ -void -TrexStatelessDpCore::run() { - printf("\nOn DP core %d\n", m_core_id); - while (true) { - test_inject_dummy_pkt(); - rte_pause(); - } +void +TrexStatelessDpCore::handle_cp_msg(TrexStatelessCpToDpMsgBase *msg) { + msg->handle(this); + delete msg; } diff --git a/src/stateless/dp/trex_stateless_dp_core.h b/src/stateless/dp/trex_stateless_dp_core.h index 4b09b752..f4dbad08 100644 --- a/src/stateless/dp/trex_stateless_dp_core.h +++ b/src/stateless/dp/trex_stateless_dp_core.h @@ -21,23 +21,128 @@ limitations under the License. #ifndef __TREX_STATELESS_DP_CORE_H__ #define __TREX_STATELESS_DP_CORE_H__ -#include <stdint.h> +#include <vector> + +#include <msg_manager.h> +#include <pal_utl.h> + +class TrexStatelessCpToDpMsgBase; +class TrexStatelessDpStart; +class CFlowGenListPerThread; +class CGenNodeStateless; +class TrexStreamsCompiledObj; -/** - * stateless DP core object - * - */ class TrexStatelessDpCore { + public: - TrexStatelessDpCore(uint8_t core_id); + /* states */ + enum state_e { + STATE_IDLE, + STATE_TRANSMITTING + }; + + TrexStatelessDpCore() { + m_thread_id = 0; + m_core = NULL; + } + + /** + * "static constructor" + * + * @param thread_id + * @param core + */ + void create(uint8_t thread_id, CFlowGenListPerThread *core); + + /** + * launch the stateless DP core code + * + */ + void start(); + + /** + * dummy traffic creator + * + * @author imarom (27-Oct-15) + * + * @param pkt + * @param pkt_len + */ + void start_traffic(TrexStreamsCompiledObj *obj); + + /** + * stop all traffic for this core + * + */ + void stop_traffic(uint8_t port_id); + + /** + * check for and handle messages from CP + * + * @author imarom (27-Oct-15) + */ + void periodic_check_for_cp_messages() { + // doing this inline for performance reasons + + /* fast path */ + if ( likely ( m_ring_from_cp->isEmpty() ) ) { + return; + } - /* starts the DP core run */ - void run(); + while ( true ) { + CGenNode * node = NULL; + if (m_ring_from_cp->Dequeue(node) != 0) { + break; + } + assert(node); + + TrexStatelessCpToDpMsgBase * msg = (TrexStatelessCpToDpMsgBase *)node; + handle_cp_msg(msg); + } + + } private: - void test_inject_dummy_pkt(); - uint8_t m_core_id; + /** + * in idle state loop, the processor most of the time sleeps + * and periodically checks for messages + * + */ + void idle_state_loop(); + + /** + * real job is done when scheduler is launched + * + */ + void start_scheduler(); + + /** + * handles a CP to DP message + * + * @author imarom (27-Oct-15) + * + * @param msg + */ + void handle_cp_msg(TrexStatelessCpToDpMsgBase *msg); + + void add_cont_stream(uint8_t dir, + double isg, + double pps, + const uint8_t *pkt, + uint16_t pkt_len); + + uint8_t m_thread_id; + state_e m_state; + CNodeRing *m_ring_from_cp; + CNodeRing *m_ring_to_cp; + + /* holds the current active nodes */ + std::vector<CGenNodeStateless *> m_active_nodes; + + /* pointer to the main object */ + CFlowGenListPerThread *m_core; }; #endif /* __TREX_STATELESS_DP_CORE_H__ */ + diff --git a/src/stateless/dp/trex_stream_node.h b/src/stateless/dp/trex_stream_node.h new file mode 100644 index 00000000..92b428ab --- /dev/null +++ b/src/stateless/dp/trex_stream_node.h @@ -0,0 +1,105 @@ +/* + Itay Marom + Cisco Systems, Inc. +*/ + +/* +Copyright (c) 2015-2015 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +#ifndef __TREX_STREAM_NODE_H__ +#define __TREX_STREAM_NODE_H__ + +#include <bp_sim.h> + +class TrexStatelessDpCore; + +/* this is a event for stateless */ +struct CGenNodeStateless : public CGenNodeBase { +friend class TrexStatelessDpCore; + +private: + void * m_cache_mbuf; + + double m_next_time_offset; + uint8_t m_is_stream_active; + uint8_t m_port_id; + + /* pad to match the size of CGenNode */ + uint8_t m_pad_end[87]; + + +public: + + inline bool is_active() { + return m_is_stream_active; + } + + + /** + * main function to handle an event of a packet tx + * + */ + inline void handle(CFlowGenListPerThread *thread) { + + thread->m_node_gen.m_v_if->send_node( (CGenNode *)this); + + /* in case of continues */ + m_time += m_next_time_offset; + + /* insert a new event */ + thread->m_node_gen.m_p_queue.push( (CGenNode *)this); + } + + void set_socket_id(socket_id_t socket){ + m_socket_id=socket; + } + + socket_id_t get_socket_id(){ + return ( m_socket_id ); + } + + inline void set_mbuf_cache_dir(pkt_dir_t dir){ + if (dir) { + m_flags |=NODE_FLAGS_DIR; + }else{ + m_flags &=~NODE_FLAGS_DIR; + } + } + + inline pkt_dir_t get_mbuf_cache_dir(){ + return ((pkt_dir_t)( m_flags &1)); + } + + + + inline void set_cache_mbuf(rte_mbuf_t * m){ + m_cache_mbuf=(void *)m; + m_flags |= NODE_FLAGS_MBUF_CACHE; + } + + inline rte_mbuf_t * get_cache_mbuf(){ + if ( m_flags &NODE_FLAGS_MBUF_CACHE ) { + return ((rte_mbuf_t *)m_cache_mbuf); + }else{ + return ((rte_mbuf_t *)0); + } + } + + +} __rte_cache_aligned; + +static_assert(sizeof(CGenNodeStateless) == sizeof(CGenNode), "sizeof(CGenNodeStateless) != sizeof(CGenNode)"); + +#endif /* __TREX_STREAM_NODE_H__ */ diff --git a/src/stateless/messaging/trex_stateless_messaging.cpp b/src/stateless/messaging/trex_stateless_messaging.cpp new file mode 100644 index 00000000..032559bc --- /dev/null +++ b/src/stateless/messaging/trex_stateless_messaging.cpp @@ -0,0 +1,78 @@ +/* + Itay Marom + Cisco Systems, Inc. +*/ + +/* +Copyright (c) 2015-2015 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +#include <trex_stateless_messaging.h> +#include <trex_stateless_dp_core.h> +#include <trex_streams_compiler.h> +#include <string.h> + +/************************* + start traffic message + ************************/ +TrexStatelessDpStart::TrexStatelessDpStart(TrexStreamsCompiledObj *obj) : m_obj(obj) { +} + + +/** + * clone for DP start message + * + */ +TrexStatelessCpToDpMsgBase * +TrexStatelessDpStart::clone() { + + TrexStreamsCompiledObj *new_obj = m_obj->clone(); + + TrexStatelessCpToDpMsgBase *new_msg = new TrexStatelessDpStart(new_obj); + + return new_msg; +} + +TrexStatelessDpStart::~TrexStatelessDpStart() { + if (m_obj) { + delete m_obj; + } +} + +bool +TrexStatelessDpStart::handle(TrexStatelessDpCore *dp_core) { + + dp_core->start_traffic(m_obj); + return true; +} + +/************************* + stop traffic message + ************************/ +bool +TrexStatelessDpStop::handle(TrexStatelessDpCore *dp_core) { + dp_core->stop_traffic(m_port_id); + return true; +} + +/** + * clone for DP stop message + * + */ +TrexStatelessCpToDpMsgBase * +TrexStatelessDpStop::clone() { + TrexStatelessCpToDpMsgBase *new_msg = new TrexStatelessDpStop(m_port_id); + + return new_msg; +} diff --git a/src/stateless/messaging/trex_stateless_messaging.h b/src/stateless/messaging/trex_stateless_messaging.h new file mode 100644 index 00000000..7978b7f9 --- /dev/null +++ b/src/stateless/messaging/trex_stateless_messaging.h @@ -0,0 +1,101 @@ +/* + Itay Marom + Cisco Systems, Inc. +*/ + +/* +Copyright (c) 2015-2015 Cisco Systems, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +#ifndef __TREX_STATELESS_MESSAGING_H__ +#define __TREX_STATELESS_MESSAGING_H__ + +#include <msg_manager.h> + +class TrexStatelessDpCore; +class TrexStreamsCompiledObj; + +/** + * defines the base class for CP to DP messages + * + * @author imarom (27-Oct-15) + */ +class TrexStatelessCpToDpMsgBase { +public: + + TrexStatelessCpToDpMsgBase() { + } + + virtual ~TrexStatelessCpToDpMsgBase() { + } + + /** + * virtual function to handle a message + * + */ + virtual bool handle(TrexStatelessDpCore *dp_core) = 0; + + + /** + * clone the current message + * + */ + virtual TrexStatelessCpToDpMsgBase * clone() = 0; + + /* no copy constructor */ + TrexStatelessCpToDpMsgBase(TrexStatelessCpToDpMsgBase &) = delete; + +}; + +/** + * a message to start traffic + * + * @author imarom (27-Oct-15) + */ +class TrexStatelessDpStart : public TrexStatelessCpToDpMsgBase { +public: + + TrexStatelessDpStart(TrexStreamsCompiledObj *obj); + + ~TrexStatelessDpStart(); + + virtual bool handle(TrexStatelessDpCore *dp_core); + + virtual TrexStatelessCpToDpMsgBase * clone(); + +private: + TrexStreamsCompiledObj *m_obj; +}; + +/** + * a message to stop traffic + * + * @author imarom (27-Oct-15) + */ +class TrexStatelessDpStop : public TrexStatelessCpToDpMsgBase { +public: + + TrexStatelessDpStop(uint8_t port_id) : m_port_id(port_id) { + } + + virtual bool handle(TrexStatelessDpCore *dp_core); + + virtual TrexStatelessCpToDpMsgBase * clone(); + +private: + uint8_t m_port_id; +}; + + +#endif /* __TREX_STATELESS_MESSAGING_H__ */ diff --git a/src/stub/trex_stateless_stub.cpp b/src/stub/trex_stateless_stub.cpp new file mode 100644 index 00000000..199356d8 --- /dev/null +++ b/src/stub/trex_stateless_stub.cpp @@ -0,0 +1,23 @@ + +#include <trex_stateless_dp_core.h> + +class CFlowGenListPerThread; +class TrexStatelessCpToDpMsgBase; + +void +TrexStatelessDpCore::create(unsigned char, CFlowGenListPerThread*) { + m_thread_id = 0; + m_core = NULL; + + m_state = STATE_IDLE; + + CMessagingManager * cp_dp = CMsgIns::Ins()->getCpDp(); + + m_ring_from_cp = cp_dp->getRingCpToDp(0); + m_ring_to_cp = cp_dp->getRingDpToCp(0); +} + +void TrexStatelessDpCore::start(){} + +void TrexStatelessDpCore::handle_cp_msg(TrexStatelessCpToDpMsgBase*) {} + diff --git a/src/time_histogram.cpp b/src/time_histogram.cpp index f1b47e59..96796bfc 100755 --- a/src/time_histogram.cpp +++ b/src/time_histogram.cpp @@ -182,10 +182,10 @@ void CTimeHistogram::DumpWinMax(FILE *fd){ } void CTimeHistogram::Dump(FILE *fd){ - fprintf (fd," min_delta : %lu usec \n",get_usec(m_min_delta)); + fprintf (fd," min_delta : %lu usec \n", (ulong)get_usec(m_min_delta)); fprintf (fd," cnt : %lu \n",m_cnt); fprintf (fd," high_cnt : %lu \n",m_high_cnt); - fprintf (fd," max_d_time : %lu usec\n",get_usec(m_max_dt)); + fprintf (fd," max_d_time : %lu usec\n", (ulong)get_usec(m_max_dt)); //fprintf (fd," average : %.0f usec\n", get_total_average()); fprintf (fd," sliding_average : %.0f usec\n", get_average_latency()); fprintf (fd," precent : %.1f %%\n",(100.0*(double)m_high_cnt/(double)m_cnt)); @@ -198,7 +198,7 @@ void CTimeHistogram::Dump(FILE *fd){ for (j=0; j<HISTOGRAM_SIZE_LOG; j++) { for (i=0; i<HISTOGRAM_SIZE; i++) { if (m_hcnt[j][i] >0 ) { - fprintf (fd," h[%lu] : %lu \n",(base*(i+1)),m_hcnt[j][i]); + fprintf (fd," h[%u] : %llu \n",(base*(i+1)),(unsigned long long)m_hcnt[j][i]); } } base=base*10; diff --git a/src/tuple_gen.h b/src/tuple_gen.h index 29adbd69..d34e27bc 100755 --- a/src/tuple_gen.h +++ b/src/tuple_gen.h @@ -553,6 +553,9 @@ public: class CServerPoolBase { public: + + virtual ~CServerPoolBase() {} + virtual void GenerateTuple(CTupleBase& tuple) = 0; virtual uint16_t GenerateOnePort(uint32_t idx) = 0; virtual void Delete() = 0; diff --git a/src/utl_json.cpp b/src/utl_json.cpp index 990346f5..fb55be0a 100755 --- a/src/utl_json.cpp +++ b/src/utl_json.cpp @@ -25,7 +25,7 @@ limitations under the License. std::string add_json(std::string name, uint32_t counter,bool last){ char buff[200]; - sprintf(buff,"\"%s\":%lu",name.c_str(),counter); + sprintf(buff,"\"%s\":%lu",name.c_str(), (ulong)counter); std::string s= std::string(buff); if (!last) { s+=","; @@ -35,7 +35,7 @@ std::string add_json(std::string name, uint32_t counter,bool last){ std::string add_json(std::string name, uint64_t counter,bool last){ char buff[200]; - sprintf(buff,"\"%s\":%llu",name.c_str(),counter); + sprintf(buff,"\"%s\":%llu",name.c_str(), (unsigned long long)counter); std::string s= std::string(buff); if (!last) { s+=","; diff --git a/src/utl_yaml.cpp b/src/utl_yaml.cpp index 5f3ca735..828817e4 100755 --- a/src/utl_yaml.cpp +++ b/src/utl_yaml.cpp @@ -104,6 +104,8 @@ bool utl_yaml_read_uint16(const YAML::Node& node, val = (uint16_t)val_tmp; res=true; } + + return (res); } bool utl_yaml_read_bool(const YAML::Node& node, |