summaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
authorYaroslav Brustinov <ybrustin@cisco.com>2016-03-31 18:26:17 +0300
committerYaroslav Brustinov <ybrustin@cisco.com>2016-03-31 18:26:17 +0300
commitcf6092b407c624ab8d6cf671e1e30bc981ed6826 (patch)
tree0113bfe19931e16554994dcf134bcd85fd779a4a /scripts
parentfff0f8effc3fa7f5a67246d79d11e61163bc92bb (diff)
parent72508ce12379dae35ec41b321d43638135e223ba (diff)
Merge remote-tracking branch 'origin/master'
Diffstat (limited to 'scripts')
-rw-r--r--scripts/automation/regression/functional_tests/scapy_pkt_builder_test.py3
-rw-r--r--scripts/automation/regression/stateless_tests/stl_client_test.py274
-rwxr-xr-x[-rw-r--r--]scripts/automation/trex_control_plane/doc_stl/api/client_code.rst36
-rwxr-xr-x[-rw-r--r--]scripts/automation/trex_control_plane/doc_stl/api/field_engine.rst14
-rwxr-xr-x[-rw-r--r--]scripts/automation/trex_control_plane/doc_stl/api/index.rst0
-rwxr-xr-x[-rw-r--r--]scripts/automation/trex_control_plane/doc_stl/api/profile_code.rst8
-rwxr-xr-x[-rw-r--r--]scripts/automation/trex_control_plane/doc_stl/api/scapy_builder.rst10
-rw-r--r--scripts/automation/trex_control_plane/doc_stl/conf.py2
-rw-r--r--scripts/automation/trex_control_plane/doc_stl/index.rst12
-rw-r--r--scripts/automation/trex_control_plane/stl/examples/stl_imix.py2
-rwxr-xr-x[-rw-r--r--]scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py250
-rwxr-xr-x[-rw-r--r--]scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_packet_builder_scapy.py185
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_port.py64
-rwxr-xr-x[-rw-r--r--]scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_streams.py117
-rw-r--r--scripts/stl/flow_stats.py6
-rw-r--r--scripts/stl/udp_1pkt_pcap.py5
-rw-r--r--scripts/stl/udp_3pkt_pcap.py9
-rw-r--r--scripts/stl/yaml/imix_1pkt_vm_minus.yaml3
18 files changed, 713 insertions, 287 deletions
diff --git a/scripts/automation/regression/functional_tests/scapy_pkt_builder_test.py b/scripts/automation/regression/functional_tests/scapy_pkt_builder_test.py
index a3fcd091..5d34e5df 100644
--- a/scripts/automation/regression/functional_tests/scapy_pkt_builder_test.py
+++ b/scripts/automation/regression/functional_tests/scapy_pkt_builder_test.py
@@ -238,7 +238,8 @@ class CTRexPktBuilderSanitySCapy_Test(pkt_bld_general_test.CGeneralPktBld_Test):
d= pkt_builder.get_vm_data()
except CTRexPacketBuildException as e:
- assert_equal(str(e), "[errcode:-11] 'variable my_valn_err does not exists '")
+ error=str(e)
+ assert_equal(error.find("[errcode:-11]"),0);
def test_simple_tuple_gen(self):
vm = STLScVmRaw( [ STLVmTupleGen(name="tuple"), # define tuple gen
diff --git a/scripts/automation/regression/stateless_tests/stl_client_test.py b/scripts/automation/regression/stateless_tests/stl_client_test.py
new file mode 100644
index 00000000..132109c0
--- /dev/null
+++ b/scripts/automation/regression/stateless_tests/stl_client_test.py
@@ -0,0 +1,274 @@
+#!/router/bin/python
+from stl_general_test import CStlGeneral_Test, CTRexScenario
+from trex_stl_lib.api import *
+import os, sys
+import glob
+
+
+def get_error_in_percentage (golden, value):
+ return abs(golden - value) / float(golden)
+
+def get_stl_profiles ():
+ profiles_path = os.path.join(CTRexScenario.scripts_path, 'stl/')
+ profiles = glob.glob(profiles_path + "/*.py") + glob.glob(profiles_path + "yaml/*.yaml")
+
+ return profiles
+
+
+class STLClient_Test(CStlGeneral_Test):
+ """Tests for stateless client"""
+
+ def setUp(self):
+ CStlGeneral_Test.setUp(self)
+
+ assert 'bi' in CTRexScenario.stl_ports_map
+
+ self.c = CTRexScenario.stl_trex
+
+ self.tx_port, self.rx_port = CTRexScenario.stl_ports_map['bi'][0]
+
+ self.c.connect()
+ self.c.reset(ports = [self.tx_port, self.rx_port])
+
+ self.pkt = STLPktBuilder(pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)/IP()/'a_payload_example')
+ self.profiles = get_stl_profiles()
+
+
+ @classmethod
+ def tearDownClass(cls):
+ # connect back at end of tests
+ if not cls.is_connected():
+ CTRexScenario.stl_trex.connect()
+
+
+ def test_basic_connect_disconnect (self):
+ try:
+ self.c.connect()
+ assert self.c.is_connected(), 'client should be connected'
+ self.c.disconnect()
+ assert not self.c.is_connected(), 'client should be disconnected'
+
+ except STLError as e:
+ assert False , '{0}'.format(e)
+
+
+ def test_basic_single_burst (self):
+ try:
+ b1 = STLStream(name = 'burst',
+ packet = self.pkt,
+ mode = STLTXSingleBurst(total_pkts = 100,
+ pps = 1000)
+ )
+
+ for i in range(0, 5):
+ self.c.add_streams([b1], ports = [self.tx_port, self.rx_port])
+
+ self.c.clear_stats()
+ self.c.start(ports = [self.tx_port, self.rx_port])
+
+ assert self.c.ports[self.tx_port].is_transmitting(), 'port should be active'
+ assert self.c.ports[self.rx_port].is_transmitting(), 'port should be active'
+
+ self.c.wait_on_traffic(ports = [self.tx_port, self.rx_port])
+ stats = self.c.get_stats()
+
+ assert self.tx_port in stats
+ assert self.rx_port in stats
+
+ assert stats[self.tx_port]['opackets'] == 100
+ assert stats[self.rx_port]['ipackets'] == 100
+
+ assert stats[self.rx_port]['opackets'] == 100
+ assert stats[self.tx_port]['ipackets'] == 100
+
+ self.c.remove_all_streams(ports = [self.tx_port, self.rx_port])
+
+
+
+ except STLError as e:
+ assert False , '{0}'.format(e)
+
+
+ #
+ def test_basic_multi_burst (self):
+ try:
+ b1 = STLStream(name = 'burst',
+ packet = self.pkt,
+ mode = STLTXMultiBurst(pkts_per_burst = 10,
+ count = 20,
+ pps = 1000)
+ )
+
+ for i in range(0, 5):
+ self.c.add_streams([b1], ports = [self.tx_port, self.rx_port])
+
+ self.c.clear_stats()
+ self.c.start(ports = [self.tx_port, self.rx_port])
+
+ assert self.c.ports[self.tx_port].is_transmitting(), 'port should be active'
+ assert self.c.ports[self.rx_port].is_transmitting(), 'port should be active'
+
+ self.c.wait_on_traffic(ports = [self.tx_port, self.rx_port])
+ stats = self.c.get_stats()
+
+ assert self.tx_port in stats
+ assert self.rx_port in stats
+
+ assert stats[self.tx_port]['opackets'] == 200
+ assert stats[self.rx_port]['ipackets'] == 200
+
+ assert stats[self.rx_port]['opackets'] == 200
+ assert stats[self.tx_port]['ipackets'] == 200
+
+ self.c.remove_all_streams(ports = [self.tx_port, self.rx_port])
+
+
+
+ except STLError as e:
+ assert False , '{0}'.format(e)
+
+
+ #
+ def test_basic_cont (self):
+ pps = 49182
+ duration = 0.1
+ golden = pps * duration
+
+ try:
+ b1 = STLStream(name = 'burst',
+ packet = self.pkt,
+ mode = STLTXCont(pps = pps)
+ )
+
+ for i in range(0, 5):
+ self.c.add_streams([b1], ports = [self.tx_port, self.rx_port])
+
+ self.c.clear_stats()
+ self.c.start(ports = [self.tx_port, self.rx_port], duration = duration)
+
+ assert self.c.ports[self.tx_port].is_transmitting(), 'port should be active'
+ assert self.c.ports[self.rx_port].is_transmitting(), 'port should be active'
+
+ self.c.wait_on_traffic(ports = [self.tx_port, self.rx_port])
+ stats = self.c.get_stats()
+
+ assert self.tx_port in stats
+ assert self.rx_port in stats
+
+ # cont. with duration should be quite percise - 5% error is relaxed enough
+ assert get_error_in_percentage(stats[self.tx_port]['opackets'], golden) < 0.05
+ assert get_error_in_percentage(stats[self.rx_port]['ipackets'], golden) < 0.05
+
+ assert get_error_in_percentage(stats[self.rx_port]['opackets'], golden) < 0.05
+ assert get_error_in_percentage(stats[self.tx_port]['ipackets'], golden) < 0.05
+
+
+ self.c.remove_all_streams(ports = [self.tx_port, self.rx_port])
+
+
+
+ except STLError as e:
+ assert False , '{0}'.format(e)
+
+
+ def test_stress_connect_disconnect (self):
+ try:
+ for i in range(0, 100):
+ self.c.connect()
+ assert self.c.is_connected(), 'client should be connected'
+ self.c.disconnect()
+ assert not self.c.is_connected(), 'client should be disconnected'
+
+
+ except STLError as e:
+ assert False , '{0}'.format(e)
+
+
+
+ def test_stress_tx (self):
+ try:
+ s1 = STLStream(name = 'stress',
+ packet = self.pkt,
+ mode = STLTXCont(percentage = 60))
+
+ # add both streams to ports
+ self.c.add_streams([s1], ports = [self.tx_port, self.rx_port])
+ for i in range(0, 100):
+
+ self.c.start(ports = [self.tx_port, self.rx_port])
+
+ assert self.c.ports[self.tx_port].is_transmitting(), 'port should be active'
+ assert self.c.ports[self.rx_port].is_transmitting(), 'port should be active'
+
+ self.c.pause(ports = [self.tx_port, self.rx_port])
+
+ assert self.c.ports[self.tx_port].is_paused(), 'port should be paused'
+ assert self.c.ports[self.rx_port].is_paused(), 'port should be paused'
+
+ self.c.resume(ports = [self.tx_port, self.rx_port])
+
+ assert self.c.ports[self.tx_port].is_transmitting(), 'port should be active'
+ assert self.c.ports[self.rx_port].is_transmitting(), 'port should be active'
+
+ self.c.stop(ports = [self.tx_port, self.rx_port])
+
+ assert not self.c.ports[self.tx_port].is_active(), 'port should be idle'
+ assert not self.c.ports[self.rx_port].is_active(), 'port should be idle'
+
+ except STLError as e:
+ assert False , '{0}'.format(e)
+
+
+ def test_all_profiles (self):
+
+ if self.is_virt_nics or not self.is_loopback:
+ print("skipping for non loopback / virtual")
+ return
+
+ try:
+ self.c.set_port_attr(ports = [self.tx_port, self.rx_port], promiscuous = True)
+
+ for profile in self.profiles:
+ print("now testing profile {0}...\n").format(profile)
+
+ p1 = STLProfile.load(profile, port_id = self.tx_port)
+ p2 = STLProfile.load(profile, port_id = self.rx_port)
+
+ if p1.has_flow_stats():
+ print("profile needs RX caps - skipping...")
+ continue
+
+ self.c.add_streams(p1, ports = self.tx_port)
+ self.c.add_streams(p2, ports = self.rx_port)
+
+ self.c.clear_stats()
+
+ self.c.start(ports = [self.tx_port, self.rx_port], mult = "30%")
+ time.sleep(100 / 1000.0)
+
+ if p1.is_pauseable() and p2.is_pauseable():
+ self.c.pause(ports = [self.tx_port, self.rx_port])
+ time.sleep(100 / 1000.0)
+
+ self.c.resume(ports = [self.tx_port, self.rx_port])
+ time.sleep(100 / 1000.0)
+
+ self.c.stop(ports = [self.tx_port, self.rx_port])
+
+ stats = self.c.get_stats()
+
+ assert self.tx_port in stats, '{0} - no stats for TX port'.format(profile)
+ assert self.rx_port in stats, '{0} - no stats for RX port'.format(profile)
+
+ assert stats[self.tx_port]['opackets'] == stats[self.rx_port]['ipackets'], '{0} - number of TX packets differ from RX packets'.format(profile)
+
+ assert stats[self.rx_port]['opackets'] == stats[self.tx_port]['ipackets'], '{0} - number of TX packets differ from RX packets'.format(profile)
+
+ self.c.remove_all_streams(ports = [self.tx_port, self.rx_port])
+
+ except STLError as e:
+ assert False , '{0}'.format(e)
+
+
+ finally:
+ self.c.set_port_attr(ports = [self.tx_port, self.rx_port], promiscuous = False)
diff --git a/scripts/automation/trex_control_plane/doc_stl/api/client_code.rst b/scripts/automation/trex_control_plane/doc_stl/api/client_code.rst
index 8736e98d..4ae2b9fd 100644..100755
--- a/scripts/automation/trex_control_plane/doc_stl/api/client_code.rst
+++ b/scripts/automation/trex_control_plane/doc_stl/api/client_code.rst
@@ -2,16 +2,26 @@
Client Module
==================
-TRex Client is an object to access TRex server. It is per user. Each user can own number of interfaces.
-Multi user can interact with one TRex server each user should own a different set of interfaces.
+The TRex Client provides access to the TRex server.
+
+**Client and interfaces**
+
+Multiple users can interact with one TRex server. Each user "owns" a different set of interfaces.
The protocol is JSON-RPC2 over ZMQ transport.
-The API has two type of API
+In addition to the Python API, a console-based API interface is also available.
+
+Python-like example::
+
+ c.start(ports = [0, 1], mult = "5mpps", duration = 10)
+
+Console-like example::
+
+ c.start_line (" -f stl/udp_1pkt_simple.py -m 10mpps --port 0 1 ")
-1. Normal API
-2. xx_line: this api get a line like the Console and parse it and call the low level api
-Example1::
+
+Example 1 - Typical Python API::
c = STLClient(username = "itay",server = "10.0.0.10", verbose_level = LoggerApi.VERBOSE_HIGH)
@@ -49,7 +59,8 @@ STLClient snippet
-----------------
-Example1::
+.. code-block:: python
+ :caption: Example 1: Minimal example of client interacting with the TRex server
c = STLClient()
@@ -75,8 +86,9 @@ Example1::
c.disconnect()
+.. code-block:: python
+ :caption: Example 2: Client can execute other functions while the TRex server is generating traffic
-Example2: wait while doing somthing::
c = STLClient()
try:
@@ -99,7 +111,10 @@ Example2: wait while doing somthing::
c.disconnect()
-Example3: Console like::
+
+.. code-block:: python
+ :caption: Example 3: Console-like API interface
+
def simple ():
@@ -148,7 +163,8 @@ Example3: Console like::
finally:
c.disconnect()
-Example4: Load profile from a file::
+
+Example 4: Load profile from a file::
def simple ():
diff --git a/scripts/automation/trex_control_plane/doc_stl/api/field_engine.rst b/scripts/automation/trex_control_plane/doc_stl/api/field_engine.rst
index d134b0b9..541e195f 100644..100755
--- a/scripts/automation/trex_control_plane/doc_stl/api/field_engine.rst
+++ b/scripts/automation/trex_control_plane/doc_stl/api/field_engine.rst
@@ -2,19 +2,19 @@
Field Engine modules
=======================
-The Field Engine (FE) has limited number of instructions/operation for supporting most use cases.
+The Field Engine (FE) has limited number of instructions/operations to support most use cases.
There is a plan to add LuaJIT to be more flexible at the cost of performance.
-The FE can allocate stream variables in a Stream context, write a stream variable to a packet offset, change packet size, etc.
+The FE can allocate stream variables in a stream context, write a stream variable to a packet offset, change packet size, and so on.
-*Some examples for what can be done:*
+*Examples of Field Engine uses:*
* Change ipv4.tos 1-10
-* Change packet size to be random in the range 64-9K
-* Create range of flows (change src_ip, dest_ip, src_port, dest_port)
+* Change packet size to a random value in the range 64 to 9K
+* Create a range of flows (change src_ip, dest_ip, src_port, dest_port)
* Update IPv4 checksum
-Snippet will create SYN Attack::
+The following snippet creates a SYN attack::
# create attack from random src_ip from 16.0.0.0-18.0.0.254 and random src_port 1025-65000
# attack 48.0.0.1 server
@@ -60,7 +60,7 @@ Snippet will create SYN Attack::
STLScVmRaw class
----------------
-Aggregate a raw instructions objects
+Aggregate raw instructions objects
.. autoclass:: trex_stl_lib.trex_stl_packet_builder_scapy.STLScVmRaw
:members:
diff --git a/scripts/automation/trex_control_plane/doc_stl/api/index.rst b/scripts/automation/trex_control_plane/doc_stl/api/index.rst
index a3c8ad5a..a3c8ad5a 100644..100755
--- a/scripts/automation/trex_control_plane/doc_stl/api/index.rst
+++ b/scripts/automation/trex_control_plane/doc_stl/api/index.rst
diff --git a/scripts/automation/trex_control_plane/doc_stl/api/profile_code.rst b/scripts/automation/trex_control_plane/doc_stl/api/profile_code.rst
index b61f05e4..9afa9df2 100644..100755
--- a/scripts/automation/trex_control_plane/doc_stl/api/profile_code.rst
+++ b/scripts/automation/trex_control_plane/doc_stl/api/profile_code.rst
@@ -2,13 +2,13 @@
Traffic profile modules
=======================
-TRex STLProfile profile include a list of STLStream. The profile is a ``program`` of streams with a relation betwean the streams.
-Each stream can trigger another stream. Stream can be given a name for a full examples see here Manual_.
+The TRex STLProfile traffic profile includes a number of streams. The profile is a ``program`` of related streams.
+Each stream can trigger another stream. Each stream can be named. For a full set of examples, see Manual_.
-.. _Manual: ../draft_trex_stateless1.html
+.. _Manual: ../trex_stateless.html
-for example::
+Example::
def create_stream (self):
diff --git a/scripts/automation/trex_control_plane/doc_stl/api/scapy_builder.rst b/scripts/automation/trex_control_plane/doc_stl/api/scapy_builder.rst
index 5544df63..2c5790bf 100644..100755
--- a/scripts/automation/trex_control_plane/doc_stl/api/scapy_builder.rst
+++ b/scripts/automation/trex_control_plane/doc_stl/api/scapy_builder.rst
@@ -2,15 +2,15 @@
Packet builder modules
=======================
-The packet builder module objective is to build a template packet for a stream and to create a Field engine program to change fields in the packet.
+The packet builder module is used for building a template packet for a stream, and creating a Field Engine program to change fields in the packet.
-**Some examples for what can be done:**
+**Examples:**
-* Build a IP/UDP/DNS packet and create a range of src_ip = 10.0.0.1-10.0.0.255
-* Build a IP/UDP packets in IMIX sizes
+* Build a IP/UDP/DNS packet with a src_ip range of 10.0.0.1 to 10.0.0.255
+* Build IP/UDP packets in IMIX sizes
-for example this snippet will create SYN Attack::
+For example, this snippet creates a SYN attack::
# create attack from random src_ip from 16.0.0.0-18.0.0.254 and random src_port 1025-65000
# attack 48.0.0.1 server
diff --git a/scripts/automation/trex_control_plane/doc_stl/conf.py b/scripts/automation/trex_control_plane/doc_stl/conf.py
index fe6b27bc..45738b6e 100644
--- a/scripts/automation/trex_control_plane/doc_stl/conf.py
+++ b/scripts/automation/trex_control_plane/doc_stl/conf.py
@@ -69,7 +69,7 @@ author = u'TRex team, Cisco Systems Inc.'
# The short X.Y version.
version = '1.94'
# The full version, including alpha/beta/rc tags.
-release = '1.7.1'
+release = '2.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/scripts/automation/trex_control_plane/doc_stl/index.rst b/scripts/automation/trex_control_plane/doc_stl/index.rst
index 97a1037a..aa2abd75 100644
--- a/scripts/automation/trex_control_plane/doc_stl/index.rst
+++ b/scripts/automation/trex_control_plane/doc_stl/index.rst
@@ -20,19 +20,23 @@ How to Install
| Put it at any place you like, preferably same place as your scripts.
| (If it's not at same place as your scripts, you will need to ensure trex_client directory is in sys.path)
-Un-pack it using command: tar -xzf trex_client.tar.gz
+Un-pack it using command::
-How to pyATS/v2.0
+ tar -xzf trex_client.tar.gz
+
+
+How to pyATS
==================
.. sectionauthor:: David Shen
pyATS Compatibility
-Trex only supports python2 for now, so it only works for **Python2** pyats.
+TRex supports both Python2 and Python3 pyATS.
-* Install python2 pyats
+* Install python2/python3 pyats
/auto/pyats/bin/pyats-install --python2
+ /auto/pyats/bin/pyats-install --python3
* setenv TREX_PATH to the trex stateless lib path
setenv TREX_PATH <your path>/automation/trex_control_plane/stl
diff --git a/scripts/automation/trex_control_plane/stl/examples/stl_imix.py b/scripts/automation/trex_control_plane/stl/examples/stl_imix.py
index 17e017a9..bc7990aa 100644
--- a/scripts/automation/trex_control_plane/stl/examples/stl_imix.py
+++ b/scripts/automation/trex_control_plane/stl/examples/stl_imix.py
@@ -17,6 +17,7 @@ def imix_test (server, mult):
# create client
c = STLClient(server = server)
+
passed = True
@@ -27,6 +28,7 @@ def imix_test (server, mult):
# take all the ports
c.reset()
+
# map ports - identify the routes
table = stl_map_ports(c)
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 6fdc3454..7fbd2808 100644..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
@@ -40,15 +40,15 @@ class LoggerApi(object):
# implemented by specific logger
def write(self, msg, newline = True):
- raise Exception("implement this")
+ raise Exception("Implement this")
# implemented by specific logger
def flush(self):
- raise Exception("implement this")
+ raise Exception("Implement this")
def set_verbose (self, level):
if not level in range(self.VERBOSE_QUIET, self.VERBOSE_HIGH + 1):
- raise ValueError("bad value provided for logger")
+ raise ValueError("Bad value provided for logger")
self.level = level
@@ -146,7 +146,7 @@ class AsyncEventHandler(object):
def on_async_dead (self):
if self.client.connected:
- msg = 'lost connection to server'
+ msg = 'Lost connection to server'
self.__add_event_log(msg, 'local', True)
self.client.connected = False
@@ -319,7 +319,7 @@ class AsyncEventHandler(object):
############################ #############################
class CCommLink(object):
- """describes the connectivity of the stateless client method"""
+ """Describes the connectivity of the stateless client method"""
def __init__(self, server="localhost", port=5050, virtual=False, prn_func = None):
self.virtual = virtual
self.server = server
@@ -380,7 +380,7 @@ class CCommLink(object):
############################ #############################
class STLClient(object):
- """TRex Stateless client object- gives operations per TRex/user"""
+ """TRex Stateless client object - gives operations per TRex/user"""
def __init__(self,
username = common.get_current_user(),
@@ -391,7 +391,7 @@ class STLClient(object):
logger = None,
virtual = False):
"""
- Set the connection setting
+ Configure the connection settings
:parameters:
username : string
@@ -496,11 +496,11 @@ class STLClient(object):
port_id_list = [port_id_list]
if not isinstance(port_id_list, list):
- raise ValueError("bad port id list: {0}".format(port_id_list))
+ raise ValueError("Bad port id list: {0}".format(port_id_list))
for port_id in port_id_list:
if not isinstance(port_id, int) or (port_id < 0) or (port_id > self.get_port_count()):
- raise ValueError("bad port id {0}".format(port_id))
+ raise ValueError("Bad port id {0}".format(port_id))
return port_id_list
@@ -727,7 +727,7 @@ class STLClient(object):
# connect async channel
- self.logger.pre_cmd("connecting to publisher server on {0}:{1}".format(self.connection_info['server'], self.connection_info['async_port']))
+ self.logger.pre_cmd("Connecting to publisher server on {0}:{1}".format(self.connection_info['server'], self.connection_info['async_port']))
rc = self.async_client.connect()
self.logger.post_cmd(rc)
@@ -765,7 +765,7 @@ class STLClient(object):
if clear_flow_stats:
self.flow_stats.clear_stats()
- self.logger.log_cmd("clearing stats on port(s) {0}:".format(port_id_list))
+ self.logger.log_cmd("Clearing stats on port(s) {0}:".format(port_id_list))
return RC
@@ -852,8 +852,26 @@ class STLClient(object):
return RC_OK()
-
-
+ # remove all RX filters in a safe manner
+ def _remove_rx_filters (self, ports, rx_delay_ms):
+
+ # get the enabled RX ports
+ rx_ports = [port_id for port_id in ports if self.ports[port_id].has_rx_enabled()]
+
+ if not rx_ports:
+ return RC_OK()
+
+ # block while any RX configured port has not yet have it's delay expired
+ while any([not self.ports[port_id].has_rx_delay_expired(rx_delay_ms) for port_id in rx_ports]):
+ time.sleep(0.01)
+
+ # remove RX filters
+ rc = RC()
+ for port_id in rx_ports:
+ rc.add(self.ports[port_id].remove_rx_filters())
+
+ return rc
+
#################################
# ------ private methods ------ #
@@ -914,13 +932,13 @@ class STLClient(object):
# return verbose level of the logger
def get_verbose (self):
"""
- get the verbose mode
+ Get the verbose mode
:parameters:
none
:return:
- get the verbose mode as Bool
+ Get the verbose mode as Bool
:raises:
None
@@ -934,10 +952,10 @@ class STLClient(object):
is_all_ports_acquired
:parameters:
- none
+ None
:return:
- return True if all ports are acquired
+ Returns True if all ports are acquired
:raises:
None
@@ -951,7 +969,7 @@ class STLClient(object):
"""
:parameters:
- none
+ None
:return:
is_connected
@@ -969,10 +987,10 @@ class STLClient(object):
"""
:parameters:
- none
+ None
:return:
- connection dict
+ Connection dict
:raises:
None
@@ -987,10 +1005,10 @@ class STLClient(object):
"""
:parameters:
- none
+ None
:return:
- connection dict
+ Connection dict
:raises:
None
@@ -1004,10 +1022,10 @@ class STLClient(object):
"""
:parameters:
- none
+ None
:return:
- connection dict
+ Connection dict
:raises:
None
@@ -1021,10 +1039,10 @@ class STLClient(object):
"""
:parameters:
- none
+ None
:return:
- connection dict
+ Connection dict
:raises:
None
@@ -1038,10 +1056,10 @@ class STLClient(object):
"""
:parameters:
- none
+ None
:return:
- connection dict
+ Connection dict
:raises:
None
@@ -1065,10 +1083,10 @@ class STLClient(object):
"""
:parameters:
- none
+ None
:return:
- connection dict
+ Connection dict
:raises:
None
@@ -1089,6 +1107,7 @@ class STLClient(object):
for port_id, port_obj in self.ports.items()
if port_obj.is_active()]
+
# get paused ports
def get_paused_ports (self):
return [port_id
@@ -1189,9 +1208,9 @@ class STLClient(object):
:parameters:
stop_traffic : bool
- tries to stop traffic before disconnecting
+ Attempts to stop traffic before disconnecting.
release_ports : bool
- tries to release all the acquired ports
+ Attempts to release all the acquired ports.
"""
@@ -1217,9 +1236,9 @@ class STLClient(object):
:parameters:
ports : list
- ports to execute the command
+ Ports on which to execute the command
force : bool
- force acquire the ports
+ Force acquire the ports.
:raises:
+ :exc:`STLError`
@@ -1252,7 +1271,7 @@ class STLClient(object):
:parameters:
ports : list
- ports to execute the command
+ Ports on which to execute the command
:raises:
+ :exc:`STLError`
@@ -1295,7 +1314,7 @@ class STLClient(object):
@__api_check(True)
def get_active_pgids(self):
"""
- Get active group ids
+ Get active group IDs
:parameters:
None
@@ -1319,11 +1338,11 @@ class STLClient(object):
@__api_check(True)
def reset(self, ports = None):
"""
- force acquire ports, stop the traffic, remove all streams and clear stats
+ Force acquire ports, stop the traffic, remove all streams and clear stats
:parameters:
ports : list
- ports to execute the command
+ Ports on which to execute the command
:raises:
@@ -1336,7 +1355,7 @@ class STLClient(object):
ports = self._validate_port_list(ports)
self.acquire(ports, force = True)
- self.stop(ports)
+ self.stop(ports, rx_delay_ms = 0)
self.remove_all_streams(ports)
self.clear_stats(ports)
@@ -1348,7 +1367,7 @@ class STLClient(object):
:parameters:
ports : list
- ports to execute the command
+ Ports on which to execute the command
:raises:
@@ -1371,16 +1390,16 @@ class STLClient(object):
@__api_check(True)
def add_streams (self, streams, ports = None):
"""
- add a list of streams to port(s)
+ Add a list of streams to port(s)
:parameters:
ports : list
- ports to execute the command
+ Ports on which to execute the command
streams: list
- streams to attach (or profile)
+ Streams to attach (or profile)
:returns:
- list of stream IDs in order of the stream list
+ List of stream IDs in order of the stream list
:raises:
+ :exc:`STLError`
@@ -1416,13 +1435,13 @@ class STLClient(object):
@__api_check(True)
def remove_streams (self, stream_id_list, ports = None):
"""
- remove a list of streams from ports
+ Remove a list of streams from ports
:parameters:
ports : list
- ports to execute the command
+ Ports on which to execute the command
stream_id_list: list
- stream id list to remove
+ Stream id list to remove
:raises:
@@ -1460,27 +1479,29 @@ class STLClient(object):
duration = -1,
total = False):
"""
- start traffic on port(s)
+ Start traffic on port(s)
:parameters:
ports : list
- ports to execute command
+ Ports on which to execute the command
mult : str
- multiplier in a form of pps, bps, or line util in %
- examples: "5kpps", "10gbps", "85%", "32mbps"
+ Multiplier in a form of pps, bps, or line util in %
+ Examples: "5kpps", "10gbps", "85%", "32mbps"
force : bool
- imply stopping the port of active and also
- forces a profile that exceeds the L1 BW
+ If the ports are not in stopped mode or do not have sufficient bandwidth for the traffic, determines whether to stop the current traffic and force start.
+ True: Force start
+ False: Do not force start
duration : int
- limit the run for time in seconds
- -1 means unlimited
+ Limit the run time (seconds)
+ -1 = unlimited
total : bool
- should the B/W be divided by the ports
- or duplicated for each
+ Determines whether to divide the configured bandwidth among the ports, or to duplicate the bandwidth for each port.
+ True: Divide bandwidth among the ports
+ False: Duplicate
:raises:
@@ -1535,13 +1556,20 @@ class STLClient(object):
@__api_check(True)
- def stop (self, ports = None):
+ def stop (self, ports = None, rx_delay_ms = 10):
"""
- stop port(s)
+ Stop port(s)
:parameters:
ports : list
- ports to execute the command
+ Ports on which to execute the command
+
+ rx_delay_ms : int
+ time to wait until RX filters are removed
+ this value should reflect the time it takes
+ packets which were transmitted to arrive
+ to the destination.
+ after this time the RX filters will be removed
:raises:
+ :exc:`STLError`
@@ -1561,27 +1589,35 @@ class STLClient(object):
if not rc:
raise STLError(rc)
+ # remove any RX filters
+ rc = self._remove_rx_filters(ports, rx_delay_ms = rx_delay_ms)
+ if not rc:
+ raise STLError(rc)
+
@__api_check(True)
def update (self, ports = None, mult = "1", total = False, force = False):
"""
- update traffic on port(s)
+ Update traffic on port(s)
:parameters:
ports : list
- ports to execute command
+ Ports on which to execute the command
mult : str
- multiplier in a form of pps, bps, or line util in %
- and also with +/-
- examples: "5kpps+", "10gbps-", "85%", "32mbps", "20%+"
+ Multiplier in a form of pps, bps, or line util in %
+ Can also specify +/-
+ Examples: "5kpps+", "10gbps-", "85%", "32mbps", "20%+"
force : bool
- forces a profile that exceeds the L1 BW
+ If the ports are not in stopped mode or do not have sufficient bandwidth for the traffic, determines whether to stop the current traffic and force start.
+ True: Force start
+ False: Do not force start
total : bool
- should the B/W be divided by the ports
- or duplicated for each
+ Determines whether to divide the configured bandwidth among the ports, or to duplicate the bandwidth for each port.
+ True: Divide bandwidth among the ports
+ False: Duplicate
:raises:
@@ -1619,11 +1655,11 @@ class STLClient(object):
@__api_check(True)
def pause (self, ports = None):
"""
- pause traffic on port(s). works only for ports that are active and all streams are in cont mode
+ Pause traffic on port(s). Works only for ports that are active, and only if all streams are in Continuous mode.
:parameters:
ports : list
- ports to execute command
+ Ports on which to execute the command
:raises:
+ :exc:`STLError`
@@ -1644,11 +1680,11 @@ class STLClient(object):
@__api_check(True)
def resume (self, ports = None):
"""
- resume traffic on port(s)
+ Resume traffic on port(s)
:parameters:
ports : list
- ports to execute command
+ Ports on which to execute the command
:raises:
+ :exc:`STLError`
@@ -1671,23 +1707,24 @@ class STLClient(object):
@__api_check(True)
def validate (self, ports = None, mult = "1", duration = "-1", total = False):
"""
- validate port(s) configuration
+ Validate port(s) configuration
:parameters:
ports : list
- ports to execute command
+ Ports on which to execute the command
mult : str
- multiplier in a form of pps, bps, or line util in %
- examples: "5kpps", "10gbps", "85%", "32mbps"
+ Multiplier in a form of pps, bps, or line util in %
+ Examples: "5kpps", "10gbps", "85%", "32mbps"
duration : int
- limit the run for time in seconds
- -1 means unlimited
+ Limit the run time (seconds)
+ -1 = unlimited
total : bool
- should the B/W be divided by the ports
- or duplicated for each
+ Determines whether to divide the configured bandwidth among the ports, or to duplicate the bandwidth for each port.
+ True: Divide bandwidth among the ports
+ False: Duplicate
:raises:
+ :exc:`STLError`
@@ -1723,17 +1760,17 @@ class STLClient(object):
@__api_check(False)
def clear_stats (self, ports = None, clear_global = True, clear_flow_stats = True):
"""
- clear stats on port(s)
+ Clear stats on port(s)
:parameters:
ports : list
- ports to execute command
+ Ports on which to execute the command
clear_global : bool
- clear the global stats
+ Clear the global stats
clear_flow_stats : bool
- clear the flow stats
+ Clear the flow stats
:raises:
+ :exc:`STLError`
@@ -1757,11 +1794,11 @@ class STLClient(object):
@__api_check(True)
def is_traffic_active (self, ports = None):
"""
- retrun if specify port(s) has traffic
+ Return if specified port(s) have traffic
:parameters:
ports : list
- ports to execute command
+ Ports on which to execute the command
:raises:
@@ -1778,17 +1815,25 @@ class STLClient(object):
@__api_check(True)
- def wait_on_traffic (self, ports = None, timeout = 60):
+ def wait_on_traffic (self, ports = None, timeout = 60, rx_delay_ms = 10):
"""
- block until specify port(s) traffic has ended
+ Block until traffic on specified port(s) has ended
:parameters:
ports : list
- ports to execute command
+ Ports on which to execute the command
timeout : int
timeout in seconds
+ rx_delay_ms : int
+ time to wait until RX filters are removed
+ this value should reflect the time it takes
+ packets which were transmitted to arrive
+ to the destination.
+ after this time the RX filters will be removed
+
+
:raises:
+ :exc:`STLTimeoutError` - in case timeout has expired
+ :exe:'STLError'
@@ -1807,14 +1852,19 @@ class STLClient(object):
if time.time() > expr:
raise STLTimeoutError(timeout)
+ # remove any RX filters
+ rc = self._remove_rx_filters(ports, rx_delay_ms = rx_delay_ms)
+ if not rc:
+ raise STLError(rc)
+
@__api_check(True)
def set_port_attr (self, ports = None, promiscuous = None):
"""
- set port(s) attributes
+ Set port attributes
:parameters:
- promiscuous - set this to True or False
+ promiscuous - True or False
:raises:
None
@@ -1845,7 +1895,7 @@ class STLClient(object):
def clear_events (self):
"""
- clear all events
+ Clear all events
:parameters:
None
@@ -1921,7 +1971,7 @@ class STLClient(object):
@__console
def start_line (self, line):
- '''Start selected traffic in specified ports on TRex\n'''
+ '''Start selected traffic on specified ports on TRex\n'''
# define a parser
parser = parsing_opts.gen_parser(self,
"start",
@@ -2008,7 +2058,7 @@ class STLClient(object):
@__console
def stop_line (self, line):
- '''Stop active traffic in specified ports on TRex\n'''
+ '''Stop active traffic on specified ports on TRex\n'''
parser = parsing_opts.gen_parser(self,
"stop",
self.stop_line.__doc__,
@@ -2061,7 +2111,7 @@ class STLClient(object):
@__console
def pause_line (self, line):
- '''Pause active traffic in specified ports on TRex\n'''
+ '''Pause active traffic on specified ports on TRex\n'''
parser = parsing_opts.gen_parser(self,
"pause",
self.pause_line.__doc__,
@@ -2086,7 +2136,7 @@ class STLClient(object):
@__console
def resume_line (self, line):
- '''Resume active traffic in specified ports on TRex\n'''
+ '''Resume active traffic on specified ports on TRex\n'''
parser = parsing_opts.gen_parser(self,
"resume",
self.resume_line.__doc__,
@@ -2130,7 +2180,7 @@ class STLClient(object):
@__console
def show_stats_line (self, line):
- '''Fetch statistics from TRex server by port\n'''
+ '''Get statistics from TRex server by port\n'''
# define a parser
parser = parsing_opts.gen_parser(self,
"stats",
@@ -2161,7 +2211,7 @@ class STLClient(object):
@__console
def show_streams_line(self, line):
- '''Fetch streams statistics from TRex server by port\n'''
+ '''Get stream statistics from TRex server by port\n'''
# define a parser
parser = parsing_opts.gen_parser(self,
"streams",
@@ -2190,7 +2240,7 @@ class STLClient(object):
@__console
def validate_line (self, line):
- '''validates port(s) stream configuration\n'''
+ '''Validates port(s) stream configuration\n'''
parser = parsing_opts.gen_parser(self,
"validate",
@@ -2208,7 +2258,7 @@ class STLClient(object):
@__console
def push_line (self, line):
- '''Push a PCAP file '''
+ '''Push a pcap file '''
parser = parsing_opts.gen_parser(self,
"push",
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_packet_builder_scapy.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_packet_builder_scapy.py
index a7064853..f8517a47 100644..100755
--- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_packet_builder_scapy.py
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_packet_builder_scapy.py
@@ -35,7 +35,7 @@ def safe_ord (c):
elif type(c) is int:
return c
else:
- raise TypeError("cannot convert: {0} of type: {1}".format(c, type(c)))
+ raise TypeError("Cannot convert: {0} of type: {1}".format(c, type(c)))
def _buffer_to_num(str_buffer):
validate_type('str_buffer', str_buffer, bytes)
@@ -48,18 +48,18 @@ def _buffer_to_num(str_buffer):
def ipv4_str_to_num (ipv4_buffer):
validate_type('ipv4_buffer', ipv4_buffer, bytes)
- assert len(ipv4_buffer)==4, 'size of ipv4_buffer is not 4'
+ assert len(ipv4_buffer)==4, 'Size of ipv4_buffer is not 4'
return _buffer_to_num(ipv4_buffer)
def mac_str_to_num (mac_buffer):
validate_type('mac_buffer', mac_buffer, bytes)
- assert len(mac_buffer)==6, 'size of mac_buffer is not 6'
+ assert len(mac_buffer)==6, 'Size of mac_buffer is not 6'
return _buffer_to_num(mac_buffer)
def is_valid_ipv4(ip_addr):
"""
- return buffer in network order
+ Return buffer in network order
"""
if type(ip_addr) == bytes and len(ip_addr) == 4:
return ip_addr
@@ -72,12 +72,12 @@ def is_valid_ipv4(ip_addr):
except AttributeError: # no inet_pton here, sorry
return socket.inet_aton(ip_addr)
except socket.error: # not a valid address
- raise CTRexPacketBuildException(-10,"not valid ipv4 format");
+ raise CTRexPacketBuildException(-10,"Not valid ipv4 format");
def is_valid_ipv6(ipv6_addr):
"""
- return buffer in network order
+ Return buffer in network order
"""
if type(ipv6_addr) == bytes and len(ipv6_addr) == 16:
return ipv6_addr
@@ -107,12 +107,12 @@ class CTRexScFieldRangeBase(CTRexScriptsBase):
self.field_name =field_name
self.field_type =field_type
if not self.field_type in CTRexScFieldRangeBase.FILED_TYPES :
- raise CTRexPacketBuildException(-12, 'field type should be in %s' % FILED_TYPES);
+ raise CTRexPacketBuildException(-12, 'Field type should be in %s' % FILED_TYPES);
class CTRexScFieldRangeValue(CTRexScFieldRangeBase):
"""
- range of field value
+ Range of field values
"""
def __init__(self, field_name,
field_type,
@@ -123,14 +123,14 @@ class CTRexScFieldRangeValue(CTRexScFieldRangeBase):
self.min_value =min_value;
self.max_value =max_value;
if min_value > max_value:
- raise CTRexPacketBuildException(-12, 'min is greater than max');
+ raise CTRexPacketBuildException(-12, 'Invalid range: min is greater than max.');
if min_value == max_value:
- raise CTRexPacketBuildException(-13, "min value is equal to max value, you can't use this type of range");
+ raise CTRexPacketBuildException(-13, "Invalid range: min value is equal to max value.");
class CTRexScIpv4SimpleRange(CTRexScFieldRangeBase):
"""
- range of ipv4 ip
+ Range of ipv4 ip
"""
def __init__(self, field_name, field_type, min_ip, max_ip):
super(CTRexScIpv4SimpleRange, self).__init__(field_name,field_type)
@@ -144,7 +144,7 @@ class CTRexScIpv4SimpleRange(CTRexScFieldRangeBase):
class CTRexScIpv4TupleGen(CTRexScriptsBase):
"""
- range tuple
+ Range tuple
"""
FLAGS_ULIMIT_FLOWS =1
@@ -166,7 +166,7 @@ class CTRexScIpv4TupleGen(CTRexScriptsBase):
class CTRexScTrimPacketSize(CTRexScriptsBase):
"""
- trim packet size. field type is CTRexScFieldRangeBase.FILED_TYPES = ["inc","dec","rand"]
+ Trim packet size. Field type is CTRexScFieldRangeBase.FILED_TYPES = ["inc","dec","rand"]
"""
def __init__(self,field_type="rand",min_pkt_size=None, max_pkt_size=None):
super(CTRexScTrimPacketSize, self).__init__()
@@ -183,11 +183,11 @@ class CTRexScTrimPacketSize(CTRexScriptsBase):
class STLScVmRaw(CTRexScriptsBase):
"""
- raw instructions
+ Raw instructions
"""
def __init__(self,list_of_commands=None,split_by_field=None):
"""
- include a list of a basic instructions objects
+ Include a list of a basic instructions objects.
:parameters:
list_of_commands : list
@@ -197,7 +197,7 @@ class STLScVmRaw(CTRexScriptsBase):
by which field to split to threads
- The following example will split the generated traffic by "ip_src" variable
+ The following example splits the generated traffic by "ip_src" variable.
.. code-block:: python
:caption: Split by
@@ -241,7 +241,7 @@ class STLScVmRaw(CTRexScriptsBase):
class CTRexVmInsBase(object):
"""
- instruction base
+ Instruction base
"""
def __init__(self, ins_type):
self.type = ins_type
@@ -334,7 +334,7 @@ class CTRexVmEngine(object):
def __init__(self):
"""
- inlcude list of instruction
+ Inlcude list of instructions.
"""
super(CTRexVmEngine, self).__init__()
self.ins=[]
@@ -390,7 +390,7 @@ class CTRexScapyPktUtl(object):
def get_pkt_layers(self):
"""
- return string 'IP:UDP:TCP'
+ Return string 'IP:UDP:TCP'
"""
l=self.get_list_iter ();
l1=map(lambda p: p.name,l );
@@ -398,7 +398,7 @@ class CTRexScapyPktUtl(object):
def _layer_offset(self, name, cnt = 0):
"""
- return offset of layer e.g 'IP',1 will return offfset of layer ip:1
+ Return offset of layer. Example: 'IP',1 returns offfset of layer ip:1
"""
save_cnt=cnt
for pkt in self.pkt_iter ():
@@ -413,7 +413,7 @@ class CTRexScapyPktUtl(object):
def layer_offset(self, name, cnt = 0):
"""
- return offset of layer e.g 'IP',1 will return offfset of layer ip:1
+ Return offset of layer. Example: 'IP',1 returns offfset of layer ip:1
"""
save_cnt=cnt
for pkt in self.pkt_iter ():
@@ -427,7 +427,7 @@ class CTRexScapyPktUtl(object):
def get_field_offet(self, layer, layer_cnt, field_name):
"""
- return offset of layer e.g 'IP',1 will return offfset of layer ip:1
+ Return offset of layer. Example: 'IP',1 returns offfset of layer ip:1
"""
t=self._layer_offset(layer,layer_cnt);
l_offset=t[1];
@@ -439,11 +439,11 @@ class CTRexScapyPktUtl(object):
if f.name == field_name:
return (l_offset+f.offset,f.get_size_bytes ());
- raise CTRexPacketBuildException(-11, "no layer %s-%d." % (name, save_cnt, field_name));
+ raise CTRexPacketBuildException(-11, "No layer %s-%d." % (name, save_cnt, field_name));
def get_layer_offet_by_str(self, layer_des):
"""
- return layer offset by string
+ Return layer offset by string.
:parameters:
@@ -469,21 +469,21 @@ class CTRexScapyPktUtl(object):
def get_field_offet_by_str(self, field_des):
"""
- return field_des (offset,size) layer:cnt.field
- for example
+ Return field_des (offset,size) layer:cnt.field
+ Example:
802|1Q.vlan get 802.1Q->valn replace | with .
IP.src
IP:0.src (first IP.src like IP.src)
- for example IP:1.src for internal IP
+ Example: IP:1.src for internal IP
- return (offset, size) as tuple
+ Return (offset, size) as tuple.
"""
s=field_des.split(".");
if len(s)!=2:
- raise CTRexPacketBuildException(-11, ("field desription should be layer:cnt.field e.g IP.src or IP:1.src"));
+ raise CTRexPacketBuildException(-11, ("Field desription should be layer:cnt.field Example: IP.src or IP:1.src"));
layer_ex = s[0].replace("|",".")
@@ -514,7 +514,7 @@ class CTRexScapyPktUtl(object):
class CTRexVmDescBase(object):
"""
- instruction base
+ Instruction base
"""
def __init__(self):
pass;
@@ -534,37 +534,37 @@ class CTRexVmDescBase(object):
def get_var_ref (self):
'''
- virtual function return a ref var name
+ Virtual function returns a ref var name.
'''
return None
def get_var_name(self):
'''
- virtual function return the varible name if exists
+ Virtual function returns the varible name if it exists.
'''
return None
def compile(self,parent):
'''
- virtual function to take parent than has function name_to_offset
+ Virtual function to take parent that has function name_to_offset.
'''
pass;
def valid_fv_size (size):
if not (size in CTRexVmInsFlowVar.VALID_SIZES):
- raise CTRexPacketBuildException(-11,("flow var has not valid size %d ") % size );
+ raise CTRexPacketBuildException(-11,("Flow var has invalid size %d ") % size );
def valid_fv_ops (op):
if not (op in CTRexVmInsFlowVar.OPERATIONS):
- raise CTRexPacketBuildException(-11,("flow var does not have a valid op %s ") % op );
+ raise CTRexPacketBuildException(-11,("Flow var has invalid op %s ") % op );
def convert_val (val):
if is_integer(val):
return val
if type(val) == str:
return ipv4_str_to_num (is_valid_ipv4(val))
- raise CTRexPacketBuildException(-11,("init val not valid %s ") % val );
+ raise CTRexPacketBuildException(-11,("init val invalid %s ") % val );
def check_for_int (val):
validate_type('val', val, int)
@@ -574,31 +574,32 @@ class STLVmFlowVar(CTRexVmDescBase):
def __init__(self, name, init_value=None, min_value=0, max_value=255, size=4, step=1,op="inc"):
"""
- Flow variable instruction. Allocate a variable on a stream context. The size of the variable could be determined
- The operation can be inc, dec and random. In case of increment and decrement operation, it is possible to set the "step" size.
- Initialization value, minimum and maximum value could be set too.
+ Flow variable instruction. Allocates a variable on a stream context. The size argument determines the variable size.
+ The operation can be inc, dec, and random.
+ For increment and decrement operations, can set the "step" size.
+ For all operations, can set initialization value, minimum and maximum value.
:parameters:
name : string
- The name of the stream variable
+ Name of the stream variable
init_value : int
- The init value of the variable. in case of None it will be min_value
+ Init value of the variable. If not specified, it will be min_value
min_value : int
- The min value
+ Min value
max_value : int
- The max value
+ Max value
size : int
- the number of bytes of the variable. could be 1,2,4,8 for uint8_t, uint16_t, uint32_t, uint64_t
+ Number of bytes of the variable. Possible values: 1,2,4,8 for uint8_t, uint16_t, uint32_t, uint64_t
step : int
- step in case of "inc","dec" operation
+ Step in case of "inc" or "dec" operations
op : string
- could be "inc", "dec", "random"
+ Possible values: "inc", "dec", "random"
.. code-block:: python
:caption: Example1
@@ -657,7 +658,7 @@ class STLVmFlowVar(CTRexVmDescBase):
class STLVmFixIpv4(CTRexVmDescBase):
def __init__(self, offset):
"""
- Fix IPv4 header checksum. should be added if the packet header was changed and there is a need to fix he checksum
+ Fix IPv4 header checksum. Use this if the packet header has changed and it is necessary to change the checksum.
:parameters:
offset : uint16_t or string
@@ -694,26 +695,28 @@ class STLVmWrFlowVar(CTRexVmDescBase):
def __init__(self, fv_name, pkt_offset, offset_fixup=0, add_val=0, is_big=True):
"""
Write a stream variable into a packet field.
- The write is done in size of the stream variable.
- In case there is a need to change the write have a look into the command `STLVmWrMaskFlowVar`.
- The Field name/offset can be given by name in this format ``header[:id].field``.
+ The write position is determined by the packet offset + offset fixup. The size of the write is determined by the stream variable.
+ Example: Offset 10, fixup 0, variable size 4. This function writes at 10, 11, 12, and 13.
+
+ For inromation about chaning the write size, offset, or fixup, see the `STLVmWrMaskFlowVar` command.
+ The Field name/offset can be given by name in the following format: ``header[:id].field``.
:parameters:
fv_name : string
- the stream variable to write to a packet offset
+ Stream variable to write to a packet offset.
pkt_offset : string or in
- the name of the field or offset in byte from packet start.
+ Name of the field or offset in bytes from packet start.
offset_fixup : int
- how many bytes to go forward. In case of a negative value go backward
+ Number of bytes to move forward. If negative, move backward.
add_val : int
- value to add to stream variable before writing it to packet field. can be used as a constant offset
+ Value to add to the stream variable before writing it to the packet field. Can be used as a constant offset.
is_big : bool
- how to write the variable to the the packet. is it big-edian or little edian
+ How to write the variable to the the packet. True=big-endian, False=little-endian
.. code-block:: python
:caption: Example3
@@ -759,7 +762,7 @@ class STLVmWrMaskFlowVar(CTRexVmDescBase):
"""
Write a stream variable into a packet field with some operations.
- Using this instruction the variable size and the field could be with different size.
+ Using this instruction, the variable size and the field can have different sizes.
Pseudocode of this code::
@@ -805,7 +808,7 @@ class STLVmWrMaskFlowVar(CTRexVmDescBase):
is_big : bool
how to write the variable to the the packet. is it big-edian or little edian
- Example 1- casting from uint16_t (var) to uint8_t (pkt)::
+ Example 1 - Cast from uint16_t (var) to uint8_t (pkt)::
base_pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)
@@ -824,7 +827,7 @@ class STLVmWrMaskFlowVar(CTRexVmDescBase):
pkt = Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)
- Example 2- change MSB of uint16_t variable::
+ Example 2 - Change MSB of uint16_t variable::
vm = STLScVmRaw( [ STLVmFlowVar(name="mac_src",
@@ -841,7 +844,7 @@ class STLVmWrMaskFlowVar(CTRexVmDescBase):
- Example 3- Every 2 packet change the MAC (shift right)::
+ Example 3 - Every 2 packets, change the MAC (shift right)::
vm = STLScVmRaw( [ STLVmFlowVar(name="mac_src",
min_value=1,
@@ -893,12 +896,12 @@ class STLVmWrMaskFlowVar(CTRexVmDescBase):
class STLVmTrimPktSize(CTRexVmDescBase):
"""
- Trim packet size by stream variable size. This instruction will only change the total packet size and will not fix up the fields to match the new size.
+ Trim the packet size by the stream variable size. This instruction only changes the total packet size, and does not repair the fields to match the new size.
:parameters:
fv_name : string
- the stream variable name. the value from this variable would be the new total packet size.
+ Stream variable name. The value of this variable is the new total packet size.
For Example::
@@ -959,8 +962,8 @@ class STLVmTrimPktSize(CTRexVmDescBase):
class STLVmTupleGen(CTRexVmDescBase):
def __init__(self,name, ip_min="0.0.0.1", ip_max="0.0.0.10", port_min=1025, port_max=65535, limit_flows=100000, flags=0):
"""
- Generate a struct with two varibles. ``var_name.ip`` as uint32_t and ``var_name.port`` as uint16_t
- The variable are dependent. When the ip variable is wrapped the port is getting increment.
+ Generate a struct with two variables: ``var_name.ip`` as uint32_t and ``var_name.port`` as uint16_t
+ The variables are dependent. When the ip variable value reaches its maximum, the port is incremented.
For:
@@ -1001,22 +1004,22 @@ class STLVmTupleGen(CTRexVmDescBase):
:parameters:
name : string
- The name of the stream struct.
+ Name of the stream struct.
ip_min : string or int
- The min value of the ip value. It can be in IPv4 format
+ Min value of the ip value. Number or IPv4 format.
ip_max : string or int
- The max value of the ip value. It can be in IPv4 format
+ Max value of the ip value. Number or IPv4 format.
port_min : int
- min value for port variable
+ Min value of port variable.
port_max : int
- max value for port variable
+ Max value of port variable.
limit_flows : int
- The limit of number of flows
+ Limit of number of flows.
flags : 0
@@ -1093,10 +1096,10 @@ class STLPktBuilder(CTrexPktBuilderInterface):
def __init__(self, pkt = None, pkt_buffer = None, vm = None, path_relative_to_profile = False, build_raw = False, remove_fcs = True):
"""
- This class defines a way to build a template packet, and Field Engine using scapy package.
- Using this class the user can also define how TRex will handle the packet by specifying the Field engine setting.
- pkt could be Scapy pkt or pcap file name
- When path_relative_to_profile is a True load pcap file from a path relative to the profile
+ This class defines a method for building a template packet and Field Engine using the Scapy package.
+ Using this class the user can also define how TRex will handle the packet by specifying the Field engine settings.
+ The pkt can be a Scapy pkt or pcap file name.
+ If using a pcap file, and path_relative_to_profile is True, then the function loads the pcap file from a path relative to the profile.
.. code-block:: python
@@ -1134,22 +1137,22 @@ class STLPktBuilder(CTrexPktBuilderInterface):
:parameters:
pkt : string,
- Scapy or pcap file filename a scapy packet
+ Scapy object or pcap filename.
pkt_buffer : bytes
- a packet as buffer
+ Packet as buffer.
vm : list or base on :class:`trex_stl_lib.trex_stl_packet_builder_scapy.STLScVmRaw`
- a list of instructions to manipolate packet fields
+ List of instructions to manipulate packet fields.
path_relative_to_profile : bool
- in case pkt is pcap file, do we want to load it relative to profile file
+ If pkt is a pcap file, determines whether to load it relative to profile file.
build_raw : bool
- Do we want to build scapy in case buffer was given. good for cases we want offset to be taken from scapy
+ If a buffer is specified (by pkt_buffer), determines whether to build Scapy. Useful in cases where it is necessary to take the offset from Scapy.
remove_fcs : bool
- in case of buffer do we want to remove fcs
+ If a buffer is specified (by pkt_buffer), determines whether to remove FCS.
@@ -1171,7 +1174,7 @@ class STLPktBuilder(CTrexPktBuilderInterface):
if pkt != None and pkt_buffer != None:
- raise CTRexPacketBuildException(-15, "packet builder cannot be provided with both pkt and pkt_buffer")
+ raise CTRexPacketBuildException(-15, "Packet builder cannot be provided with both pkt and pkt_buffer.")
# process packet
if pkt != None:
@@ -1183,7 +1186,7 @@ class STLPktBuilder(CTrexPktBuilderInterface):
# process VM
if vm != None:
if not isinstance(vm, (STLScVmRaw, list)):
- raise CTRexPacketBuildException(-14, "bad value for variable vm")
+ raise CTRexPacketBuildException(-14, "Bad value for variable vm.")
self.add_command(vm if isinstance(vm, STLScVmRaw) else STLScVmRaw(vm))
@@ -1219,7 +1222,7 @@ class STLPktBuilder(CTrexPktBuilderInterface):
def dump_pkt(self, encode = True):
"""
- Dumps the packet as a decimal array of bytes (each item x gets value between 0-255)
+ Dumps the packet as a decimal array of bytes (each item x gets value in range 0-255)
:parameters:
encode : bool
@@ -1254,7 +1257,7 @@ class STLPktBuilder(CTrexPktBuilderInterface):
def pkt_layers_desc (self):
"""
- return layer description like this IP:TCP:Pyload
+ Return layer description in this format: IP:TCP:Pyload
"""
pkt_buf = self._get_pkt_as_str()
@@ -1274,13 +1277,13 @@ class STLPktBuilder(CTrexPktBuilderInterface):
def set_pcap_file (self, pcap_file):
"""
- load raw pcap file into a buffer. load only the first packet
+ Load raw pcap file into a buffer. Loads only the first packet.
:parameters:
pcap_file : file_name
:raises:
- + :exc:`AssertionError`, in case packet is empty.
+ + :exc:`AssertionError`, if packet is empty.
"""
f_path = self._get_pcap_file_path (pcap_file)
@@ -1293,7 +1296,7 @@ class STLPktBuilder(CTrexPktBuilderInterface):
self.pkt_raw = pkt[0]
break
if not was_set :
- raise CTRexPacketBuildException(-14, "no buffer inside the pcap file {0}".format(f_path))
+ raise CTRexPacketBuildException(-14, "No buffer inside the pcap file {0}".format(f_path))
def to_pkt_dump(self):
p = self.pkt
@@ -1312,7 +1315,7 @@ class STLPktBuilder(CTrexPktBuilderInterface):
"""
Scapy packet
- For Example::
+ Example::
pkt =Ether()/IP(src="16.0.0.1",dst="48.0.0.1")/UDP(dport=12,sport=1025)/IP()/('x'*10)
@@ -1401,7 +1404,7 @@ class STLPktBuilder(CTrexPktBuilderInterface):
if var_names :
for var_name in var_names:
if var_name in vars:
- raise CTRexPacketBuildException(-11,("variable %s define twice ") % (var_name) );
+ raise CTRexPacketBuildException(-11,("Variable %s defined twice ") % (var_name) );
else:
vars[var_name]=1
@@ -1410,7 +1413,7 @@ class STLPktBuilder(CTrexPktBuilderInterface):
var_name = desc.get_var_ref()
if var_name :
if not var_name in vars:
- raise CTRexPacketBuildException(-11,("variable %s does not exists ") % (var_name) );
+ raise CTRexPacketBuildException(-11,("Variable %s does not exist ") % (var_name) );
desc.compile(self);
for desc in obj.commands:
@@ -1439,7 +1442,7 @@ class STLPktBuilder(CTrexPktBuilderInterface):
# regular scapy packet
elif not self.pkt:
# should not reach here
- raise CTRexPacketBuildException(-11, 'empty packet')
+ raise CTRexPacketBuildException(-11, 'Empty packet')
if self.remove_fcs and self.pkt.lastlayer().name == 'Padding':
self.pkt.lastlayer().underlayer.remove_payload()
@@ -1469,7 +1472,7 @@ class STLPktBuilder(CTrexPktBuilderInterface):
if self.pkt_raw:
return self.pkt_raw
- raise CTRexPacketBuildException(-11, 'empty packet');
+ raise CTRexPacketBuildException(-11, 'Empty packet');
def _add_tuple_gen(self,tuple_gen):
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 47124114..049929ae 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
@@ -7,8 +7,8 @@ from .trex_stl_types import *
from . import trex_stl_stats
import base64
-import time
import copy
+from datetime import datetime, timedelta
StreamOnPort = namedtuple('StreamOnPort', ['compiled_stream', 'metadata'])
@@ -61,6 +61,8 @@ class Port(object):
self.port_stats = trex_stl_stats.CPortStats(self)
self.next_available_id = 1
+ self.tx_stopped_ts = None
+ self.has_rx_streams = False
def err(self, msg):
@@ -239,6 +241,9 @@ class Port(object):
'rate' : streams_list[i].get_rate()}
ret.add(RC_OK(data = stream_id))
+
+ self.has_rx_streams = self.has_rx_streams or streams_list[i].has_flow_stats()
+
else:
ret.add(RC(*single_rc))
@@ -283,6 +288,9 @@ class Port(object):
self.state = self.STATE_STREAMS if (len(self.streams) > 0) else self.STATE_IDLE
+ # recheck if any RX stats streams present on the port
+ self.has_rx_streams = any([stream.has_flow_stats() for stream in self.streams])
+
return self.ok() if rc else self.err(rc.err())
@@ -305,6 +313,7 @@ class Port(object):
self.streams = {}
self.state = self.STATE_IDLE
+ self.has_rx_streams = False
return self.ok()
@@ -351,7 +360,7 @@ class Port(object):
# stop traffic
# with force ignores the cached state and sends the command
def stop (self, force = False):
-
+
if not self.is_acquired():
return self.err("port is not owned")
@@ -360,7 +369,6 @@ class Port(object):
if (self.state == self.STATE_IDLE) or (self.state == self.state == self.STATE_STREAMS):
return self.ok()
-
params = {"handler": self.handler,
"port_id": self.port_id}
@@ -370,8 +378,56 @@ class Port(object):
self.state = self.STATE_STREAMS
+ # timestamp for last tx
+ self.tx_stopped_ts = datetime.now()
+
+ return self.ok()
+
+
+ # return True if port has any stream configured with RX stats
+ def has_rx_enabled (self):
+ return self.has_rx_streams
+
+
+ # return true if rx_delay_ms has passed since the last port stop
+ def has_rx_delay_expired (self, rx_delay_ms):
+ assert(self.has_rx_enabled())
+
+ # if active - it's not safe to remove RX filters
+ if self.is_active():
+ return False
+
+ # either no timestamp present or time has already passed
+ return not self.tx_stopped_ts or (datetime.now() - self.tx_stopped_ts) > timedelta(milliseconds = rx_delay_ms)
+
+
+
+ def remove_rx_filters (self):
+ assert(self.has_rx_enabled())
+
+ if not self.is_acquired():
+ return self.err("port is not owned")
+
+ if self.state == self.STATE_DOWN:
+ return self.err("Unable to remove RX filters - port is down")
+
+ if self.state == self.STATE_TX:
+ return self.err("Unable to remove RX filters - port is transmitting")
+
+ if self.state == self.STATE_IDLE:
+ return self.ok()
+
+
+ params = {"handler": self.handler,
+ "port_id": self.port_id}
+
+ rc = self.transmit("remove_rx_filters", params)
+ if rc.bad():
+ return self.err(rc.err())
+
return self.ok()
+
def pause (self):
if not self.is_acquired():
@@ -597,6 +653,8 @@ class Port(object):
################# events handler ######################
def async_event_port_job_done (self):
+ # until thread is locked - order is important
+ self.tx_stopped_ts = datetime.now()
self.state = self.STATE_STREAMS
# rest of the events are used for TUI / read only sessions
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 4f8ce3e6..aeeddc49 100644..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
@@ -21,22 +21,22 @@ class STLTXMode(object):
def __init__ (self, pps = None, bps_L1 = None, bps_L2 = None, percentage = None):
"""
- Speed could be in packet per second (pps) or L2/L1 bps or port precent
- only one of them is valid.
+ Speed can be given in packets per second (pps), L2/L1 bps, or port percent
+ Use only one unit.
you can enter pps =10000 oe bps_L1=10
:parameters:
pps : float
- packet per second
+ Packets per second
bps_L1 : float
- bit per second L1 (with IPG)
+ Bits per second L1 (with IPG)
bps_L2 : float
- bit per second L2 (Ethernet-FCS)
+ Bits per second L2 (Ethernet-FCS)
percentage : float
- link interface precent 0-100 e.g. 10 is 10%% of the port link setup
+ Link interface percent (0-100). Example: 10 is 10% of the port link setup
.. code-block:: python
:caption: STLTXMode Example
@@ -95,11 +95,11 @@ class STLTXMode(object):
# continuous mode
class STLTXCont(STLTXMode):
- """ continuous mode """
+ """ Continuous mode """
def __init__ (self, **kwargs):
"""
- continuous mode
+ Continuous mode
see :class:`trex_stl_lib.trex_stl_streams.STLTXMode` for rate
@@ -124,11 +124,11 @@ class STLTXSingleBurst(STLTXMode):
def __init__ (self, total_pkts = 1, **kwargs):
"""
- single burst mode
+ Single burst mode
:parameters:
total_pkts : int
- how many packets for this burst
+ Number of packets for this burst
see :class:`trex_stl_lib.trex_stl_streams.STLTXMode` for rate
@@ -154,7 +154,7 @@ class STLTXSingleBurst(STLTXMode):
# multi burst mode
class STLTXMultiBurst(STLTXMode):
- """ Multi burst mode """
+ """ Multi-burst mode """
def __init__ (self,
pkts_per_burst = 1,
@@ -162,18 +162,18 @@ class STLTXMultiBurst(STLTXMode):
count = 1,
**kwargs):
"""
- Multi burst mode
+ Multi-burst mode
:parameters:
pkts_per_burst: int
- how many packets per burst
+ Number of packets per burst
ibg : float
- inter burst gap in usec 1000,000.0 is 1 sec
+ Inter-burst gap in usec 1,000,000.0 is 1 sec
count : int
- how many bursts
+ Number of bursts
see :class:`trex_stl_lib.trex_stl_streams.STLTXMode` for rate
@@ -230,7 +230,7 @@ class STLFlowStats(object):
def to_json (self):
- """ dump as json"""
+ """ Dump as json"""
return dict(self.fields)
@staticmethod
@@ -238,7 +238,7 @@ class STLFlowStats(object):
return {'enabled' : False}
class STLStream(object):
- """ One stream object, include mode, Field Engine mode packet template and Rx stats
+ """ One stream object. Includes mode, Field Engine mode packet template and Rx stats
.. code-block:: python
:caption: STLStream Example
@@ -277,42 +277,42 @@ class STLStream(object):
:parameters:
name : string
- The name of the stream. Needed if this stream is dependent on another stream and another stream need to refer to this stream by its name.
+ Name of the stream. Required if this stream is dependent on another stream, and another stream needs to refer to this stream by name.
packet : STLPktBuilder see :class:`trex_stl_lib.trex_stl_packet_builder_scapy.STLPktBuilder`
- The template packet and field engine program e.g. packet = STLPktBuilder(pkt = base_pkt/pad)
+ Template packet and field engine program. Example: packet = STLPktBuilder(pkt = base_pkt/pad)
mode : :class:`trex_stl_lib.trex_stl_streams.STLTXCont` or :class:`trex_stl_lib.trex_stl_streams.STLTXSingleBurst` or :class:`trex_stl_lib.trex_stl_streams.STLTXMultiBurst`
enabled : bool
- if the stream is enabled.
+ Indicates whether the stream is enabled.
self_start : bool
- In case it is False another stream will activate it
+ If False, another stream activates it.
isg : float
- Inter stream gap in usec. time to wait until stream will send the first packet
+ Inter-stream gap in usec. Time to wait until the stream sends the first packet.
flow_stats : :class:`trex_stl_lib.trex_stl_streams.STLFlowStats`
- Per stream statistic object see STLFlowStats
+ Per stream statistic object. See: STLFlowStats
next : string
- The name of the stream to activate
+ Name of the stream to activate.
stream_id :
- for HLTAPI usage
+ For use by HLTAPI.
action_count : uint16_t
- In case there is a next stream how many loops until stopping. Default is zero, which mean unlimited
+ If there is a next stream, number of loops before stopping. Default: 0 (unlimited).
random_seed: uint16_t
- If given the seed for this stream will be this value. Good in case you need a deterministic random value
+ If given, the seed for this stream will be this value. Useful if you need a deterministic random value.
mac_src_override_by_pkt : bool
- Template packet will set src MAC
+ Template packet sets src MAC.
mac_dst_override_mode=None : STLStreamDstMAC_xx
- Template packet will set dst MAC
+ Template packet sets dst MAC.
"""
@@ -326,7 +326,7 @@ class STLStream(object):
validate_type('random_seed',random_seed,int);
if (type(mode) == STLTXCont) and (next != None):
- raise STLError("continuous stream cannot have a next stream ID")
+ raise STLError("Continuous stream cannot have a next stream ID")
# tag for the stream and next - can be anything
self.name = name
@@ -412,7 +412,7 @@ class STLStream(object):
def to_json (self):
"""
- return json format
+ Return json format
"""
return dict(self.fields)
@@ -430,6 +430,10 @@ class STLStream(object):
return self.next
+ def has_flow_stats (self):
+ """ Return True if stream was configured with flow stats """
+ return self.fields['flow_stats']['enabled']
+
def get_pkt (self):
""" Get packet as string """
return self.pkt
@@ -444,7 +448,7 @@ class STLStream(object):
def get_pkt_type (self):
- """ Get packet description for example IP:UDP """
+ """ Get packet description. Example: IP:UDP """
if self.packet_desc == None:
self.packet_desc = STLPktBuilder.pkt_layers_desc_from_buffer(self.get_pkt())
@@ -472,7 +476,7 @@ class STLStream(object):
return self.get_rate_from_field(self.fields['mode']['rate'])
def to_pkt_dump (self):
- """ print packet description from scapy """
+ """ Print packet description from Scapy """
if self.name:
print("Stream Name: ",self.name)
scapy_b = self.scapy_pkt_builder;
@@ -484,7 +488,7 @@ class STLStream(object):
def to_yaml (self):
- """ convert to YAML """
+ """ Convert to YAML """
y = {}
if self.name:
@@ -506,7 +510,7 @@ class STLStream(object):
# returns the Python code (text) to build this stream, inside the code it will be in variable "stream"
def to_code (self):
- """ convert to Python code as profile """
+ """ Convert to Python code as profile """
packet = Ether(self.pkt)
layer = packet
while layer: # remove checksums
@@ -621,7 +625,7 @@ class STLStream(object):
return r'\x{0:02x}'.format(ord(match.group()))
def dump_to_yaml (self, yaml_file = None):
- """ print as yaml """
+ """ Print as yaml """
yaml_dump = yaml.dump([self.to_yaml()], default_flow_style = False)
# write to file if provided
@@ -642,7 +646,7 @@ class YAMLLoader(object):
packet_type = set(packet_dict).intersection(['binary', 'pcap'])
if len(packet_type) != 1:
- raise STLError("packet section must contain either 'binary' or 'pcap'")
+ raise STLError("Packet section must contain either 'binary' or 'pcap'")
if 'binary' in packet_type:
try:
@@ -707,7 +711,7 @@ class YAMLLoader(object):
pg_id = flow_stats_obj.get('stream_id')
if pg_id == None:
- raise STLError("enabled RX stats section must contain 'stream_id' field")
+ raise STLError("Enabled RX stats section must contain 'stream_id' field")
return STLFlowStats(pg_id = pg_id)
@@ -822,16 +826,21 @@ class STLProfile(object):
def get_streams (self):
- """ Get the list of stream"""
+ """ Get the list of streams"""
return self.streams
def __str__ (self):
return '\n'.join([str(stream) for stream in self.streams])
+ def is_pauseable (self):
+ return all([x.get_mode() == "Continuous" for x in (self.get_streams())])
+
+ def has_flow_stats (self):
+ return any([x.has_flow_stats() for x in self.get_streams()])
@staticmethod
def load_yaml (yaml_file):
- """ load from YAML file a profile with number of streams"""
+ """ Load (from YAML file) a profile with a number of streams"""
# check filename
if not os.path.isfile(yaml_file):
@@ -866,11 +875,11 @@ class STLProfile(object):
@staticmethod
def load_py (python_file, direction = 0, port_id = 0, **kwargs):
- """ load from Python profile """
+ """ Load from Python profile """
# check filename
if not os.path.isfile(python_file):
- raise STLError("file '{0}' does not exists".format(python_file))
+ raise STLError("File '{0}' does not exist".format(python_file))
basedir = os.path.dirname(python_file)
sys.path.append(basedir)
@@ -883,7 +892,7 @@ class STLProfile(object):
t = STLProfile.get_module_tunables(module)
for arg in kwargs:
if not arg in t:
- raise STLError("profile {0} does not support tunable '{1}' - supported tunables are: '{2}'".format(python_file, arg, t))
+ raise STLError("Profile {0} does not support tunable '{1}' - supported tunables are: '{2}'".format(python_file, arg, t))
streams = module.register().get_streams(direction = direction,
port_id = port_id,
@@ -910,26 +919,26 @@ class STLProfile(object):
# loop_count = 0 means loop forever
@staticmethod
def load_pcap (pcap_file, ipg_usec = None, speedup = 1.0, loop_count = 1, vm = None):
- """ Convert a pcap file with a number of packets to a list of connected streams
+ """ Convert a pcap file with a number of packets to a list of connected streams.
packet1->packet2->packet3 etc
:parameters:
pcap_file : string
- The name of the pcap file
+ Name of the pcap file
ipg_usec : float
- The inter packet gap in usec. in case of None IPG is taken from pcap file
+ Inter packet gap in usec. If IPG=0, IPG is taken from pcap file
speedup : float
- By which factor to get IPG smaller so we will send pcap file in speedup
+ When reading the pcap file, divide IPG by this "speedup" factor. Resulting IPG is sped up by this factor.
loop_count : uint16_t
- how many loops to repeat the pcap file
+ Number of loops to repeat the pcap file
vm : list
- A list of Field engine instructions
+ List of Field engine instructions
:return: STLProfile
@@ -987,12 +996,12 @@ class STLProfile(object):
@staticmethod
def load (filename, direction = 0, port_id = 0, **kwargs):
- """ load a profile by its type supported type are
+ """ Load a profile by its type. Supported types are:
* py
* yaml
* pcap file that converted to profile automaticly
- :parameters:
+ :Parameters:
filename : string as filename
direction : profile's direction (if supported by the profile)
port_id : which port ID this profile is being loaded to
@@ -1024,7 +1033,7 @@ class STLProfile(object):
return profile.meta
def dump_as_pkt (self):
- """ dump the profile as scapy packet. in case it is raw convert to scapy and dump it"""
+ """ Dump the profile as Scapy packet. If the packet is raw, convert it to Scapy before dumping it."""
cnt=0;
for stream in self.streams:
print("=======================")
@@ -1034,7 +1043,7 @@ class STLProfile(object):
stream.to_pkt_dump()
def dump_to_yaml (self, yaml_file = None):
- """ convert it to yaml """
+ """ Convert the profile to yaml """
yaml_list = [stream.to_yaml() for stream in self.streams]
yaml_str = yaml.dump(yaml_list, default_flow_style = False)
@@ -1046,7 +1055,7 @@ class STLProfile(object):
return yaml_str
def dump_to_code (self, profile_file = None):
- """ convert it to Python native profile. yeah this is cool """
+ """ Convert the profile to Python native profile. """
profile_dump = '''# !!! Auto-generated code !!!
from trex_stl_lib.api import *
diff --git a/scripts/stl/flow_stats.py b/scripts/stl/flow_stats.py
index 69e1166c..cbb5ac21 100644
--- a/scripts/stl/flow_stats.py
+++ b/scripts/stl/flow_stats.py
@@ -1,15 +1,17 @@
from trex_stl_lib.api import *
+import os
# stream from pcap file. continues pps 10 in sec
+CP = os.path.join(os.path.dirname(__file__))
class STLS1(object):
def get_streams (self, direction = 0, **kwargs):
- return [STLStream(packet = STLPktBuilder(pkt ="stl/yaml/udp_64B_no_crc.pcap"), # path relative to pwd
+ return [STLStream(packet = STLPktBuilder(pkt = os.path.join(CP, "yaml/udp_64B_no_crc.pcap")), # path relative to pwd
mode = STLTXCont(pps=1000),
flow_stats = STLFlowStats(pg_id = 7)),
- STLStream(packet = STLPktBuilder(pkt ="stl/yaml/udp_594B_no_crc.pcap"), # path relative to pwd
+ STLStream(packet = STLPktBuilder(pkt = os.path.join(CP, "yaml/udp_594B_no_crc.pcap")), # path relative to pwd
mode = STLTXCont(pps=5000),
flow_stats = STLFlowStats(pg_id = 12))
]
diff --git a/scripts/stl/udp_1pkt_pcap.py b/scripts/stl/udp_1pkt_pcap.py
index 9fb0e269..2a364810 100644
--- a/scripts/stl/udp_1pkt_pcap.py
+++ b/scripts/stl/udp_1pkt_pcap.py
@@ -1,11 +1,14 @@
from trex_stl_lib.api import *
+import os
# stream from pcap file. continues pps 10 in sec
+CP = os.path.join(os.path.dirname(__file__))
+
class STLS1(object):
def get_streams (self, direction = 0, **kwargs):
- return [STLStream(packet = STLPktBuilder(pkt ="stl/yaml/udp_64B_no_crc.pcap"), # path relative to pwd
+ return [STLStream(packet = STLPktBuilder(pkt = os.path.join(CP, "yaml/udp_64B_no_crc.pcap")),
mode = STLTXCont(pps=10)) ] #rate continues, could be STLTXSingleBurst,STLTXMultiBurst
diff --git a/scripts/stl/udp_3pkt_pcap.py b/scripts/stl/udp_3pkt_pcap.py
index fd2c609e..19ff46bc 100644
--- a/scripts/stl/udp_3pkt_pcap.py
+++ b/scripts/stl/udp_3pkt_pcap.py
@@ -1,26 +1,29 @@
from trex_stl_lib.api import *
+import os
# stream from pcap file. continues pps 10 in sec
+CP = os.path.join(os.path.dirname(__file__))
+
class STLS1(object):
def create_stream (self):
return STLProfile( [ STLStream( isg = 10.0, # star in delay
name ='S0',
- packet = STLPktBuilder(pkt ="stl/yaml/udp_64B_no_crc.pcap"),
+ packet = STLPktBuilder(pkt = os.path.join(CP, "yaml/udp_64B_no_crc.pcap")),
mode = STLTXSingleBurst( pps = 10, total_pkts = 10),
next = 'S1'), # point to next stream
STLStream( self_start = False, # stream is disabled enable trow S0
name ='S1',
- packet = STLPktBuilder(pkt ="stl/yaml/udp_594B_no_crc.pcap"),
+ packet = STLPktBuilder(pkt = os.path.join(CP, "yaml/udp_594B_no_crc.pcap")),
mode = STLTXSingleBurst( pps = 10, total_pkts = 20),
next = 'S2' ),
STLStream( self_start = False, # stream is disabled enable trow S0
name ='S2',
- packet = STLPktBuilder(pkt ="stl/yaml/udp_1518B_no_crc.pcap"),
+ packet = STLPktBuilder(pkt = os.path.join(CP, "yaml/udp_1518B_no_crc.pcap")),
mode = STLTXSingleBurst( pps = 10, total_pkts = 30 )
)
]).get_streams()
diff --git a/scripts/stl/yaml/imix_1pkt_vm_minus.yaml b/scripts/stl/yaml/imix_1pkt_vm_minus.yaml
index e83cfdd0..6d5345df 100644
--- a/scripts/stl/yaml/imix_1pkt_vm_minus.yaml
+++ b/scripts/stl/yaml/imix_1pkt_vm_minus.yaml
@@ -18,7 +18,8 @@
"min_value" : 1000,
"name" : "l3_src",
"op" : "inc",
- "size" : 2,
+ "step": 1,
+ "size" : 4,
"type" : "flow_var"
},
{