NFVBENCH-187: Augment --l2-loopback command line option capabilities 28/71328/5
authorPierrick Louin <pierrick.louin@orange.com>
Sun, 8 Nov 2020 21:31:41 +0000 (22:31 +0100)
committerPierrick Louin <pierrick.louin@orange.com>
Mon, 9 Nov 2020 09:37:30 +0000 (10:37 +0100)
[vlan(s)|no-tag|true|false] - Update documentation
Clarify some fuzzy coding in options processing [nfvbench.py]

Change-Id: Ie6eec7722bfa557924f435f268b852c300e160df
Signed-off-by: Pierrick Louin <pierrick.louin@orange.com>
docs/testing/user/userguide/advanced.rst
docs/testing/user/userguide/faq.rst
docs/testing/user/userguide/readme.rst
nfvbench/cfg.default.yaml
nfvbench/chain_runner.py
nfvbench/credentials.py
nfvbench/nfvbench.py
nfvbench/traffic_gen/trex_gen.py
nfvbench/traffic_server.py

index d7dc53f..2bd88cf 100644 (file)
@@ -598,6 +598,66 @@ Used parameters:
 * ``--unidir`` : run traffic with unidirectional flow (default to bidirectional flow)
 
 
+.. _adv-l2l-cli:
+
+L2 loopback test via CLI
+------------------------
+
+The CLI allows running a pure L2 loopback benchmark with the ``--l2-loopback`` option.
+Enabling this mode overrides any service chain type selected in the config file.
+The usual argument would be a single VLAN ID but the syntax has been extended.
+
+Examples of runs:
+
+* specify the vlan ID
+
+  .. code-block:: bash
+  
+    nfvbench -c nfvbench.cfg --frame-size=64 --rate=100% --duration=10 --l2-loopback=123
+    
+* specify a list of vlan IDs
+  
+  Several service chains are created, the count is adjusted to the list size.
+
+  .. code-block:: bash
+  
+    nfvbench -c nfvbench.cfg -fs=64 --rate=100% --duration=10 --l2-loopback=123,124,125
+    
+* enable the mode without VLAN tagging
+
+  In this case the service chain count is forced to 1.
+  
+  .. code-block:: bash
+  
+    nfvbench -c nfvbench.cfg -fs=64 --rate=100% --duration=10 --l2-loopback=no-tag
+    
+* use different VLAN tags for left & right side ports
+
+  .. code-block:: bash
+  
+    nfvbench -c nfvbench.cfg -fs=64 --rate=100% --duration=10 --l2-loopback=111_211
+    nfvbench -c nfvbench.cfg -fs=64 --rate=100% --duration=10 --l2-loopback=111,112_211,212
+
+  .. note::
+    It may look bizarre to specify mismatched VLAN tags for left & right sides,
+    however no assumption is made about the loop implementation.
+    This could help testing some exotic L2 layer configuration comprising a VLAN rewriting.
+
+* enable the mode, starting from current settings (prepared in the cfg file)
+
+  In this case the service chain count is not adjusted.
+
+  .. code-block:: bash
+  
+    nfvbench -c nfvbench.cfg -fs=64 --rate=100% --duration=10 --l2-loopback=true
+    
+* disable the mode (possibly enabled in the cfg file)
+
+  .. code-block:: bash
+  
+    nfvbench -c nfvbench.cfg --l2-loopback=false
+
+
 MAC Addresses
 -------------
 
index a8aad9a..014a1ab 100644 (file)
@@ -46,7 +46,7 @@ The most common issues that prevent traffic from passing are:
 - incorrect vlan_tagging setting in the NFVbench configuration, this needs to match how the NFVbench ports on the switch are configured (trunk or access port)
 
    - if the switch port is configured as access port, you must disable vlan_tagging in the NFVbench configuration
-   - of the switch port is configured as trunk (recommended method), you must enable it
+   - if the switch port is configured as trunk (recommended method), you must enable it
 
 Issues with high performances at a high line rate
 -------------------------------------------------
