summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorimarom <imarom@cisco.com>2015-11-29 08:38:38 -0500
committerimarom <imarom@cisco.com>2015-11-29 08:45:27 -0500
commit4c94931c5de8673433d3bf22999ecc84d41e0595 (patch)
tree9a452d1182408f71cb5236cd8a54b567d87f70ff
parent27a7103d501e9a0bf005d657cb3f7c51a72eca6b (diff)
support for update +/- request
-rwxr-xr-xscripts/automation/trex_control_plane/client/trex_stateless_client.py19
-rwxr-xr-xscripts/automation/trex_control_plane/console/parsing_opts.py89
-rw-r--r--src/rpc-server/commands/trex_rpc_cmd_stream.cpp48
-rw-r--r--src/rpc-server/trex_rpc_cmd_api.h2
-rw-r--r--src/stateless/cp/trex_stateless_port.cpp135
-rw-r--r--src/stateless/cp/trex_stateless_port.h82
6 files changed, 252 insertions, 123 deletions
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 b3476268..c1dea9eb 100755
--- a/scripts/automation/trex_control_plane/client/trex_stateless_client.py
+++ b/scripts/automation/trex_control_plane/client/trex_stateless_client.py
@@ -292,14 +292,6 @@ class Port(object):
def get_all_streams (self):
return self.streams
-
- def process_mul (self, mul):
- # if percentage - translate
- if mul['type'] == 'percentage':
- mul['type'] = 'max_bps'
- mul['max'] = self.get_speed_bps() * (mul['max'] / 100)
-
-
# start traffic
def start (self, mul, duration):
if self.state == self.STATE_DOWN:
@@ -311,8 +303,6 @@ class Port(object):
if self.state == self.STATE_TX:
return self.err("Unable to start traffic - port is already transmitting")
- self.process_mul(mul)
-
params = {"handler": self.handler,
"port_id": self.port_id,
"mul": mul,
@@ -385,8 +375,6 @@ class Port(object):
if (self.state != self.STATE_TX) :
return self.err("port is not transmitting")
- self.process_mul(mul)
-
params = {"handler": self.handler,
"port_id": self.port_id,
"mul": mul}
@@ -1018,13 +1006,14 @@ class CTRexStatelessClient(object):
parsing_opts.FORCE,
parsing_opts.STREAM_FROM_PATH_OR_FILE,
parsing_opts.DURATION,
- parsing_opts.MULTIPLIER)
+ parsing_opts.MULTIPLIER_STRICT)
opts = parser.parse_args(line.split())
if opts is None:
return RC_ERR("bad command line paramters")
+
if opts.db:
stream_list = self.stream_db.get_stream_pack(opts.db)
rc = RC(stream_list != None)
@@ -1044,7 +1033,7 @@ class CTRexStatelessClient(object):
# total has no meaning with percentage - its linear
if opts.total and (opts.mult['type'] != 'percentage'):
# if total was set - divide it between the ports
- opts.mult['max'] = opts.mult['max'] / len(opts.ports)
+ opts.mult['value'] = opts.mult['value'] / len(opts.ports)
return self.cmd_start(opts.ports, stream_list, opts.mult, opts.force, opts.duration)
@@ -1078,7 +1067,7 @@ class CTRexStatelessClient(object):
# total has no meaning with percentage - its linear
if opts.total and (opts.mult['type'] != 'percentage'):
# if total was set - divide it between the ports
- opts.mult['max'] = opts.mult['max'] / len(opts.ports)
+ opts.mult['value'] = opts.mult['value'] / len(opts.ports)
return self.cmd_update(opts.ports, opts.mult)
diff --git a/scripts/automation/trex_control_plane/console/parsing_opts.py b/scripts/automation/trex_control_plane/console/parsing_opts.py
index 0bcdce84..d7bf583a 100755
--- a/scripts/automation/trex_control_plane/console/parsing_opts.py
+++ b/scripts/automation/trex_control_plane/console/parsing_opts.py
@@ -10,16 +10,17 @@ 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
-SERVER_IP = 7
-STREAM_FROM_PATH_OR_FILE = 8
-DURATION = 9
-FORCE = 10
-TOTAL = 11
+MULTIPLIER_STRICT = 2
+PORT_LIST = 3
+ALL_PORTS = 4
+PORT_LIST_WITH_ALL = 5
+FILE_PATH = 6
+FILE_FROM_DB = 7
+SERVER_IP = 8
+STREAM_FROM_PATH_OR_FILE = 9
+DURATION = 10
+FORCE = 11
+TOTAL = 12
# list of ArgumentGroup types
MUTEX = 1
@@ -54,10 +55,15 @@ match_multiplier_help = """Multiplier should be passed in the following format:
will provide a percentage of the line rate. examples
: '-m 10', '-m 10kbps', '-m 10mpps', '-m 23%%' """
-def match_multiplier(val):
- '''match some val against multiplier shortcut inputs '''
+def match_multiplier_common(val, strict_abs = True):
- match = re.match("^(\d+(\.\d+)?)(bps|kbps|mbps|gbps|pps|kpps|mpps|%?)$", val)
+ # on strict absolute we do not allow +/-
+ if strict_abs:
+ match = re.match("^(\d+(\.\d+)?)(bps|kbps|mbps|gbps|pps|kpps|mpps|%?)$", val)
+ op = None
+ else:
+ match = re.match("^(\d+(\.\d+)?)(bps|kbps|mbps|gbps|pps|kpps|mpps|%?)([\+\-])?$", val)
+ op = match.group(4)
result = {}
@@ -65,44 +71,53 @@ def match_multiplier(val):
value = float(match.group(1))
unit = match.group(3)
+
+
# raw type (factor)
if not unit:
result['type'] = 'raw'
- result['max'] = value
+ result['value'] = value
elif unit == 'bps':
- result['type'] = 'max_bps'
- result['max'] = value
+ result['type'] = 'bps'
+ result['value'] = value
elif unit == 'kbps':
- result['type'] = 'max_bps'
- result['max'] = value * 1000
+ result['type'] = 'bps'
+ result['value'] = value * 1000
elif unit == 'mbps':
- result['type'] = 'max_bps'
- result['max'] = value * 1000 * 1000
+ result['type'] = 'bps'
+ result['value'] = value * 1000 * 1000
elif unit == 'gbps':
- result['type'] = 'max_bps'
- result['max'] = value * 1000 * 1000 * 1000
+ result['type'] = 'bps'
+ result['value'] = value * 1000 * 1000 * 1000
elif unit == 'pps':
- result['type'] = 'max_pps'
- result['max'] = value
+ result['type'] = 'pps'
+ result['value'] = value
elif unit == "kpps":
- result['type'] = 'max_pps'
- result['max'] = value * 1000
+ result['type'] = 'pps'
+ result['value'] = value * 1000
elif unit == "mpps":
- result['type'] = 'max_pps'
- result['max'] = value * 1000 * 1000
+ result['type'] = 'pps'
+ result['value'] = value * 1000 * 1000
elif unit == "%":
- # will be translated by the port object
result['type'] = 'percentage'
- result['max'] = value
+ result['value'] = value
+
+
+ if op == "+":
+ result['op'] = "add"
+ elif op == "-":
+ result['op'] = "sub"
+ else:
+ result['op'] = "abs"
return result
@@ -110,6 +125,13 @@ def match_multiplier(val):
raise argparse.ArgumentTypeError(match_multiplier_help)
+def match_multiplier(val):
+ '''match some val against multiplier shortcut inputs '''
+ return match_multiplier_common(val, strict_abs = False)
+
+def match_multiplier_strict(val):
+ '''match some val against multiplier shortcut inputs '''
+ return match_multiplier_common(val, strict_abs = True)
def is_valid_file(filename):
if not os.path.isfile(filename):
@@ -121,9 +143,14 @@ def is_valid_file(filename):
OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'],
{'help': match_multiplier_help,
'dest': "mult",
- 'default': {'type':'raw', 'max':1},
+ 'default': {'type':'raw', 'value':1, 'op': 'abs'},
'type': match_multiplier}),
+ MULTIPLIER_STRICT: ArgumentPack(['-m', '--multiplier'],
+ {'help': match_multiplier_help,
+ 'dest': "mult",
+ 'default': {'type':'raw', 'value':1, 'op': 'abs'},
+ 'type': match_multiplier_strict}),
TOTAL: ArgumentPack(['-t', '--total'],
{'help': "traffic will be divided between all ports specified",
diff --git a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp
index a5bf0d16..dea4c171 100644
--- a/src/rpc-server/commands/trex_rpc_cmd_stream.cpp
+++ b/src/rpc-server/commands/trex_rpc_cmd_stream.cpp
@@ -475,28 +475,17 @@ TrexRpcCmdStartTraffic::_run(const Json::Value &params, Json::Value &result) {
/* multiplier */
const Json::Value &mul_obj = parse_object(params, "mul", result);
- std::string mul_type = parse_string(mul_obj, "type", result);
- double mul_value = parse_double(mul_obj, "max", result);
- /* now create an object for multiplier */
- TrexStatelessPort::mul_st mul;
-
- mul.value = mul_value;
-
- /* dispatch according to type of multiplier */
- if (mul_type == "raw") {
- mul.type = TrexStatelessPort::MUL_FACTOR;
-
- } else if (mul_type == "max_bps") {
- mul.type = TrexStatelessPort::MUL_MAX_BPS;
+ std::string type = parse_choice(mul_obj, "type", TrexPortMultiplier::g_types, result);
+ std::string op = parse_string(mul_obj, "op", result);
+ double value = parse_double(mul_obj, "value", result);
- } else if (mul_type == "max_pps") {
- mul.type = TrexStatelessPort::MUL_MAX_PPS;
-
- } else {
- generate_parse_err(result, "multiplier type can be either 'raw', 'max_bps' or 'max_pps'");
+ if (op != "abs") {
+ generate_parse_err(result, "start message can only specify absolute speed rate");
}
+ TrexPortMultiplier mul(type, op, value);
+
try {
port->start_traffic(mul, duration);
@@ -651,28 +640,15 @@ TrexRpcCmdUpdateTraffic::_run(const Json::Value &params, Json::Value &result) {
TrexStatelessPort *port = get_stateless_obj()->get_port_by_id(port_id);
/* multiplier */
- const Json::Value &mul_obj = parse_object(params, "mul", result);
- std::string mul_type = parse_string(mul_obj, "type", result);
- double mul_value = parse_double(mul_obj, "max", result);
-
- /* now create an object for multiplier */
- TrexStatelessPort::mul_st mul;
-
- mul.value = mul_value;
- /* dispatch according to type of multiplier */
- if (mul_type == "raw") {
- mul.type = TrexStatelessPort::MUL_FACTOR;
+ const Json::Value &mul_obj = parse_object(params, "mul", result);
- } else if (mul_type == "max_bps") {
- mul.type = TrexStatelessPort::MUL_MAX_BPS;
+ std::string type = parse_choice(mul_obj, "type", TrexPortMultiplier::g_types, result);
+ std::string op = parse_choice(mul_obj, "op", TrexPortMultiplier::g_ops, result);
+ double value = parse_double(mul_obj, "value", result);
- } else if (mul_type == "max_pps") {
- mul.type = TrexStatelessPort::MUL_MAX_PPS;
+ TrexPortMultiplier mul(type, op, value);
- } else {
- generate_parse_err(result, "multiplier type can be either 'raw', 'max_bps' or 'max_pps'");
- }
try {
port->update_traffic(mul);
diff --git a/src/rpc-server/trex_rpc_cmd_api.h b/src/rpc-server/trex_rpc_cmd_api.h
index 3c718eaa..e93fb775 100644
--- a/src/rpc-server/trex_rpc_cmd_api.h
+++ b/src/rpc-server/trex_rpc_cmd_api.h
@@ -159,7 +159,7 @@ protected:
* parse a field from choices
*
*/
- template<typename T> T parse_choice(const Json::Value &params, const std::string &name, std::initializer_list<T> choices, Json::Value &result) {
+ template<typename T> T parse_choice(const Json::Value &params, const std::string &name, const std::initializer_list<T> choices, Json::Value &result) {
const Json::Value &field = params[name];
if (field == Json::Value::null) {
diff --git a/src/stateless/cp/trex_stateless_port.cpp b/src/stateless/cp/trex_stateless_port.cpp
index 8346b61d..95bdca0b 100644
--- a/src/stateless/cp/trex_stateless_port.cpp
+++ b/src/stateless/cp/trex_stateless_port.cpp
@@ -104,7 +104,7 @@ TrexStatelessPort::release(void) {
*
*/
void
-TrexStatelessPort::start_traffic(const TrexStatelessPort::mul_st &mul, double duration) {
+TrexStatelessPort::start_traffic(const TrexPortMultiplier &mul, double duration) {
/* command allowed only on state stream */
verify_state(PORT_STATE_STREAMS);
@@ -112,7 +112,9 @@ TrexStatelessPort::start_traffic(const TrexStatelessPort::mul_st &mul, double du
/* just making sure no leftovers... */
delete_streams_graph();
- /* calculate the effective M */
+ /* on start - we can only provide absolute values */
+ assert(mul.m_op == TrexPortMultiplier::OP_ABS);
+
double per_core_mul = calculate_effective_mul(mul);
/* fetch all the streams from the table */
@@ -221,19 +223,41 @@ TrexStatelessPort::resume_traffic(void) {
}
void
-TrexStatelessPort::update_traffic(const TrexStatelessPort::mul_st &mul) {
+TrexStatelessPort::update_traffic(const TrexPortMultiplier &mul) {
+
+ double factor;
verify_state(PORT_STATE_TX | PORT_STATE_PAUSE);
/* generate a message to all the relevant DP cores to start transmitting */
double new_per_core_m = calculate_effective_mul(mul);
- double factor = new_per_core_m / m_current_per_core_m;
+
+ switch (mul.m_op) {
+ case TrexPortMultiplier::OP_ABS:
+ factor = new_per_core_m / m_current_per_core_m;
+ break;
+
+ case TrexPortMultiplier::OP_ADD:
+ factor = (m_current_per_core_m + new_per_core_m) / m_current_per_core_m;
+ break;
+
+ case TrexPortMultiplier::OP_SUB:
+ factor = (m_current_per_core_m - new_per_core_m) / m_current_per_core_m;
+ if (factor <= 0) {
+ throw TrexRpcException("Update request will lower traffic to less than zero");
+ }
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
TrexStatelessCpToDpMsgBase *update_msg = new TrexStatelessDpUpdate(m_port_id, factor);
send_message_to_dp(update_msg);
- m_current_per_core_m = new_per_core_m;
+ m_current_per_core_m *= factor;
}
@@ -368,16 +392,29 @@ TrexStatelessPort::on_dp_event_occured(TrexDpPortEvent::event_e event_type) {
}
}
-/**
- * calculate an effective M based on requirments
- *
- */
+uint64_t
+TrexStatelessPort::get_port_speed_bps() {
+ switch (m_speed) {
+ case TrexPlatformApi::SPEED_1G:
+ return (1LLU * 1000 * 1000 * 1000);
+
+ case TrexPlatformApi::SPEED_10G:
+ return (10LLU * 1000 * 1000 * 1000);
+
+ case TrexPlatformApi::SPEED_40G:
+ return (40LLU * 1000 * 1000 * 1000);
+
+ default:
+ return 0;
+ }
+}
+
double
-TrexStatelessPort::calculate_effective_mul(const mul_st &mul) {
+TrexStatelessPort::calculate_effective_mul(const TrexPortMultiplier &mul) {
/* for a simple factor request - calculate the multiplier per core */
- if (mul.type == MUL_FACTOR) {
- return (mul.value / m_cores_id_list.size());
+ if (mul.m_type == TrexPortMultiplier::MUL_FACTOR) {
+ return (mul.m_value / m_cores_id_list.size());
}
/* we now need the graph - generate it if we don't have it (happens once) */
@@ -385,16 +422,30 @@ TrexStatelessPort::calculate_effective_mul(const mul_st &mul) {
generate_streams_graph();
}
- /* now we can calculate the effective M */
- if (mul.type == MUL_MAX_BPS) {
- return ( (mul.value / m_graph_obj->get_max_bps()) / m_cores_id_list.size());
- } else if (mul.type == MUL_MAX_PPS) {
- return ( (mul.value / m_graph_obj->get_max_pps()) / m_cores_id_list.size());
- } else {
+ switch (mul.m_type) {
+ case TrexPortMultiplier::MUL_BPS:
+ return ( (mul.m_value / m_graph_obj->get_max_bps()) / m_cores_id_list.size());
+
+ case TrexPortMultiplier::MUL_PPS:
+ return ( (mul.m_value / m_graph_obj->get_max_pps()) / m_cores_id_list.size());
+
+ case TrexPortMultiplier::MUL_PERCENTAGE:
+ /* if abs percentage is from the line speed - otherwise its from the current speed */
+
+ if (mul.m_op == TrexPortMultiplier::OP_ABS) {
+ double required = (mul.m_value / 100.0) * get_port_speed_bps();
+ return ( (required / m_graph_obj->get_max_bps()) / m_cores_id_list.size());
+ } else {
+ return (m_current_per_core_m * (mul.m_value / 100.0));
+ }
+
+ default:
assert(0);
}
+
}
+
void
TrexStatelessPort::generate_streams_graph() {
@@ -419,3 +470,51 @@ TrexStatelessPort::delete_streams_graph() {
}
}
+
+
+/***************************
+ * port multiplier
+ *
+ **************************/
+const std::initializer_list<std::string> TrexPortMultiplier::g_types = {"raw", "bps", "pps", "percentage"};
+const std::initializer_list<std::string> TrexPortMultiplier::g_ops = {"abs", "add", "sub"};
+
+TrexPortMultiplier::
+TrexPortMultiplier(const std::string &type_str, const std::string &op_str, double value) {
+ mul_type_e type;
+ mul_op_e op;
+
+ if (type_str == "raw") {
+ type = MUL_FACTOR;
+
+ } else if (type_str == "bps") {
+ type = MUL_BPS;
+
+ } else if (type_str == "pps") {
+ type = MUL_PPS;
+
+ } else if (type_str == "percentage") {
+ type = MUL_PERCENTAGE;
+ } else {
+ throw TrexException("bad type str: " + type_str);
+ }
+
+ if (op_str == "abs") {
+ op = OP_ABS;
+
+ } else if (op_str == "add") {
+ op = OP_ADD;
+
+ } else if (op_str == "sub") {
+ op = OP_SUB;
+
+ } else {
+ throw TrexException("bad op str: " + op_str);
+ }
+
+ m_type = type;
+ m_op = op;
+ m_value = value;
+
+}
+
diff --git a/src/stateless/cp/trex_stateless_port.h b/src/stateless/cp/trex_stateless_port.h
index 7d20f338..45eb16e8 100644
--- a/src/stateless/cp/trex_stateless_port.h
+++ b/src/stateless/cp/trex_stateless_port.h
@@ -27,6 +27,7 @@ limitations under the License.
class TrexStatelessCpToDpMsgBase;
class TrexStreamsGraphObj;
+class TrexPortMultiplier;
/**
* describes a stateless port
@@ -59,24 +60,7 @@ public:
RC_ERR_FAILED_TO_COMPILE_STREAMS
};
- /**
- * defines the type of multipler passed to start
- */
- enum mul_type_e {
- MUL_FACTOR,
- MUL_MAX_BPS,
- MUL_MAX_PPS
- };
-
- /**
- * multiplier object
- */
- typedef struct {
- mul_type_e type;
- double value;
- } mul_st;
-
-
+
TrexStatelessPort(uint8_t port_id, const TrexPlatformApi *api);
/**
@@ -95,7 +79,7 @@ public:
* start traffic
* throws TrexException in case of an error
*/
- void start_traffic(const mul_st &mul, double duration = -1);
+ void start_traffic(const TrexPortMultiplier &mul, double duration = -1);
/**
* stop traffic
@@ -119,7 +103,7 @@ public:
* update current traffic on port
*
*/
- void update_traffic(const mul_st &mul);
+ void update_traffic(const TrexPortMultiplier &mul);
/**
* get the port state
@@ -227,7 +211,6 @@ public:
}
-
private:
@@ -276,7 +259,13 @@ private:
* calculate effective M per core
*
*/
- double calculate_effective_mul(const mul_st &mul);
+ double calculate_effective_mul(const TrexPortMultiplier &mul);
+
+ /**
+ * get port speed in bits per second
+ *
+ */
+ uint64_t get_port_speed_bps();
/**
* generates a graph of streams graph
@@ -314,4 +303,53 @@ private:
const TrexStreamsGraphObj *m_graph_obj;
};
+
+
+/**
+ * port multiplier object
+ *
+ */
+class TrexPortMultiplier {
+public:
+
+
+ /**
+ * defines the type of multipler passed to start
+ */
+ enum mul_type_e {
+ MUL_FACTOR,
+ MUL_BPS,
+ MUL_PPS,
+ MUL_PERCENTAGE
+ };
+
+ /**
+ * multiplier can be absolute value
+ * increment value or subtract value
+ */
+ enum mul_op_e {
+ OP_ABS,
+ OP_ADD,
+ OP_SUB
+ };
+
+
+ TrexPortMultiplier(mul_type_e type, mul_op_e op, double value) {
+ m_type = type;
+ m_op = op;
+ m_value = value;
+ }
+
+ TrexPortMultiplier(const std::string &type_str, const std::string &op_str, double value);
+
+
+public:
+ static const std::initializer_list<std::string> g_types;
+ static const std::initializer_list<std::string> g_ops;
+
+ mul_type_e m_type;
+ mul_op_e m_op;
+ double m_value;
+};
+
#endif /* __TREX_STATELESS_PORT_H__ */