diff options
-rwxr-xr-x | linux/ws_main.py | 1 | ||||
-rw-r--r-- | scripts/automation/trex_control_plane/client/trex_stateless_sim.py | 142 | ||||
-rwxr-xr-x | src/bp_sim.cpp | 5 | ||||
-rwxr-xr-x | src/main.cpp | 21 | ||||
-rw-r--r-- | src/sim/trex_sim.h | 17 | ||||
-rw-r--r-- | src/sim/trex_sim_stateless.cpp | 137 | ||||
-rw-r--r-- | src/stateless/cp/trex_stateless_port.h | 4 |
7 files changed, 225 insertions, 102 deletions
diff --git a/linux/ws_main.py b/linux/ws_main.py index 71914630..a41fab1e 100755 --- a/linux/ws_main.py +++ b/linux/ws_main.py @@ -257,6 +257,7 @@ bp =SrcGroups([ cxxflags_base =['-DWIN_UCODE_SIM', + '-DTREX_SIM', '-D_BYTE_ORDER', '-D_LITTLE_ENDIAN', '-DLINUX', diff --git a/scripts/automation/trex_control_plane/client/trex_stateless_sim.py b/scripts/automation/trex_control_plane/client/trex_stateless_sim.py index 5d06c6e5..4382e9fb 100644 --- a/scripts/automation/trex_control_plane/client/trex_stateless_sim.py +++ b/scripts/automation/trex_control_plane/client/trex_stateless_sim.py @@ -26,6 +26,8 @@ except ImportError: from client_utils.jsonrpc_client import JsonRpcClient, BatchMessage from client_utils.packet_builder import CTRexPktBuilder +from client_utils import parsing_opts + import json from common.trex_streams import * @@ -68,29 +70,21 @@ def merge_cap_files (pcap_file_list, out_filename, delete_src = False): class SimRun(object): - def __init__ (self, yaml_file, dp_core_count, core_index, packet_limit, output_filename, is_valgrind, is_gdb, limit): + def __init__ (self, options): - self.yaml_file = yaml_file - self.output_filename = output_filename - self.dp_core_count = dp_core_count - self.core_index = core_index - self.packet_limit = packet_limit - self.is_valgrind = is_valgrind - self.is_gdb = is_gdb - self.limit = limit + self.options = options # dummies self.handler = 0 self.port_id = 0 - self.mul = {"op": "abs", - "type": "raw", - "value": 1} + + self.mul = options.mult self.duration = -1 def load_yaml_file (self): streams_db = CStreamsDB() - stream_list = streams_db.load_yaml_file(self.yaml_file) + stream_list = streams_db.load_yaml_file(self.options.input_file) streams_json = [] for stream in stream_list.compiled: @@ -130,44 +124,65 @@ class SimRun(object): f.close() try: - cmd = ['bp-sim-64-debug', - '--pcap', - '--sl', - '--cores', - str(self.dp_core_count), - '--limit', - str(self.limit), - '-f', - f.name, - '-o', - self.output_filename] - - if self.core_index != None: - cmd += ['--core_index', str(self.core_index)] - - if self.is_valgrind: - cmd = ['valgrind', '--leak-check=full'] + cmd - elif self.is_gdb: - cmd = ['gdb', '--args'] + cmd - - print "executing command: '{0}'".format(" ".join(cmd)) - subprocess.call(cmd) - - # core index - if (self.dp_core_count > 1) and (self.core_index == None): - self.merge_results() - + if self.options.json: + with open(f.name) as file: + data = "\n".join(file.readlines()) + print json.dumps(json.loads(data), indent = 4, separators=(',', ': '), sort_keys = True) + else: + self.execute_bp_sim(f.name) finally: os.unlink(f.name) + def execute_bp_sim (self, json_filename): + exe = 'bp-sim-64' if self.options.release else 'bp-sim-64-debug' + if not os.path.exists(exe): + print "cannot find executable '{0}'".format(exe) + exit(-1) + + cmd = [exe, + '--pcap', + '--sl', + '--cores', + str(self.options.cores), + '--limit', + str(self.options.limit), + '-f', + json_filename, + '-o', + self.options.output_file] + + if self.options.dry: + cmd += ['--dry'] + + if self.options.core_index != None: + cmd += ['--core_index', str(self.options.core_index)] + + if self.options.valgrind: + cmd = ['valgrind', '--leak-check=full'] + cmd + + elif self.options.gdb: + cmd = ['gdb', '--args'] + cmd + + print "executing command: '{0}'".format(" ".join(cmd)) + subprocess.call(cmd) + + self.merge_results() + + def merge_results (self): - if (self.core_index != None) or (self.dp_core_count == 1): - # nothing to do + if self.options.dry: + return + + if self.options.cores == 1: + return + + if self.options.core_index != None: return - inputs = ["{0}-{1}".format(self.output_filename, index) for index in xrange(0, self.dp_core_count)] - merge_cap_files(inputs, self.output_filename, delete_src = True) + + inputs = ["{0}-{1}".format(self.options.output_file, index) for index in xrange(0, self.options.cores)] + merge_cap_files(inputs, self.options.output_file, delete_src = True) @@ -180,8 +195,8 @@ def is_valid_file(filename): def unsigned_int (x): x = int(x) - if x <= 0: - raise argparse.ArgumentTypeError("argument must be >= 1") + if x < 0: + raise argparse.ArgumentTypeError("argument must be >= 0") return x @@ -207,16 +222,26 @@ def setParserOptions(): default = None, type = int) - parser.add_argument("-j", "--join", - help = "run and join output from 0..core_count [default is False]", - default = False, - type = bool) + parser.add_argument("-r", "--release", + help = "runs on release image instead of debug [default is False]", + action = "store_true", + default = False) + + parser.add_argument("-s", "--dry", + help = "dry run only (nothing will be written to the file) [default is False]", + action = "store_true", + default = False) parser.add_argument("-l", "--limit", help = "limit test total packet count [default is 5000]", default = 5000, type = unsigned_int) + parser.add_argument('-m', '--multiplier', + help = parsing_opts.match_multiplier_help, + dest = 'mult', + default = {'type':'raw', 'value':1, 'op': 'abs'}, + type = parsing_opts.match_multiplier_strict) group = parser.add_mutually_exclusive_group() @@ -230,6 +255,11 @@ def setParserOptions(): action = "store_true", default = False) + group.add_argument("--json", + help = "generate JSON output only to stdout [default is False]", + action = "store_true", + default = False) + return parser @@ -239,6 +269,9 @@ def validate_args (parser, options): if not options.core_index in xrange(0, options.cores): parser.error("DP core index valid range is 0 to {0}".format(options.cores - 1)) + # zero is ok - no limit, but other values must be at least as the number of cores + if (options.limit != 0) and options.limit < options.cores: + parser.error("limit cannot be lower than number of DP cores") def main (): @@ -247,14 +280,7 @@ def main (): validate_args(parser, options) - r = SimRun(options.input_file, - options.cores, - options.core_index, - options.limit, - options.output_file, - options.valgrind, - options.gdb, - options.limit) + r = SimRun(options) r.run() diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp index fcef049c..5ee06190 100755 --- a/src/bp_sim.cpp +++ b/src/bp_sim.cpp @@ -3537,9 +3537,6 @@ int CNodeGenerator::flush_file(dsec_t max_time, } } - //#ifndef RTE_DPDK - //thread->check_msgs(); - //#endif uint8_t type=node->m_type; @@ -3553,7 +3550,7 @@ int CNodeGenerator::flush_file(dsec_t max_time, } else { node_sl->handle(thread); - #ifdef _DEBUG + #ifdef TREX_SIM update_stl_stats(node_sl); if (has_limit_reached()) { thread->m_stateless_dp_info.stop_traffic(node_sl->get_port_id(), false, 0); diff --git a/src/main.cpp b/src/main.cpp index ea8e1e44..a2d06067 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -36,7 +36,8 @@ using namespace std; // An enum for all the option types enum { OPT_HELP, OPT_CFG, OPT_NODE_DUMP, OP_STATS, OPT_FILE_OUT, OPT_UT, OPT_PCAP, OPT_IPV6, OPT_MAC_FILE, - OPT_SL, OPT_DP_CORE_COUNT, OPT_DP_CORE_INDEX, OPT_LIMIT}; + OPT_SL, OPT_DP_CORE_COUNT, OPT_DP_CORE_INDEX, OPT_LIMIT, + OPT_DRY_RUN}; @@ -75,16 +76,12 @@ static CSimpleOpt::SOption parser_options[] = { OPT_DP_CORE_COUNT, "--cores", SO_REQ_SEP }, { OPT_DP_CORE_INDEX, "--core_index", SO_REQ_SEP }, { OPT_LIMIT, "--limit", SO_REQ_SEP }, + { OPT_DRY_RUN, "--dry", SO_NONE }, SO_END_OF_OPTIONS }; - -static bool in_range(int x, int low, int high) { - return ( (x >= low) && (x <= high) ); -} - static int usage(){ printf(" Usage: bp_sim [OPTION] -f cfg.yaml -o outfile.erf \n"); @@ -189,6 +186,10 @@ static int parse_options(int argc, params["limit"] = atoi(args.OptionArg()); break; + case OPT_DRY_RUN: + params["dry"] = 1; + break; + default: usage(); return -1; @@ -277,12 +278,18 @@ int main(int argc , char * argv[]){ params["limit"] = 5000; } + if (params.count("dry") == 0) { + params["dry"] = 0; + } + return st.run(CGlobalInfo::m_options.cfg_file, CGlobalInfo::m_options.out_file, 2, params["dp_core_count"], params["dp_core_index"], - params["limit"]); + params["limit"], + (params["dry"] == 1) + ); } } } diff --git a/src/sim/trex_sim.h b/src/sim/trex_sim.h index a541ce01..a0f44cdb 100644 --- a/src/sim/trex_sim.h +++ b/src/sim/trex_sim.h @@ -32,6 +32,12 @@ class TrexStateless; class TrexPublisher; class DpToCpHandler; + +static inline bool +in_range(int x, int low, int high) { + return ( (x >= low) && (x <= high) ); +} + /** * interface for a sim target * @@ -103,7 +109,8 @@ public: int port_count, int dp_core_count, int dp_core_index, - int limit); + int limit, + bool is_dry_run); TrexStateless * get_stateless_obj() { return m_trex_stateless; @@ -128,6 +135,12 @@ private: void validate_response(const Json::Value &resp); + bool should_capture_core(int i); + bool is_multiple_capture(); + uint64_t get_limit_per_core(int core_index); + + void show_intro(const std::string &out_filename); + bool is_verbose() { return m_verbose; } @@ -137,12 +150,14 @@ private: TrexPublisher *m_publisher; CFlowGenList m_fl; CErfIFStl m_erf_vif; + CNullIF m_null_erf_vif; bool m_verbose; int m_port_count; int m_dp_core_count; int m_dp_core_index; uint64_t m_limit; + bool m_is_dry_run; }; #endif /* __TREX_SIM_H__ */ diff --git a/src/sim/trex_sim_stateless.cpp b/src/sim/trex_sim_stateless.cpp index 2b73f686..a5d2213e 100644 --- a/src/sim/trex_sim_stateless.cpp +++ b/src/sim/trex_sim_stateless.cpp @@ -121,6 +121,7 @@ SimStateless::SimStateless() { m_dp_core_index = -1; m_port_count = -1; m_limit = 0; + m_is_dry_run = false; /* override ownership checks */ TrexRpcCommand::test_set_override_ownership(true); @@ -133,17 +134,19 @@ SimStateless::run(const string &json_filename, int port_count, int dp_core_count, int dp_core_index, - int limit) { + int limit, + bool is_dry_run) { assert(dp_core_count > 0); /* -1 means its not set or positive value between 0 and the dp core count - 1*/ - assert( (dp_core_index == -1) || ( (dp_core_index >=0 ) && (dp_core_index < dp_core_count) ) ); + assert( (dp_core_index == -1) || ( in_range(dp_core_index, 0, dp_core_count - 1)) ); m_dp_core_count = dp_core_count; m_dp_core_index = dp_core_index; m_port_count = port_count; m_limit = limit; + m_is_dry_run = is_dry_run; prepare_dataplane(); prepare_control_plane(); @@ -220,7 +223,11 @@ SimStateless::prepare_dataplane() { m_fl.generate_p_thread_info(m_dp_core_count); for (int i = 0; i < m_dp_core_count; i++) { - m_fl.m_threads_info[i]->set_vif(&m_erf_vif); + if (should_capture_core(i)) { + m_fl.m_threads_info[i]->set_vif(&m_erf_vif); + } else { + m_fl.m_threads_info[i]->set_vif(&m_null_erf_vif); + } } } @@ -267,47 +274,81 @@ SimStateless::validate_response(const Json::Value &resp) { } +static inline bool is_debug() { + #ifdef DEBUG + return true; + #else + return false; + #endif +} + +void +SimStateless::show_intro(const std::string &out_filename) { + std::cout << "\nGeneral info:\n\n"; + std::cout << "image type: " << (is_debug() ? "debug" : "release") << "\n"; + std::cout << "I/O output: " << (m_is_dry_run ? "*DRY*" : out_filename) << "\n"; + + if (m_limit > 0) { + std::cout << "packet limit: " << m_limit << "\n"; + } else { + std::cout << "packet limit: " << "*NO LIMIT*" << "\n"; + } + + if (m_dp_core_index != -1) { + std::cout << "core recording: " << m_dp_core_index << "\n"; + } else { + std::cout << "core recording: merge all\n"; + } + + std::cout << "\nConfiguration info:\n\n"; + + std::cout << "ports: " << m_port_count << "\n"; + std::cout << "cores: " << m_dp_core_count << "\n"; + + + std::cout << "\nPort Config:\n\n"; + //TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(0); + //std::cout << "stream count:" << port->get_stream_by_id() + + std::cout << "\nStarting simulation...\n"; +} void SimStateless::run_dp(const std::string &out_filename) { uint64_t pkt_cnt = 0; - if (m_dp_core_count == 1) { - pkt_cnt = run_dp_core(0, out_filename); - } else { + show_intro(out_filename); - /* do we have a specific core index to capture ? */ - if (m_dp_core_index != -1) { - for (int i = 0; i < m_dp_core_count; i++) { - if (i == m_dp_core_index) { - pkt_cnt += run_dp_core(i, out_filename); - } else { - run_dp_core(i, "/dev/null"); - } - } - } else { - for (int i = 0; i < m_dp_core_count; i++) { - std::stringstream ss; - ss << out_filename << "-" << i; - pkt_cnt += run_dp_core(i, ss.str()); - } + if (is_multiple_capture()) { + for (int i = 0; i < m_dp_core_count; i++) { + std::stringstream ss; + ss << out_filename << "-" << i; + pkt_cnt += run_dp_core(i, ss.str()); } + } else { + for (int i = 0; i < m_dp_core_count; i++) { + pkt_cnt += run_dp_core(i, out_filename); + } } - std::cout << "\n"; - std::cout << "ports: " << m_port_count << "\n"; - std::cout << "cores: " << m_dp_core_count << "\n"; + std::cout << "\nwritten " << pkt_cnt << " packets " << "to '" << out_filename << "'\n\n"; +} - if (m_dp_core_index != -1) { - std::cout << "core index: " << m_dp_core_index << "\n"; + +uint64_t +SimStateless::get_limit_per_core(int core_index) { + /* global no limit ? */ + if (m_limit == 0) { + return (0); } else { - std::cout << "core index: merge all\n"; + uint64_t l = std::max((uint64_t)1, m_limit / m_dp_core_count); + if (core_index == 0) { + l += (m_limit % m_dp_core_count); + } + return l; } - - std::cout << "pkt limit: " << m_limit << "\n"; - std::cout << "\nwritten " << pkt_cnt << " packets " << "to '" << out_filename << "'\n\n"; } uint64_t @@ -315,12 +356,17 @@ SimStateless::run_dp_core(int core_index, const std::string &out_filename) { CFlowGenListPerThread *lpt = m_fl.m_threads_info[core_index]; - lpt->start_stateless_simulation_file((std::string)out_filename, CGlobalInfo::m_options.preview, m_limit / m_dp_core_count); + lpt->start_stateless_simulation_file((std::string)out_filename, CGlobalInfo::m_options.preview, get_limit_per_core(core_index)); lpt->start_stateless_daemon_simulation(); flush_dp_to_cp_messages_core(core_index); - return lpt->m_node_gen.m_cnt; + if (should_capture_core(core_index)) { + return lpt->m_node_gen.m_cnt; + } else { + return (0); + } + } @@ -344,3 +390,30 @@ SimStateless::flush_dp_to_cp_messages_core(int core_index) { delete msg; } } + +bool +SimStateless::should_capture_core(int i) { + + /* dry run - no core should be recordered */ + if (m_is_dry_run) { + return false; + } + + /* no specific core index ? record all */ + if (m_dp_core_index == -1) { + return true; + } else { + return (i == m_dp_core_index); + } +} + +bool +SimStateless::is_multiple_capture() { + /* dry run - no core should be recordered */ + if (m_is_dry_run) { + return false; + } + + return ( (m_dp_core_count > 1) && (m_dp_core_index == -1) ); +} + diff --git a/src/stateless/cp/trex_stateless_port.h b/src/stateless/cp/trex_stateless_port.h index a529d38f..784bf4c0 100644 --- a/src/stateless/cp/trex_stateless_port.h +++ b/src/stateless/cp/trex_stateless_port.h @@ -259,6 +259,10 @@ public: return m_stream_table.get_stream_by_id(stream_id); } + int get_stream_count() { + return m_stream_table.size(); + } + void get_id_list(std::vector<uint32_t> &id_list) { m_stream_table.get_id_list(id_list); } |