index 50175c3..f6cc153 100644 (file)
@@ -78,15 +78,22 @@ NFVbench supports settings that involve externally staged packet paths with or w
 
 Direct L2 Loopback (Switch or wire loopback)
 --------------------------------------------
-NFVbench supports benchmarking of pure L2 loopbacks (see "--l2-loopback vlan" option)
+NFVbench supports benchmarking of pure L2 loopbacks
 
 - Switch level loopback
 - Port to port wire loopback
 
-In this mode, NFVbench will take a vlan ID and send packets from each port to the other port
-(dest MAC set to the other port MAC) using the same VLAN ID on both ports.
+In this mode, NFVbench will send packets from each port to the other port
+(the destination MAC address is set to the other port MAC address).
 This can be useful for example to verify that the connectivity to the switch is working properly.
 
+Such a test can be quickly run using the CLI ``--l2-loopback`` :ref:`option <adv-l2l-cli>`.
+
+For a typical test, packets will be VLAN tagged with the same ID on both ports.
+However, multiple L2 vlan tagged service chains are also allowed,
+which permits testing various configurations and the behavior of the bench itself.
+
+
 Traffic Generation
 ------------------
 
index 26df919..4491097 100644 (file)
@@ -60,7 +60,7 @@ flavor:
   # Size of local disk in GB
   disk: 0
   # metadata are supported and can be added if needed, optional
-  # note that if your openstack does not have NUMA optimization
+  # note that if your OpenStack does not have NUMA optimization
   # (cpu pinning and huge pages)
   # you must comment out extra_specs completely otherwise
   # loopback VM creation will fail
@@ -79,7 +79,7 @@ flavor:
 # When multiqueue is used the recommended setting is to set it to same value as the
 # number of vCPU used - up to a max of 8 queues.
 # Setting to a lower value than vCPU should also work. For example if using 4 vCPU and
-# vif_multiqueue_size is set to 2, openstack will create 4 queues per interface but the
+# vif_multiqueue_size is set to 2, OpenStack will create 4 queues per interface but the
 # test VM will only use the first 2 queues.
 vif_multiqueue_size: 1
 
@@ -95,7 +95,7 @@ num_mbufs: 16384
 availability_zone:
 # To force placement on a given hypervisor, set the name here
 # (if multiple names are provided, the first will be used)
-# Leave empty to let openstack pick the hypervisor
+# Leave empty to let OpenStack pick the hypervisor
 compute_nodes:
 # If openrc is not admin set a valid value for hypervisor hostname
 # Example of value: hypervisor_hostname: "server1"
@@ -128,10 +128,16 @@ flow_count: 10000
 sriov: false
 
 # Perform port to port loopback (direct or through switch)
-# Should be used with EXT service chain and no ARP (no_arp: true)
-# When enabled, the vlans property must contain the same VLAN id for all chains.
-# Can be overriden by --l2-loopback
+# e.g. for unitary testing of the switch or the bench itself.
+# When selected, this mode forces EXT service chain and no ARP mode
+# Destination MAC for each port is set to the other (peer) port MAC.
+# VLAN tagging is defined by 'vlans' & 'vlan_tagging' properties.
+# Can be overriden by --l2-loopback (including vlan tagging spec).
 l2_loopback: false
+# No assumption is made about the loop implementation.
+# Multiple L2 vlan tagged service chains are allowed,
+# the vlan ID lists' size must be at least service_chain_count.
+# If not vlan tagging, the service chain count is forced to 1.
 
 # Resources created by NFVbench will not be removed
 # Can be overriden by --no-cleanup
@@ -390,7 +396,7 @@ generic_poll_sec: 2
 # name of the loop VM
 loop_vm_name: 'nfvbench-loop-vm'
 
