summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xlinux/ws_main.py1
-rw-r--r--scripts/automation/trex_control_plane/client/trex_stateless_sim.py142
-rwxr-xr-xsrc/bp_sim.cpp5
-rwxr-xr-xsrc/main.cpp21
-rw-r--r--src/sim/trex_sim.h17
-rw-r--r--src/sim/trex_sim_stateless.cpp137
-rw-r--r--src/stateless/cp/trex_stateless_port.h4
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);
}