From: Miroslav Miklus Date: Thu, 12 May 2016 22:35:53 +0000 (+0200) Subject: T-REX stl traffic send improvement for async calls X-Git-Url: https://gerrit.fd.io/r/gitweb?p=csit.git;a=commitdiff_plain;h=180d17939d123c04bf142cedf02daa325e3f4fa6 T-REX stl traffic send improvement for async calls JIRA: CSIT-68 - show runtime statistics with running traffic - T-REX driver async. driver Change-Id: Ie5eb7021f610fb58383b033dda5b1b867f7d3d2c Signed-off-by: Miroslav Miklus --- diff --git a/resources/libraries/python/TrafficGenerator.py b/resources/libraries/python/TrafficGenerator.py index 7f53836494..3969891cf9 100644 --- a/resources/libraries/python/TrafficGenerator.py +++ b/resources/libraries/python/TrafficGenerator.py @@ -35,7 +35,7 @@ class TGDropRateSearchImpl(DropRateSearch): loss_acceptance_type, traffic_type): # we need instance of TrafficGenerator instantiated by Robot Framework - # to be able to use trex_stateless_remote_exec method + # to be able to use trex_stl-*() tg_instance = BuiltIn().get_library_instance( 'resources.libraries.python.TrafficGenerator') @@ -43,9 +43,9 @@ class TGDropRateSearchImpl(DropRateSearch): raise Exception('TG subtype not defined') elif tg_instance._node['subtype'] == NodeSubTypeTG.TREX: unit_rate = str(rate) + self.get_rate_type_str() - tg_instance.trex_stateless_remote_exec(self.get_duration(), + tg_instance.trex_stl_start_remote_exec(self.get_duration(), unit_rate, frame_size, - traffic_type) + traffic_type, False) # TODO: getters for tg_instance and loss_acceptance_type logger.trace("comparing: {} < {} ".format(tg_instance._loss, @@ -73,6 +73,7 @@ class TrafficGenerator(object): # T-REX interface order mapping self._ifaces_reordered = 0 + #pylint: disable=too-many-arguments, too-many-locals def initialize_traffic_generator(self, tg_node, tg_if1, tg_if2, dut1_node, dut1_if1, dut1_if2, dut2_node, dut2_if1, dut2_if2, @@ -197,19 +198,54 @@ class TrafficGenerator(object): logger.error('pkill t-rex failed: {0}'.format(stdout + stderr)) raise RuntimeError('pkill t-rex failed') - def trex_stateless_remote_exec(self, duration, rate, framesize, - traffic_type): - """Execute stateless script on remote node over ssh. + @staticmethod + def trex_stl_stop_remote_exec(node): + """Execute script on remote node over ssh to stop running traffic. + + :param node: T-REX generator node. + :type node: dict + :return: Nothing + """ + ssh = SSH() + ssh.connect(node) + + (ret, stdout, stderr) = ssh.exec_command( + "sh -c '/tmp/openvpp-testing/resources/tools/t-rex/" + "t-rex-stateless-stop.py'") + logger.trace(ret) + logger.trace(stdout) + logger.trace(stderr) + + if int(ret) != 0: + raise RuntimeError('T-rex stateless runtime error') + + def trex_stl_start_remote_exec(self, duration, rate, framesize, + traffic_type, async_call, warmup_time=5): + """Execute script on remote node over ssh to start traffic. + :param duration: Time expresed in seconds for how long to send traffic. + :param rate: Traffic rate expressed with units (pps, %) + :param framesize: L2 frame size to send (without padding and IPG). :param traffic_type: Traffic profile. + :param async_call: If enabled then don't wait for all incomming trafic. + :param warmup_time: Warmup time period. + :type duration: int + :type rate: str + :type framesize: int :type traffic_type: str + :type async_call: bool + :type warmup_time: int + :return: Nothing """ ssh = SSH() ssh.connect(self._node) _p0 = 1 _p1 = 2 + _async = "" + if async_call: + _async = "--async" if self._ifaces_reordered != 0: _p0, _p1 = _p1, _p0 @@ -217,40 +253,43 @@ class TrafficGenerator(object): (ret, stdout, stderr) = ssh.exec_command( "sh -c '/tmp/openvpp-testing/resources/tools/t-rex/" "t-rex-stateless.py " - "-d {0} -r {1} -s {2} " + "--duration={0} -r {1} -s {2} " "--p{3}_src_start_ip 10.10.10.1 " "--p{3}_src_end_ip 10.10.10.254 " "--p{3}_dst_start_ip 20.20.20.1 " "--p{4}_src_start_ip 20.20.20.1 " "--p{4}_src_end_ip 20.20.20.254 " - "--p{4}_dst_start_ip 10.10.10.1'".\ - format(duration, rate, framesize, _p0, _p1),\ + "--p{4}_dst_start_ip 10.10.10.1 " + "{5} --warmup_time={6}'".format(duration, rate, framesize, _p0, + _p1, _async, warmup_time), timeout=int(duration)+60) elif traffic_type in ["3-node-IPv4"]: (ret, stdout, stderr) = ssh.exec_command( "sh -c '/tmp/openvpp-testing/resources/tools/t-rex/" "t-rex-stateless.py " - "-d {0} -r {1} -s {2} " + "--duration={0} -r {1} -s {2} " "--p{3}_src_start_ip 10.10.10.2 " "--p{3}_src_end_ip 10.10.10.254 " "--p{3}_dst_start_ip 20.20.20.2 " "--p{4}_src_start_ip 20.20.20.2 " "--p{4}_src_end_ip 20.20.20.254 " - "--p{4}_dst_start_ip 10.10.10.2'".\ - format(duration, rate, framesize, _p0, _p1),\ + "--p{4}_dst_start_ip 10.10.10.2 " + "{5} --warmup_time={6}'".format(duration, rate, framesize, _p0, + _p1, _async, warmup_time), timeout=int(duration)+60) elif traffic_type in ["3-node-IPv6"]: (ret, stdout, stderr) = ssh.exec_command( "sh -c '/tmp/openvpp-testing/resources/tools/t-rex/" "t-rex-stateless.py " - "-d {0} -r {1} -s {2} -6 " + "--duration={0} -r {1} -s {2} -6 " "--p{3}_src_start_ip 2001:1::2 " "--p{3}_src_end_ip 2001:1::FE " "--p{3}_dst_start_ip 2001:2::2 " "--p{4}_src_start_ip 2001:2::2 " "--p{4}_src_end_ip 2001:2::FE " - "--p{4}_dst_start_ip 2001:1::2'".\ - format(duration, rate, framesize, _p0, _p1),\ + "--p{4}_dst_start_ip 2001:1::2 " + "{5} --warmup_time={6}'".format(duration, rate, framesize, _p0, + _p1, _async, warmup_time), timeout=int(duration)+60) else: raise NotImplementedError('Unsupported traffic type') @@ -261,6 +300,11 @@ class TrafficGenerator(object): if int(ret) != 0: raise RuntimeError('T-rex stateless runtime error') + elif async_call: + #no result + self._received = None + self._sent = None + self._loss = None else: # last line from console output line = stdout.splitlines()[-1] @@ -272,16 +316,24 @@ class TrafficGenerator(object): self._sent = self._result.split(', ')[2].split('=')[1] self._loss = self._result.split(', ')[3].split('=')[1] - def send_traffic_on(self, node, duration, rate, - framesize, traffic_type): + def stop_traffic_on_tg(self): + """Stop all traffic on TG + + :return: Nothing + """ + if self._node is None: + raise RuntimeError("TG is not set") + if self._node['subtype'] == NodeSubTypeTG.TREX: + self.trex_stl_stop_remote_exec(self._node) + + def send_traffic_on_tg(self, duration, rate, framesize, + traffic_type, warmup_time=5, async_call=False): """Send traffic from all configured interfaces on TG. - :param node: Dictionary containing TG information. :param duration: Duration of test traffic generation in seconds. :param rate: Offered load per interface (e.g. 1%, 3gbps, 4mpps, ...). :param framesize: Frame size (L2) in Bytes. :param traffic_type: Traffic profile. - :type node: dict :type duration: str :type rate: str :type framesize: str @@ -289,14 +341,20 @@ class TrafficGenerator(object): :return: TG output. :rtype: str """ + + node = self._node + if node is None: + raise RuntimeError("TG is not set") + if node['type'] != NodeType.TG: raise Exception('Node type is not a TG') if node['subtype'] is None: raise Exception('TG subtype not defined') elif node['subtype'] == NodeSubTypeTG.TREX: - self.trex_stateless_remote_exec(duration, rate, framesize, - traffic_type) + self.trex_stl_start_remote_exec(duration, rate, framesize, + traffic_type, async_call, + warmup_time=warmup_time) else: raise NotImplementedError("TG subtype not supported") diff --git a/resources/libraries/python/VppCounters.py b/resources/libraries/python/VppCounters.py index d8d4554899..4bb7d63135 100644 --- a/resources/libraries/python/VppCounters.py +++ b/resources/libraries/python/VppCounters.py @@ -57,9 +57,19 @@ class VppCounters(object): vat = VatExecutor() vat.execute_script("show_errors_verbose.vat", node, json_out=False) + @staticmethod + def vpp_show_runtime(node): + """Run "show runtime" CLI command. + + :param node: Node to run command on. + :type node: dict + """ + vat = VatExecutor() + vat.execute_script("show_runtime.vat", node, json_out=False) + @staticmethod def vpp_show_runtime_verbose(node): - """Run "show runtime" debug CLI command. + """Run "show runtime verbose" CLI command. :param node: Node to run command on. :type node: dict @@ -77,6 +87,16 @@ class VppCounters(object): vat = VatExecutor() vat.execute_script("show_hardware_detail.vat", node, json_out=False) + @staticmethod + def vpp_clear_runtime(node): + """Run "clear runtime" CLI command. + + :param node: Node to run command on. + :type node: dict + """ + vat = VatExecutor() + vat.execute_script("clear_runtime.vat", node, json_out=False) + @staticmethod def vpp_clear_interface_counters(node): """Clear interface counters on VPP node. diff --git a/resources/libraries/robot/counters.robot b/resources/libraries/robot/counters.robot index b4db3febd9..0cb18c15db 100644 --- a/resources/libraries/robot/counters.robot +++ b/resources/libraries/robot/counters.robot @@ -43,6 +43,17 @@ | | [Arguments] | ${node} | | Vpp Dump Stats Table | ${node} | | Vpp Show Errors | ${node} -| | Vpp Show Errors Verbose | ${node} | | Vpp Show Hardware Detail | ${node} -| | Vpp Show Runtime Verbose | ${node} +| | Vpp Show Runtime | ${node} + +| Clear runtime statistics on all DUTs +| | [Documentation] | Clear VPP runtime statistics on all DUTs +| | ${duts}= | Get Matches | ${nodes} | DUT* +| | :FOR | ${dut} | IN | @{duts} +| | | Vpp clear runtime | ${nodes['${dut}']} + +| Show runtime statistics on all DUTs +| | [Documentation] | Show VPP runtime statistics on all DUTs +| | ${duts}= | Get Matches | ${nodes} | DUT* +| | :FOR | ${dut} | IN | @{duts} +| | | Vpp show runtime | ${nodes['${dut}']} diff --git a/resources/libraries/robot/performance.robot b/resources/libraries/robot/performance.robot index d43073d30d..e26bc19283 100644 --- a/resources/libraries/robot/performance.robot +++ b/resources/libraries/robot/performance.robot @@ -162,7 +162,8 @@ | | [Documentation] | Find throughput by using RFC2544 linear search | | [Arguments] | ${framesize} | ${start_rate} | ${step_rate} | | ... | ${topology_type} | ${min_rate} | ${max_rate} -| | Set Duration | 60 +| | ${duration}= | Set Variable | 60 +| | Set Duration | ${duration} | | Set Search Rate Boundaries | ${max_rate} | ${min_rate} | | Set Search Linear Step | ${step_rate} | | Set Search Frame Size | ${framesize} @@ -170,12 +171,15 @@ | | Linear Search | ${start_rate} | ${topology_type} | | ${rate_per_stream}= | Verify Search Result | | Display result of NDR search | ${rate_per_stream} | ${framesize} | 2 +| | Clear and show runtime stats with running traffic | ${duration} +| | ... | ${rate_per_stream}pps | ${framesize} | ${topology_type} | Find NDR using binary search and pps | | [Documentation] | Find throughput by using RFC2544 binary search | | [Arguments] | ${framesize} | ${binary_min} | ${binary_max} | | ... | ${topology_type} | ${min_rate} | ${max_rate} | ${threshold} -| | Set Duration | 60 +| | ${duration}= | Set Variable | 60 +| | Set Duration | ${duration} | | Set Search Rate Boundaries | ${max_rate} | ${min_rate} | | Set Search Frame Size | ${framesize} | | Set Search Rate Type pps @@ -183,13 +187,16 @@ | | Binary Search | ${binary_min} | ${binary_max} | ${topology_type} | | ${rate_per_stream}= | Verify Search Result | | Display result of NDR search | ${rate_per_stream} | ${framesize} | 2 +| | Clear and show runtime stats with running traffic | ${duration} +| | ... | ${rate_per_stream}pps | ${framesize} | ${topology_type} | Find NDR using combined search and pps | | [Documentation] | Find throughput by using RFC2544 combined search | | ... | (linear + binary) | | [Arguments] | ${framesize} | ${start_rate} | ${step_rate} | | ... | ${topology_type} | ${min_rate} | ${max_rate} | ${threshold} -| | Set Duration | 60 +| | ${duration}= | Set Variable | 60 +| | Set Duration | ${duration} | | Set Search Rate Boundaries | ${max_rate} | ${min_rate} | | Set Search Linear Step | ${step_rate} | | Set Search Frame Size | ${framesize} @@ -198,6 +205,8 @@ | | Combined Search | ${start_rate} | ${topology_type} | | ${rate_per_stream}= | Verify Search Result | | Display result of NDR search | ${rate_per_stream} | ${framesize} | 2 +| | Clear and show runtime stats with running traffic | ${duration} +| | ... | ${rate_per_stream}pps | ${framesize} | ${topology_type} | Display result of NDR search | | [Documentation] | Display result of NDR search in packet per seconds (total @@ -209,9 +218,19 @@ | | Set Test Message | (${nr_streams}x ${rate_per_stream} pps) | append=yes | | Set Test Message | FINAL_BANDWIDTH: ${bandwidth_total} Gbps | append=yes - | Traffic should pass with no loss | | [Arguments] | ${duration} | ${rate} | ${framesize} | ${topology_type} -| | Send traffic on | ${tg} | ${duration} -| | ... | ${rate} | ${framesize} | ${topology_type} +| | Clear and show runtime stats with running traffic | ${duration} +| | ... | ${rate} | ${framesize} | ${topology_type} +| | Send traffic on tg | ${duration} | ${rate} | ${framesize} +| | ... | ${topology_type} | | No traffic loss occurred + +| Clear and show runtime stats with running traffic +| | [Arguments] | ${duration} | ${rate} | ${framesize} | ${topology_type} +| | Send traffic on tg | -1 | ${rate} | ${framesize} +| | ... | ${topology_type} | warmup_time=0 | async_call=True +| | Clear runtime statistics on all DUTs +| | Sleep | ${duration} +| | Show runtime statistics on all DUTs +| | Stop traffic on tg diff --git a/resources/templates/vat/clear_runtime.vat b/resources/templates/vat/clear_runtime.vat new file mode 100644 index 0000000000..931fd5fe54 --- /dev/null +++ b/resources/templates/vat/clear_runtime.vat @@ -0,0 +1 @@ +exec clear runtime diff --git a/resources/templates/vat/show_runtime.vat b/resources/templates/vat/show_runtime.vat new file mode 100644 index 0000000000..1baaedb0e6 --- /dev/null +++ b/resources/templates/vat/show_runtime.vat @@ -0,0 +1 @@ +exec show runtime diff --git a/resources/tools/t-rex/t-rex-stateless-stop.py b/resources/tools/t-rex/t-rex-stateless-stop.py new file mode 100755 index 0000000000..e9accbe3ab --- /dev/null +++ b/resources/tools/t-rex/t-rex-stateless-stop.py @@ -0,0 +1,97 @@ +#!/usr/bin/python + +# Copyright (c) 2016 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""This script uses T-REX stateless API to drive t-rex instance. + +Requirements: +- T-REX: https://github.com/cisco-system-traffic-generator/trex-core + - compiled and running T-REX process (eg. ./t-rex-64 -i -c 4) + - trex_stl_lib.api library +- Script must be executed on a node with T-REX instance + +Functionality: +1. Stop any running traffic + +""" + +import sys + +sys.path.insert(0, "/opt/trex-core-2.00/scripts/automation/"+\ + "trex_control_plane/stl/") +from trex_stl_lib.api import * + + +def stop_all_traffic_streams(): + """Stop traffic if any is running. + + :return: nothing + """ + + # create client + client = STLClient() + + try: + # turn this off if too many logs + #client.set_verbose("high") + + # connect to server + client.connect() + + client.acquire(force=True) + client.stop(ports=[0, 1]) + + # read the stats after the test + stats = client.get_stats() + + print "#####statistics (approx.)#####" + print json.dumps(stats, indent=4, + separators=(',', ': '), sort_keys=True) + + lost_a = stats[0]["opackets"] - stats[1]["ipackets"] + lost_b = stats[1]["opackets"] - stats[0]["ipackets"] + + total_sent = stats[0]["opackets"] + stats[1]["opackets"] + total_rcvd = stats[0]["ipackets"] + stats[1]["ipackets"] + + print "\npackets lost from 0 --> 1: {0} pkts".format(lost_a) + print "packets lost from 1 --> 0: {0} pkts".format(lost_b) + + except STLError as ex_error: + print_error(str(ex_error)) + sys.exit(1) + + finally: + client.disconnect() + + + +def print_error(msg): + """Print error message on stderr. + + :param msg: Error message to print. + :type msg: string + :return: nothing + """ + + sys.stderr.write(msg+'\n') + + +def main(): + """Main function.""" + + stop_all_traffic_streams() + +if __name__ == "__main__": + main() diff --git a/resources/tools/t-rex/t-rex-stateless.py b/resources/tools/t-rex/t-rex-stateless.py index 97ccc97304..5a03273339 100755 --- a/resources/tools/t-rex/t-rex-stateless.py +++ b/resources/tools/t-rex/t-rex-stateless.py @@ -41,11 +41,12 @@ Functionality: """ +import argparse import json import socket import string import struct -import sys, getopt +import sys sys.path.insert(0, "/opt/trex-core-2.00/scripts/automation/"+\ "trex_control_plane/stl/") @@ -216,19 +217,21 @@ def create_packets_v6(traffic_options, frame_size=78): return(pkt_a, pkt_b) -def simple_burst(pkt_a, pkt_b, duration=10, rate="1mpps", warmup_time=5): +def simple_burst(pkt_a, pkt_b, duration, rate, warmup_time, async_start): """Run the traffic with specific parameters. :param pkt_a: Base packet for stream 1. :param pkt_b: Base packet for stream 2. - :param duration: Duration of traffic run in seconds. + :param duration: Duration of traffic run in seconds (-1=infinite). :param rate: Rate of traffic run [percentage, pps, bps]. :param warmup_time: Warm up duration. + :async_start: Start the traffic and exit :type pkt_a: STLPktBuilder :type pkt_b: STLPktBuilder :type duration: int :type rate: string :type warmup_time: int + :type async_start: bool :return: nothing """ @@ -264,7 +267,7 @@ def simple_burst(pkt_a, pkt_b, duration=10, rate="1mpps", warmup_time=5): client.add_streams(stream2, ports=[1]) #warmup phase - if warmup_time is not None: + if warmup_time > 0: client.clear_stats() client.start(ports=[0, 1], mult=rate, duration=warmup_time) client.wait_on_traffic(ports=[0, 1], timeout=(warmup_time+30)) @@ -290,54 +293,37 @@ def simple_burst(pkt_a, pkt_b, duration=10, rate="1mpps", warmup_time=5): # choose rate and start traffic client.start(ports=[0, 1], mult=rate, duration=duration) - # block until done - client.wait_on_traffic(ports=[0, 1], timeout=(duration+30)) + if not async_start: + # block until done + client.wait_on_traffic(ports=[0, 1], timeout=(duration+30)) - # read the stats after the test - stats = client.get_stats() + # read the stats after the test + stats = client.get_stats() - print "#####statistics#####" - print json.dumps(stats, indent=4, - separators=(',', ': '), sort_keys=True) + print "#####statistics#####" + print json.dumps(stats, indent=4, + separators=(',', ': '), sort_keys=True) - lost_a = stats[0]["opackets"] - stats[1]["ipackets"] - lost_b = stats[1]["opackets"] - stats[0]["ipackets"] + lost_a = stats[0]["opackets"] - stats[1]["ipackets"] + lost_b = stats[1]["opackets"] - stats[0]["ipackets"] - total_sent = stats[0]["opackets"] + stats[1]["opackets"] - total_rcvd = stats[0]["ipackets"] + stats[1]["ipackets"] + total_sent = stats[0]["opackets"] + stats[1]["opackets"] + total_rcvd = stats[0]["ipackets"] + stats[1]["ipackets"] - print "\npackets lost from 0 --> 1: {0} pkts".format(lost_a) - print "packets lost from 1 --> 0: {0} pkts".format(lost_b) + print "\npackets lost from 0 --> 1: {0} pkts".format(lost_a) + print "packets lost from 1 --> 0: {0} pkts".format(lost_b) except STLError as ex_error: print_error(str(ex_error)) sys.exit(1) finally: - client.disconnect() - print "rate={0}, totalReceived={1}, totalSent={2}, frameLoss={3}"\ - .format(rate, total_rcvd, total_sent, lost_a+lost_b) - - -def print_help(): - """Print help on stdout.""" - - print "args: [-h] -d -s "+\ - " [-r] "+\ - " [-6] Use of ipv6 "+\ - "--p1_src_mac "+\ - "--p1_dst_mac "+\ - "--p1_src_start_ip "+\ - "--p1_src_end_ip "+\ - "--p1_dst_start_ip "+\ - "--p1_dst_end_ip "+\ - "--p2_src_mac "+\ - "--p2_dst_mac "+\ - "--p2_src_start_ip "+\ - "--p2_src_end_ip "+\ - "--p2_dst_start_ip "+\ - "--p2_dst_end_ip " - + if async_start: + client.disconnect(stop_traffic=False, release_ports=True) + else: + client.disconnect() + print "rate={0}, totalReceived={1}, totalSent={2}, frameLoss={3}"\ + .format(rate, total_rcvd, total_sent, lost_a+lost_b) def print_error(msg): """Print error message on stderr. @@ -350,53 +336,69 @@ def print_error(msg): sys.stderr.write(msg+'\n') -def main(argv): +def main(): """Main function.""" - _duration = 10 - _frame_size = 64 - _rate = '1mpps' _traffic_options = {} + #default L3 profile is IPv4 _use_ipv6 = False - - try: - opts, _ = getopt.getopt(argv, "hd:s:r:6o:", - ["help", - "p1_src_mac=", - "p1_dst_mac=", - "p1_src_start_ip=", - "p1_src_end_ip=", - "p1_dst_start_ip=", - "p1_dst_end_ip=", - "p2_src_mac=", - "p2_dst_mac=", - "p2_src_start_ip=", - "p2_src_end_ip=", - "p2_dst_start_ip=", - "p2_dst_end_ip="]) - except getopt.GetoptError: - print_help() - sys.exit(1) - for opt, arg in opts: - if opt in ('-h', "--help"): - print_help() - sys.exit() - elif opt == '-d': - _duration = int(arg) - elif opt == '-s': - _frame_size = int(arg) - elif opt == '-r': - _rate = arg - elif opt == '-6': - _use_ipv6 = True - elif opt.startswith("--p"): - _traffic_options[opt[2:]] = arg - - print _traffic_options - if len(_traffic_options) != 6: - print_error("Supported only: src_start_ip, src_end_ip, dst_start_ip") - print_help() - sys.exit(1) + #default warmup time is 5 seconds + _warmup_time = 5 + #default behaviour of this script is sychronous + _async_call = False + + parser = argparse.ArgumentParser() + parser.add_argument("-d", "--duration", required=True, type=int, + help="Duration of traffic run") + parser.add_argument("-s", "--frame_size", required=True, type=int, + help="Size of a Frame without padding and IPG") + parser.add_argument("-r", "--rate", required=True, + help="Traffic rate with included units (%, pps)") + parser.add_argument("-6", "--use_IPv6", action="store_true", + help="Use IPv6 traffic profile instead of IPv4") + parser.add_argument("--async", action="store_true", + help="Non-blocking call of the script") + parser.add_argument("-w", "--warmup_time", type=int, + help="Traffic warmup time in seconds, 0 = disable") +# parser.add_argument("--p1_src_mac", +# help="Port 1 source MAC address") +# parser.add_argument("--p1_dst_mac", +# help="Port 1 destination MAC address") + parser.add_argument("--p1_src_start_ip", required=True, + help="Port 1 source start IP address") + parser.add_argument("--p1_src_end_ip", required=True, + help="Port 1 source end IP address") + parser.add_argument("--p1_dst_start_ip", required=True, + help="Port 1 destination start IP address") +# parser.add_argument("--p1_dst_end_ip", +# help="Port 1 destination end IP address") +# parser.add_argument("--p2_src_mac", +# help="Port 2 source MAC address") +# parser.add_argument("--p2_dst_mac", +# help="Port 2 destination MAC address") + parser.add_argument("--p2_src_start_ip", required=True, + help="Port 2 source start IP address") + parser.add_argument("--p2_src_end_ip", required=True, + help="Port 2 source end IP address") + parser.add_argument("--p2_dst_start_ip", required=True, + help="Port 2 destination start IP address") +# parser.add_argument("--p2_dst_end_ip", +# help="Port 2 destination end IP address") + + args = parser.parse_args() + + _duration = args.duration + _frame_size = args.frame_size + _rate = args.rate + _use_ipv6 = args.use_IPv6 + _async_call = args.async + + if args.warmup_time is not None: + _warmup_time = args.warmup_time + + for attr in [a for a in dir(args) if a.startswith('p')]: + if getattr(args, attr) is not None: + _traffic_options[attr] = getattr(args, attr) if _use_ipv6: pkt_a, pkt_b = create_packets_v6(_traffic_options, @@ -405,7 +407,7 @@ def main(argv): pkt_a, pkt_b = create_packets(_traffic_options, frame_size=_frame_size) - simple_burst(pkt_a, pkt_b, duration=_duration, rate=_rate) + simple_burst(pkt_a, pkt_b, _duration, _rate, _warmup_time, _async_call) if __name__ == "__main__": - main(sys.argv[1:]) + sys.exit(main())