-# Default names, subnets and CIDRs for PVP/PVVP networks (openstack only)
+# Default names, subnets and CIDRs for PVP/PVVP networks (OpenStack only)
 #
 # If a network with given name already exists it will be reused.
 # - PVP only uses left and right
@@ -673,19 +679,21 @@ mpls: false
 # is not supported). Use the vtep_vlan option to enable vlan tagging for the VxLAN overlay network.
 vlan_tagging: true
 
-# Used only in the case of EXT chain and no openstack or not admin access to specify the VLAN IDs to use.
-# This property is ignored when OpenStakc is used or in the case of l2-loopback.
+# Used only in the case of EXT chain and no OpenStack or not admin access to specify the VLAN IDs to use.
+# This property is ignored when OpenStack is used or when 'vlan_tagging' is disabled.
 # If OpenStack is used leave the list empty, VLAN IDs are retrieved from OpenStack networks using Neutron API.
 # If networks are shared across all chains (service_chain_shared_net=true), the list should have exactly 2 values
 # If networks are not shared across chains (service_chain_shared_net=false), the list should have
 # 2 list of vlan IDs
-# In the special case of l2-loopback the list should have the same VLAN id for all chains
 # Examples:
 #   [1998, 1999] left network uses vlan 1998 right network uses vlan 1999
 #   [[1,2],[3,4]] chain 0 left vlan 1, right vlan 2 - chain 1 left vlan 3 right vlan 4
-#   [1010, 1010] same VLAN id with l2-loopback enabled
-#
+#   [1010, 1010] same vlan ID on both sides, for a typical l2-loopback test (*)
+# The vlan lists may be oversized, compared to the actual service chain count
+# (lowest indexes are used) but an exception is raised if they are too short.
 vlans: []
+# (*) actually there is no restriction, left/right IDs may differ
+#     for some exotic purpose - see also the l2_loopback parameter.
 
 # ARP is used to discover the MAC address of VNFs that run L3 routing.
 # Used only with EXT chain.
@@ -725,7 +733,7 @@ traffic:
 # Can be overriden by --no-traffic
 no_traffic: false
 
-# Use an L3 router in the packet path. This option if set will create or reuse an openstack neutron
+# Use an L3 router in the packet path. This option if set will create or reuse an OpenStack neutron
 # router (PVP, PVVP) or reuse an existing L3 router (EXT) to route traffic to the destination VM.
 # Can be overriden by --l3-router
 l3_router: false
index ae9ccff..7b1153f 100644 (file)
@@ -71,6 +71,8 @@ class ChainRunner(object):
             # VLAN is discovered from the networks
             gen_config.set_vlans(0, self.chain_manager.get_chain_vlans(0))
             gen_config.set_vlans(1, self.chain_manager.get_chain_vlans(1))
+        else:
+            LOG.info("Ports: untagged")
 
         # the only case we do not need to set the dest MAC is in the case of
         # l2-loopback (because the traffic gen will default to use the peer MAC)
index d9a67e6..4e4985f 100644 (file)
@@ -176,7 +176,7 @@ class Credentials(object):
             # Return HTTP 200 if user is admin
             self.get_session().get('/users', endpoint_filter=filter)
             self.is_admin = True
