diff options
13 files changed, 184 insertions, 96 deletions
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py index 743ff27c..964acce7 100755 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py @@ -777,7 +777,7 @@ class STLClient(object): return rc - def __push_remote (self, pcap_filename, port_id_list, ipg_usec, speedup, count, duration, is_dual): + def __push_remote (self, pcap_filename, port_id_list, ipg_usec, speedup, count, duration, is_dual, min_ipg_usec): port_id_list = self.__ports(port_id_list) rc = RC() @@ -793,7 +793,8 @@ class STLClient(object): count, duration, is_dual, - slave_handler)) + slave_handler, + min_ipg_usec)) return rc @@ -2494,7 +2495,8 @@ class STLClient(object): speedup = 1.0, count = 1, duration = -1, - is_dual = False): + is_dual = False, + min_ipg_usec = None): """ Push a remote server-reachable PCAP file the path must be fullpath accessible to the server @@ -2524,6 +2526,9 @@ class STLClient(object): also requires that all the ports will be in master mode with their adjacent ports as slaves + min_ipg_usec : float + Minimum inter-packet gap in microseconds to guard from too small ipg. + :raises: + :exc:`STLError` @@ -2537,6 +2542,7 @@ class STLClient(object): validate_type('count', count, int) validate_type('duration', duration, (float, int)) validate_type('is_dual', is_dual, bool) + validate_type('min_ipg_usec', min_ipg_usec, (float, int, type(None))) # for dual mode check that all are masters if is_dual: @@ -2555,7 +2561,7 @@ class STLClient(object): self.logger.pre_cmd("Pushing remote PCAP on port(s) {0}:".format(ports)) - rc = self.__push_remote(pcap_filename, ports, ipg_usec, speedup, count, duration, is_dual) + rc = self.__push_remote(pcap_filename, ports, ipg_usec, speedup, count, duration, is_dual, min_ipg_usec) self.logger.post_cmd(rc) if not rc: @@ -2573,7 +2579,8 @@ class STLClient(object): force = False, vm = None, packet_hook = None, - is_dual = False): + is_dual = False, + min_ipg_usec = None): """ Push a local PCAP to the server This is equivalent to loading a PCAP file to a profile @@ -2615,6 +2622,9 @@ class STLClient(object): also requires that all the ports will be in master mode with their adjacent ports as slaves + min_ipg_usec : float + Minimum inter-packet gap in microseconds to guard from too small ipg. + :raises: + :exc:`STLError` @@ -2629,6 +2639,7 @@ class STLClient(object): validate_type('duration', duration, (float, int)) validate_type('vm', vm, (list, type(None))) validate_type('is_dual', is_dual, bool) + validate_type('min_ipg_usec', min_ipg_usec, (float, int, type(None))) # no support for > 1MB PCAP - use push remote @@ -2657,7 +2668,8 @@ class STLClient(object): speedup, count, vm = vm, - packet_hook = packet_hook) + packet_hook = packet_hook, + min_ipg_usec = min_ipg_usec) self.logger.post_cmd(RC_OK) except STLError as e: self.logger.post_cmd(RC_ERR(e)) @@ -2682,7 +2694,8 @@ class STLClient(object): count, vm = vm, packet_hook = packet_hook, - split_mode = split_mode) + split_mode = split_mode, + min_ipg_usec = min_ipg_usec) self.logger.post_cmd(RC_OK()) @@ -3653,6 +3666,7 @@ class STLClient(object): parsing_opts.COUNT, parsing_opts.DURATION, parsing_opts.IPG, + parsing_opts.MIN_IPG, parsing_opts.SPEEDUP, parsing_opts.FORCE, parsing_opts.DUAL] @@ -3685,6 +3699,7 @@ class STLClient(object): self.push_remote(opts.file[0], ports = opts.ports, ipg_usec = opts.ipg_usec, + min_ipg_usec = opts.min_ipg_usec, speedup = opts.speedup, count = opts.count, duration = opts.duration, @@ -3694,6 +3709,7 @@ class STLClient(object): self.push_pcap(opts.file[0], ports = opts.ports, ipg_usec = opts.ipg_usec, + min_ipg_usec = opts.min_ipg_usec, speedup = opts.speedup, count = opts.count, duration = opts.duration, diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py index 66d8be2b..9eefc177 100644 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py @@ -735,7 +735,7 @@ class Port(object): return self.get_rx_filter_mode() == 'all' @writeable - def push_remote (self, pcap_filename, ipg_usec, speedup, count, duration, is_dual, slave_handler): + def push_remote (self, pcap_filename, ipg_usec, speedup, count, duration, is_dual, slave_handler, min_ipg_usec): params = {"handler": self.handler, "port_id": self.port_id, @@ -745,7 +745,8 @@ class Port(object): "count": count, "duration": duration, "is_dual": is_dual, - "slave_handler": slave_handler} + "slave_handler": slave_handler, + "min_ipg_usec": min_ipg_usec if min_ipg_usec else 0} rc = self.transmit("push_remote", params) if rc.bad(): diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_streams.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_streams.py index aa797773..3bce671a 100755 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_streams.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_streams.py @@ -987,7 +987,8 @@ class STLProfile(object): loop_count = 1, vm = None, packet_hook = None, - split_mode = None): + split_mode = None, + min_ipg_usec = None): """ Convert a pcap file with a number of packets to a list of connected streams. packet1->packet2->packet3 etc @@ -1017,6 +1018,9 @@ class STLProfile(object): used for dual mode can be 'MAC' or 'IP' + min_ipg_usec : float + Minumum inter packet gap in usec. Used to guard from too small IPGs. + :return: STLProfile """ @@ -1025,8 +1029,9 @@ class STLProfile(object): if not os.path.isfile(pcap_file): raise STLError("file '{0}' does not exists".format(pcap_file)) - # make sure IPG is not less than 1 usec - if ipg_usec is not None and ipg_usec < 0.001: + # make sure IPG is not less than 0.001 usec + if (ipg_usec is not None and (ipg_usec < 0.001 * speedup) and + (min_ipg_usec is None or min_ipg_usec < 0.001)): raise STLError("ipg_usec cannot be less than 0.001 usec: '{0}'".format(ipg_usec)) if loop_count < 0: @@ -1039,6 +1044,7 @@ class STLProfile(object): pkts = PCAPReader(pcap_file).read_all() return STLProfile.__pkts_to_streams(pkts, ipg_usec, + min_ipg_usec, speedup, loop_count, vm, @@ -1059,6 +1065,7 @@ class STLProfile(object): profile_a = STLProfile.__pkts_to_streams(pkts_a, ipg_usec, + min_ipg_usec, speedup, loop_count, vm, @@ -1067,6 +1074,7 @@ class STLProfile(object): profile_b = STLProfile.__pkts_to_streams(pkts_b, ipg_usec, + min_ipg_usec, speedup, loop_count, vm, @@ -1081,28 +1089,37 @@ class STLProfile(object): @staticmethod - def __pkts_to_streams (pkts, ipg_usec, speedup, loop_count, vm, packet_hook, start_delay_usec = 0): + def __pkts_to_streams (pkts, ipg_usec, min_ipg_usec, speedup, loop_count, vm, packet_hook, start_delay_usec = 0): streams = [] if speedup == 0: raise STLError('Speedup should not be 0') - - # 10 ms delay before starting the PCAP - last_ts_usec = -(start_delay_usec) + if min_ipg_usec and min_ipg_usec < 0: + raise STLError('min_ipg_usec should not be negative.') if packet_hook: pkts = [(packet_hook(cap), meta) for (cap, meta) in pkts] + if ipg_usec == None: + constant_diff = None + else: + constant_diff = ipg_usec / float(speedup) + if min_ipg_usec is not None: + constant_diff = max(constant_diff, min_ipg_usec) for i, (cap, meta) in enumerate(pkts, start = 1): # IPG - if not provided, take from cap - if ipg_usec == None: + if constant_diff is None: packet_time = meta[0] * 1e6 + meta[1] if i == 1: - base_time = packet_time - ts_usec = (packet_time - base_time) / float(speedup) + isg = min_ipg_usec if min_ipg_usec else 0 + else: + isg = (packet_time - prev_time) / float(speedup) + if min_ipg_usec: + isg = max(isg, min_ipg_usec) + prev_time = packet_time else: - ts_usec = (ipg_usec * i) / float(speedup) + isg = constant_diff # handle last packet if i == len(pkts): @@ -1111,18 +1128,32 @@ class STLProfile(object): else: next = i + 1 action_count = 0 + self_start = False if i != 1 else True + + # add stream with delay that will not be part of loop: "delayed_start" -> 1 -> 2 -> 3 -> ... -> 1 -> 2 + if start_delay_usec and i == 1: + if loop_count == 1: # no loop actually + isg = start_delay_usec + else: + streams.append(STLStream(name = 'delayed_start', + packet = STLPktBuilder(pkt_buffer = cap, vm = vm), + mode = STLTXSingleBurst(total_pkts = 1, percentage = 100), + self_start = True, + isg = start_delay_usec, + action_count = action_count, + next = next)) + action_count = max(0, action_count - 1) + self_start = False streams.append(STLStream(name = i, packet = STLPktBuilder(pkt_buffer = cap, vm = vm), mode = STLTXSingleBurst(total_pkts = 1, percentage = 100), - self_start = True if (i == 1) else False, - isg = (ts_usec - last_ts_usec), # seconds to usec + self_start = self_start, + isg = isg, action_count = action_count, next = next)) - - last_ts_usec = ts_usec - + profile = STLProfile(streams) profile.meta = {'type': 'pcap'} diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py index 0a7b510f..f5dab30c 100755 --- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py +++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py @@ -14,75 +14,85 @@ ArgumentGroup = namedtuple('ArgumentGroup', ['type', 'args', 'options']) # list of available parsing options -MULTIPLIER = 1 -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 -DRY_RUN = 12 -XTERM = 13 -TOTAL = 14 -FULL_OUTPUT = 15 -IPG = 16 -SPEEDUP = 17 -COUNT = 18 -PROMISCUOUS = 19 -LINK_STATUS = 20 -LED_STATUS = 21 -TUNABLES = 22 -REMOTE_FILE = 23 -LOCKED = 24 -PIN_CORES = 25 -CORE_MASK = 26 -DUAL = 27 -FLOW_CTRL = 28 -SUPPORTED = 29 -FILE_PATH_NO_CHECK = 30 - -OUTPUT_FILENAME = 31 -LIMIT = 33 -PORT_RESTART = 34 - -RETRIES = 37 - -SINGLE_PORT = 38 -DST_MAC = 39 - -PING_IPV4 = 40 -PING_COUNT = 41 -PKT_SIZE = 42 - -SERVICE_OFF = 43 - -SRC_IPV4 = 44 -DST_IPV4 = 45 - -GLOBAL_STATS = 50 -PORT_STATS = 51 -PORT_STATUS = 52 -STREAMS_STATS = 53 -STATS_MASK = 54 -CPU_STATS = 55 -MBUF_STATS = 56 -EXTENDED_STATS = 57 -EXTENDED_INC_ZERO_STATS = 58 - -STREAMS_MASK = 60 -CORE_MASK_GROUP = 61 - -# ALL_STREAMS = 61 -# STREAM_LIST_WITH_ALL = 62 +_constants = ''' + +MULTIPLIER +MULTIPLIER_STRICT +PORT_LIST +ALL_PORTS +PORT_LIST_WITH_ALL +FILE_PATH +FILE_FROM_DB +SERVER_IP +STREAM_FROM_PATH_OR_FILE +DURATION +FORCE +DRY_RUN +XTERM +TOTAL +FULL_OUTPUT +IPG +MIN_IPG +SPEEDUP +COUNT +PROMISCUOUS +LINK_STATUS +LED_STATUS +TUNABLES +REMOTE_FILE +LOCKED +PIN_CORES +CORE_MASK +DUAL +FLOW_CTRL +SUPPORTED +FILE_PATH_NO_CHECK + +OUTPUT_FILENAME +LIMIT +PORT_RESTART + +RETRIES + +SINGLE_PORT +DST_MAC + +PING_IPV4 +PING_COUNT +PKT_SIZE + +SERVICE_OFF + +SRC_IPV4 +DST_IPV4 + +GLOBAL_STATS +PORT_STATS +PORT_STATUS +STREAMS_STATS +STATS_MASK +CPU_STATS +MBUF_STATS +EXTENDED_STATS +EXTENDED_INC_ZERO_STATS + +STREAMS_MASK +CORE_MASK_GROUP + +# ALL_STREAMS +# STREAM_LIST_WITH_ALL +# list of ArgumentGroup types +MUTEX +''' + +for index, line in enumerate(_constants.splitlines()): + var = line.strip().split() + if not var or '#' in var[0]: + continue + exec('%s = %s' % (var[0], index)) -# list of ArgumentGroup types -MUTEX = 1 def check_negative(value): ivalue = int(value) @@ -314,6 +324,11 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'], 'default': None, 'type': float}), + MIN_IPG: ArgumentPack(['--min-ipg'], + {'help': "Minimal IPG value in usec between packets. Used to guard from too small IPGs.", + 'dest': "min_ipg_usec", + 'default': None, + 'type': float}), SPEEDUP: ArgumentPack(['-s', '--speedup'], {'help': "Factor to accelerate the injection. effectively means IPG = IPG / SPEEDUP", diff --git a/src/gtest/trex_stateless_gtest.cpp b/src/gtest/trex_stateless_gtest.cpp index 09942c57..2593261f 100644 --- a/src/gtest/trex_stateless_gtest.cpp +++ b/src/gtest/trex_stateless_gtest.cpp @@ -4340,6 +4340,7 @@ TEST_F(basic_stl, pcap_remote_basic) { 0, "exp/remote_test.cap", 10, + 0, 1, 1, -1, @@ -4363,6 +4364,7 @@ TEST_F(basic_stl, pcap_remote_loop) { 0, "exp/remote_test.cap", 1, + 0, 1, 3, -1, @@ -4385,6 +4387,7 @@ TEST_F(basic_stl, pcap_remote_duration) { 0, "exp/remote_test.cap", 100000, + 0, 1, 0, 0.5, @@ -4407,6 +4410,7 @@ TEST_F(basic_stl, pcap_remote_dual) { 0, "exp/remote_test_dual.erf", 10000, + 0, 1, 0, 0.5, diff --git a/src/rpc-server/commands/trex_rpc_cmd_general.cpp b/src/rpc-server/commands/trex_rpc_cmd_general.cpp index f936f946..b3b1b3b4 100644 --- a/src/rpc-server/commands/trex_rpc_cmd_general.cpp +++ b/src/rpc-server/commands/trex_rpc_cmd_general.cpp @@ -631,6 +631,10 @@ TrexRpcCmdPushRemote::_run(const Json::Value ¶ms, Json::Value &result) { uint8_t port_id = parse_port(params, result); std::string pcap_filename = parse_string(params, "pcap_filename", result); double ipg_usec = parse_double(params, "ipg_usec", result); + double min_ipg_sec = 0; + if (params.isMember("min_ipg_usec")) { + min_ipg_sec = usec_to_sec(parse_double(params, "min_ipg_usec", result)); + } double speedup = parse_double(params, "speedup", result); uint32_t count = parse_uint32(params, "count", result); double duration = parse_double(params, "duration", result); @@ -649,7 +653,7 @@ TrexRpcCmdPushRemote::_run(const Json::Value ¶ms, Json::Value &result) { try { - port->push_remote(pcap_filename, ipg_usec, speedup, count, duration, is_dual); + port->push_remote(pcap_filename, ipg_usec, min_ipg_sec, speedup, count, duration, is_dual); } catch (const TrexException &ex) { generate_execute_err(result, ex.what()); } diff --git a/src/stateless/cp/trex_stateless_port.cpp b/src/stateless/cp/trex_stateless_port.cpp index 3a4db196..97f60dd6 100644 --- a/src/stateless/cp/trex_stateless_port.cpp +++ b/src/stateless/cp/trex_stateless_port.cpp @@ -511,6 +511,7 @@ TrexStatelessPort::update_traffic(const TrexPortMultiplier &mul, bool force) { void TrexStatelessPort::push_remote(const std::string &pcap_filename, double ipg_usec, + double min_ipg_sec, double speedup, uint32_t count, double duration, @@ -550,6 +551,7 @@ TrexStatelessPort::push_remote(const std::string &pcap_filename, m_pending_async_stop_event, pcap_filename, ipg_usec, + min_ipg_sec, speedup, count, duration, diff --git a/src/stateless/cp/trex_stateless_port.h b/src/stateless/cp/trex_stateless_port.h index 317f4f70..404e1355 100644 --- a/src/stateless/cp/trex_stateless_port.h +++ b/src/stateless/cp/trex_stateless_port.h @@ -221,6 +221,7 @@ public: */ void push_remote(const std::string &pcap_filename, double ipg_usec, + double min_ipg_sec, double speedup, uint32_t count, double duration, diff --git a/src/stateless/dp/trex_stateless_dp_core.cpp b/src/stateless/dp/trex_stateless_dp_core.cpp index 485e8533..6f9376c2 100644 --- a/src/stateless/dp/trex_stateless_dp_core.cpp +++ b/src/stateless/dp/trex_stateless_dp_core.cpp @@ -478,6 +478,7 @@ bool TrexStatelessDpPerPort::pause_traffic(uint8_t port_id){ bool TrexStatelessDpPerPort::push_pcap(uint8_t port_id, const std::string &pcap_filename, double ipg_usec, + double min_ipg_sec, double speedup, uint32_t count, bool is_dual) { @@ -508,6 +509,7 @@ bool TrexStatelessDpPerPort::push_pcap(uint8_t port_id, slave_mac_addr, pcap_filename, ipg_usec, + min_ipg_sec, speedup, count, is_dual); @@ -1169,6 +1171,7 @@ TrexStatelessDpCore::push_pcap(uint8_t port_id, int event_id, const std::string &pcap_filename, double ipg_usec, + double m_min_ipg_sec, double speedup, uint32_t count, double duration, @@ -1179,7 +1182,7 @@ TrexStatelessDpCore::push_pcap(uint8_t port_id, lp_port->set_event_id(event_id); /* delegate the command to the port */ - bool rc = lp_port->push_pcap(port_id, pcap_filename, ipg_usec, speedup, count, is_dual); + bool rc = lp_port->push_pcap(port_id, pcap_filename, ipg_usec, m_min_ipg_sec, speedup, count, is_dual); if (!rc) { /* report back that we stopped */ CNodeRing *ring = CMsgIns::Ins()->getCpDp()->getRingDpToCp(m_core->m_thread_id); @@ -1263,6 +1266,7 @@ bool CGenNodePCAP::create(uint8_t port_id, const uint8_t *slave_mac_addr, const std::string &pcap_filename, double ipg_usec, + double min_ipg_sec, double speedup, uint32_t count, bool is_dual) { @@ -1275,13 +1279,14 @@ bool CGenNodePCAP::create(uint8_t port_id, m_count = count; m_is_dual = is_dual; m_dir = dir; + m_min_ipg_sec = min_ipg_sec; /* mark this node as slow path */ set_slow_path(true); if (ipg_usec != -1) { /* fixed IPG */ - m_ipg_sec = usec_to_sec(ipg_usec / speedup); + m_ipg_sec = std::max(min_ipg_sec, usec_to_sec(ipg_usec / speedup)); m_speedup = 0; } else { /* packet IPG */ diff --git a/src/stateless/dp/trex_stateless_dp_core.h b/src/stateless/dp/trex_stateless_dp_core.h index b386daf7..e880a6eb 100644 --- a/src/stateless/dp/trex_stateless_dp_core.h +++ b/src/stateless/dp/trex_stateless_dp_core.h @@ -74,6 +74,7 @@ public: bool push_pcap(uint8_t port_id, const std::string &pcap_filename, double ipg_usec, + double min_ipg_sec, double speedup, uint32_t count, bool is_dual); @@ -183,6 +184,7 @@ public: int event_id, const std::string &pcap_filename, double ipg_usec, + double min_ipg_sec, double speedup, uint32_t count, double duration, diff --git a/src/stateless/dp/trex_stream_node.h b/src/stateless/dp/trex_stream_node.h index dda3113a..bc7be057 100644 --- a/src/stateless/dp/trex_stream_node.h +++ b/src/stateless/dp/trex_stream_node.h @@ -468,6 +468,7 @@ public: const uint8_t *slave_mac_addr, const std::string &pcap_filename, double ipg_usec, + double min_ipg_sec, double speedup, uint32_t count, bool is_dual); @@ -536,7 +537,7 @@ public: if (m_ipg_sec != -1) { return m_ipg_sec; } else { - return ((m_raw_packet->get_time() - m_last_pkt_time) / m_speedup); + return (std::max(m_min_ipg_sec, (m_raw_packet->get_time() - m_last_pkt_time) / m_speedup)); } } @@ -632,6 +633,7 @@ private: double m_last_pkt_time; double m_speedup; double m_ipg_sec; + double m_min_ipg_sec; uint32_t m_count; double m_next_time_offset; /* in sec */ @@ -644,7 +646,7 @@ private: bool m_is_dual; /* pad to match the size of CGenNode */ - uint8_t m_pad_end[19]; + uint8_t m_pad_end[11]; } __rte_cache_aligned; diff --git a/src/stateless/messaging/trex_stateless_messaging.cpp b/src/stateless/messaging/trex_stateless_messaging.cpp index 2b8e93bb..aeb1e677 100644 --- a/src/stateless/messaging/trex_stateless_messaging.cpp +++ b/src/stateless/messaging/trex_stateless_messaging.cpp @@ -191,6 +191,7 @@ TrexStatelessDpPushPCAP::handle(TrexStatelessDpCore *dp_core) { m_event_id, m_pcap_filename, m_ipg_usec, + m_min_ipg_sec, m_speedup, m_count, m_duration, @@ -204,6 +205,7 @@ TrexStatelessDpPushPCAP::clone() { m_event_id, m_pcap_filename, m_ipg_usec, + m_min_ipg_sec, m_speedup, m_count, m_duration, diff --git a/src/stateless/messaging/trex_stateless_messaging.h b/src/stateless/messaging/trex_stateless_messaging.h index dbdd9b56..72b92d11 100644 --- a/src/stateless/messaging/trex_stateless_messaging.h +++ b/src/stateless/messaging/trex_stateless_messaging.h @@ -313,6 +313,7 @@ public: int event_id, const std::string &pcap_filename, double ipg_usec, + double min_ipg_sec, double speedup, uint32_t count, double duration, @@ -321,6 +322,7 @@ public: m_port_id = port_id; m_event_id = event_id; m_ipg_usec = ipg_usec; + m_min_ipg_sec = min_ipg_sec; m_speedup = speedup; m_count = count; m_duration = duration; @@ -335,6 +337,7 @@ private: std::string m_pcap_filename; int m_event_id; double m_ipg_usec; + double m_min_ipg_sec; double m_speedup; double m_duration; uint32_t m_count; |