From e4c8e44b0842093ce2a245e863a8db7f4c2ae9ff Mon Sep 17 00:00:00 2001 From: Yaroslav Brustinov Date: Sun, 11 Dec 2016 19:06:13 +0200 Subject: add min_ipg to push_pcaps Change-Id: I353f8903c40963517fd2fed721cc0671d9f6dc4b Signed-off-by: Yaroslav Brustinov --- .../stl/trex_stl_lib/trex_stl_client.py | 30 ++++- .../stl/trex_stl_lib/trex_stl_port.py | 5 +- .../stl/trex_stl_lib/trex_stl_streams.py | 63 ++++++--- .../stl/trex_stl_lib/utils/parsing_opts.py | 147 ++++++++++++--------- 4 files changed, 154 insertions(+), 91 deletions(-) (limited to 'scripts/automation/trex_control_plane/stl/trex_stl_lib') 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", -- cgit 1.2.3-korg