-        except Exception as e:
+        except Exception:
             try:
                 # vX/users URL returns exception (HTTP 403) if user is not admin.
                 self.get_session().get('/v' + str(self.rc_identity_api_version) + '/users',
index 19c402f..427c94c 100644 (file)
@@ -199,12 +199,23 @@ class NFVBench(object):
         config.service_chain = config.service_chain.upper()
         config.service_chain_count = int(config.service_chain_count)
         if config.l2_loopback:
-            # force the number of chains to be 1 in case of l2 loopback
-            config.service_chain_count = 1
+            # force the number of chains to be 1 in case of untagged l2 loopback
+            # (on the other hand, multiple L2 vlan tagged service chains are allowed)
+            if not config.vlan_tagging:
+                config.service_chain_count = 1
             config.service_chain = ChainType.EXT
             config.no_arp = True
             LOG.info('Running L2 loopback: using EXT chain/no ARP')
 
+        # allow oversized vlan lists, just clip them
+        try:
+            vlans = [list(v) for v in config.vlans]
+            for v in vlans:
+                del v[config.service_chain_count:]
+            config.vlans = vlans
+        except Exception:
+            pass
+
         # traffic profile override options
         if 'frame_sizes' in opts:
             unidir = False
@@ -498,16 +509,20 @@ def _parse_opts_from_cli():
 
     parser.add_argument('--l2-loopback', '--l2loopback', dest='l2_loopback',
                         action='store',
-                        metavar='<vlan>',
-                        help='Port to port or port to switch to port L2 loopback with VLAN id')
+                        metavar='<vlan(s)|no-tag|true|false>',
+                        help='Port to port or port to switch to port L2 loopback '
+                             'tagged with given VLAN id(s) or not (given \'no-tag\') '
+                             '\'true\': use current vlans; \'false\': disable this mode.')
 
     parser.add_argument('--user-info', dest='user_info',
-                        action='store',
+                        action='append',
                         metavar='<data>',
-                        help='Custom data to be included as is in the json report config branch - '
-                               + ' example, pay attention! no space: '
-                               + '--user-info=\'{"status":"explore","description":'
-                               + '{"target":"lab","ok":true,"version":2020}}\'')
+                        help='Custom data to be included as is '
+                             'in the json report config branch - '
+                             ' example, pay attention! no space: '
+                             '--user-info=\'{"status":"explore","description":'
+                             '{"target":"lab","ok":true,"version":2020}}\' - '
+                             'this option may be repeated; given data will be merged.')
 
     parser.add_argument('--vlan-tagging', dest='vlan_tagging',
                         type=bool_arg,
@@ -521,7 +536,7 @@ def _parse_opts_from_cli():
                         action='store',
                         default=None,
                         help='Override the NFVbench \'intf_speed\' '
-                                + 'parameter (e.g. 10Gbps, auto, 16.72Gbps)')
+                             'parameter (e.g. 10Gbps, auto, 16.72Gbps)')
 
     parser.add_argument('--cores', dest='cores',
                         type=int_arg,
@@ -534,32 +549,32 @@ def _parse_opts_from_cli():
                         type=int_arg,
                         metavar='<size>',
                         action='store',
-                        default='0',
+                        default=None,
                         help='Specify the FE cache size (default: 0, flow-count if < 0)')
 
     parser.add_argument('--service-mode', dest='service_mode',
                         action='store_true',
-                        default=False,
+                        default=None,
                         help='Enable T-Rex service mode (for debugging purpose)')
 
     parser.add_argument('--no-e2e-check', dest='no_e2e_check',
                         action='store_true',
-                        default=False,
+                        default=None,
                         help='Skip "end to end" connectivity check (on test purpose)')
 
     parser.add_argument('--no-flow-stats', dest='no_flow_stats',
                         action='store_true',
-                        default=False,
+                        default=None,
                         help='Disable additional flow stats (on high load traffic)')
 
     parser.add_argument('--no-latency-stats', dest='no_latency_stats',
                         action='store_true',
-                        default=False,
+                        default=None,
                         help='Disable flow stats for latency traffic')
 
     parser.add_argument('--no-latency-streams', dest='no_latency_streams',
                         action='store_true',
-                        default=False,
+                        default=None,
                         help='Disable latency measurements (no streams)')
 
     parser.add_argument('--user-id', dest='user_id',
@@ -580,16 +595,16 @@ def _parse_opts_from_cli():
                         default=None,
                         action='store_true',
                         help='Show the current TRex local server log file contents'
-                               + ' => diagnostic/help in case of configuration problems')
+                             ' => diagnostic/help in case of configuration problems')
 
     parser.add_argument('--debug-mask', dest='debug_mask',
                         type=int_arg,
                         metavar='<mask>',
                         action='store',
-                        default='0x00000000',
+                        default=None,
                         help='General purpose register (debugging flags), '
-                                + 'the hexadecimal notation (0x...) is accepted.'
-                                + 'Designed for development needs.')
+                             'the hexadecimal notation (0x...) is accepted.'
+                             'Designed for development needs (default: 0).')
 
     opts, unknown_opts = parser.parse_known_args()
     return opts, unknown_opts
@@ -724,65 +739,125 @@ def main():
                 LOG.addHandler(fluent_logger)
                 break
 
-        # convert 'user_info' opt from json string to dictionnary
-        # and merge the result with the current config dictionnary
-        if opts.user_info:
-            opts.user_info = json.loads(opts.user_info)
-            if config.user_info:
-                config.user_info = config.user_info + opts.user_info
-            else:
-                config.user_info = opts.user_info
-            # hide the option to further _update_config()
-            opts.user_info = None
-
         # traffic profile override options
         override_custom_traffic(config, opts.frame_sizes, opts.unidir)
 
-        # copy over cli options that are used in config
+        # Copy over some of the cli options that are used in config.
+        # This explicit copy is sometimes necessary
+        # because some early evaluation depends on them
+        # and cannot wait for _update_config() coming further.
+        # It is good practice then to set them to None (<=> done)
+        # and even required if a specific conversion is performed here
+        # that would be corrupted by a default update (simple copy).
+        # On the other hand, some excessive assignments have been removed
+        # from here, since the _update_config() procedure does them well.
+
         config.generator_profile = opts.generator_profile
-        if opts.sriov:
+        if opts.sriov is not None:
             config.sriov = True
-        if opts.log_file:
+            opts.sriov = None
+        if opts.log_file is not None:
             config.log_file = opts.log_file
-        if opts.service_chain:
+            opts.log_file = None
+        if opts.user_id is not None:
+            config.user_id = opts.user_id
+            opts.user_id = None
+        if opts.group_id is not None:
+            config.group_id = opts.group_id
+            opts.group_id = None
+        if opts.service_chain is not None:
             config.service_chain = opts.service_chain
-        if opts.service_chain_count:
-            config.service_chain_count = opts.service_chain_count
-        if opts.no_vswitch_access:
-            config.no_vswitch_access = opts.no_vswitch_access
-        if opts.hypervisor:
+            opts.service_chain = None
+        if opts.hypervisor is not None:
             # can be any of 'comp1', 'nova:', 'nova:comp1'
             config.compute_nodes = opts.hypervisor
-        if opts.vxlan:
-            config.vxlan = True
-        if opts.mpls:
-            config.mpls = True
-        if opts.restart:
-            config.restart = True
-        if opts.service_mode:
-            config.service_mode = True
-        if opts.no_flow_stats:
-            config.no_flow_stats = True
-        if opts.no_latency_stats:
-            config.no_latency_stats = True
-        if opts.no_latency_streams:
-            config.no_latency_streams = True
-        # port to port loopback (direct or through switch)
-        if opts.l2_loopback:
-            config.l2_loopback = True
-            if config.service_chain != ChainType.EXT:
-                LOG.info('Changing service chain type to EXT')
-                config.service_chain = ChainType.EXT
-            if not config.no_arp:
-                LOG.info('Disabling ARP')
-                config.no_arp = True
-            config.vlans = [int(opts.l2_loopback), int(opts.l2_loopback)]
-            LOG.info('Running L2 loopback: using EXT chain/no ARP')
+            opts.hypervisor = None
+        if opts.debug_mask is not None:
+            config.debug_mask = opts.debug_mask
+            opts.debug_mask = None
 
-        if opts.use_sriov_middle_net:
-            if (not config.sriov) or (config.service_chain != ChainType.PVVP):
-                raise Exception("--use-sriov-middle-net is only valid for PVVP with SRIOV")
-            config.use_sriov_middle_net = True
+        # convert 'user_info' opt from json string to dictionnary
+        # and merge the result with the current config dictionnary
+        if opts.user_info is not None:
+            for user_info_json in opts.user_info:
+                user_info_dict = json.loads(user_info_json)
+                if config.user_info:
+                    config.user_info = config.user_info + user_info_dict
+                else:
+                    config.user_info = user_info_dict
+            opts.user_info = None
+
+        # port to port loopback (direct or through switch)
+        # we accept the following syntaxes for the CLI argument
+        #   'false'   : mode not enabled
+        #   'true'    : mode enabled with currently defined vlan IDs
+        #   'no-tag'  : mode enabled with no vlan tagging
+        #   <vlan IDs>: mode enabled using the given (pair of) vlan ID lists
+        #     - If present, a '_' char will separate left an right ports lists
+        #         e.g. 'a_x'         => vlans: [[a],[x]]
+        #              'a,b,c_x,y,z' =>        [[a,b,c],[x,y,z]]
+        #     - Otherwise the given vlan ID list applies to both sides
+        #         e.g. 'a'           => vlans: [[a],[a]]
+        #              'a,b'         =>        [[a,b],[a,b]]
+        #     - Vlan lists size needs to be at least the actual SCC value
+        #     - Unless overriden in CLI opts, config.service_chain_count
+        #       is adjusted to the size of the VLAN ID lists given here.
+
+        if opts.l2_loopback is not None:
+            arg_pair = opts.l2_loopback.lower().split('_')
+            if arg_pair[0] == 'false':
+                config.l2_loopback = False
+            else:
+                config.l2_loopback = True
+                if config.service_chain != ChainType.EXT:
+                    LOG.info('Changing service chain type to EXT')
+                    config.service_chain = ChainType.EXT
+                if not config.no_arp:
+                    LOG.info('Disabling ARP')
+                    config.no_arp = True
+                if arg_pair[0] == 'true':
+                    pass
+                else:
+                    # here explicit (not)tagging is not CLI overridable
+                    opts.vlan_tagging = None
+                    if arg_pair[0] == 'no-tag':
+                        config.vlan_tagging = False
+                    else:
+                        config.vlan_tagging = True
+                        if len(arg_pair) == 1 or not arg_pair[1]:
+                            arg_pair = [arg_pair[0], arg_pair[0]]
+                        vlans = [[], []]
+
+                        def append_vlan(port, vlan_id):
+                            # a vlan tag value must be in [0..4095]
+                            if vlan_id not in range(0, 4096):
+                                raise ValueError
+                            vlans[port].append(vlan_id)
+                        try:
+                            for port in [0, 1]:
+                                vlan_ids = arg_pair[port].split(',')
+                                for vlan_id in vlan_ids:
+                                    append_vlan(port, int(vlan_id))
+                            if len(vlans[0]) != len(vlans[1]):
+                                raise ValueError
+                        except ValueError:
+                            # at least one invalid tag => no tagging
+                            config.vlan_tagging = False
+                        if config.vlan_tagging:
+                            config.vlans = vlans
+                            # force service chain count if not CLI overriden
+                            if opts.service_chain_count is None:
+                                config.service_chain_count = len(vlans[0])
+            opts.l2_loopback = None
+
+        if config.use_sriov_middle_net is None:
+            config.use_sriov_middle_net = False
+        if opts.use_sriov_middle_net is not None:
+            config.use_sriov_middle_net = opts.use_sriov_middle_net
+            opts.use_sriov_middle_net = None
+        if (config.use_sriov_middle_net and (
+                (not config.sriov) or (config.service_chain != ChainType.PVVP))):
+            raise Exception("--use-sriov-middle-net is only valid for PVVP with SRIOV")
 
         if config.sriov and config.service_chain != ChainType.EXT:
             # if sriov is requested (does not apply to ext chains)
index 4e20f73..21e79ae 100644 (file)
@@ -589,8 +589,6 @@ class TRex(AbstractTrafficGenerator):
         """
         streams = []
         pg_id, lat_pg_id = self.get_pg_id(port, chain_id)
-        if self.config.no_flow_stats:
-            LOG.info("Traffic flow statistics are disabled.")
         if l2frame == 'IMIX':
             for ratio, l2_frame_size in zip(IMIX_RATIOS, IMIX_L2_SIZES):
                 pkt = self._create_pkt(stream_cfg, l2_frame_size)
@@ -602,12 +600,12 @@ class TRex(AbstractTrafficGenerator):
                         streams.append(STLStream(packet=pkt,
                                                  flow_stats=STLFlowStats(pg_id=pg_id,
                                                                          vxlan=True)
-                                                 if not self.config.no_flow_stats else None,
+                                                    if not self.config.no_flow_stats else None,
                                                  mode=STLTXCont(pps=ratio)))
                     else:
                         streams.append(STLStream(packet=pkt,
                                                  flow_stats=STLFlowStats(pg_id=pg_id)
-                                                 if not self.config.no_flow_stats else None,
+                                                    if not self.config.no_flow_stats else None,
                                                  mode=STLTXCont(pps=ratio)))
 
             if latency:
@@ -633,12 +631,12 @@ class TRex(AbstractTrafficGenerator):
                     streams.append(STLStream(packet=pkt,
                                              flow_stats=STLFlowStats(pg_id=pg_id,
                                                                      vxlan=True)
-                                             if not self.config.no_flow_stats else None,
+                                                if not self.config.no_flow_stats else None,
                                              mode=STLTXCont()))
                 else:
                     streams.append(STLStream(packet=pkt,
                                              flow_stats=STLFlowStats(pg_id=pg_id)
-                                             if not self.config.no_flow_stats else None,
+                                                if not self.config.no_flow_stats else None,
                                              mode=STLTXCont()))
             # for the latency stream, the minimum payload is 16 bytes even in case of vlan tagging
             # without vlan, the min l2 frame size is 64
@@ -662,12 +660,12 @@ class TRex(AbstractTrafficGenerator):
                 streams.append(STLStream(packet=pkt,
                                          flow_stats=STLFlowLatencyStats(pg_id=lat_pg_id,
                                                                         vxlan=True)
-                                         if not self.config.no_latency_stats else None,
+                                            if not self.config.no_latency_stats else None,
                                          mode=STLTXCont(pps=self.LATENCY_PPS)))
             else:
                 streams.append(STLStream(packet=pkt,
                                          flow_stats=STLFlowLatencyStats(pg_id=lat_pg_id)
-                                         if not self.config.no_latency_stats else None,
+                                            if not self.config.no_latency_stats else None,
                                          mode=STLTXCont(pps=self.LATENCY_PPS)))
         return streams
 
@@ -1005,6 +1003,8 @@ class TRex(AbstractTrafficGenerator):
         latency: True if latency measurement is needed
         e2e: True if performing "end to end" connectivity check
         """
+        if self.config.no_flow_stats:
+            LOG.info("Traffic flow statistics are disabled.")
         r = self.__is_rate_enough(l2frame_size, rates, bidirectional, latency)
         if not r['result']:
             raise TrafficGeneratorException(
index bc79204..6074a6e 100644 (file)
@@ -108,8 +108,8 @@ class TRexTrafficServer(TrafficServer):
                                          prefix=generator_config.name,
                                          limit_memory=generator_config.limit_memory,
                                          nb_cores=generator_config.cores,
-                                         use_vlan=generator_config.gen_config.get('vtep_vlan')
-                                         or generator_config.vlan_tagging,
+                                         use_vlan=generator_config.gen_config.get('vtep_vlan') or
+                                         generator_config.vlan_tagging,
                                          ifs=ifs)
 
         if hasattr(generator_config, 'mbuf_64') and generator_config.mbuf_64: