Trex_speed_improvement: Add logic for dealing with high speed cards 79/51779/11
authorChristian Trautman <ctrautma@redhat.com>
Tue, 6 Feb 2018 18:57:42 +0000 (13:57 -0500)
committerChristian Trautman <ctrautma@redhat.com>
Fri, 23 Feb 2018 13:47:25 +0000 (08:47 -0500)
Adds configuration options and logic to detect maximum supported
speed of T-Rex server side cards.

1. Adds logic to pull maximum supported speed from port info
2. Adds forcable option to have user specify maximum speed
3. If logic cannot detect speed from port_info because it is
   not available or the forcable option is not set it will
   assume 10G speeds.
4. Tested on Intel XXV25G and Mellanox ConnectX-5 cards
5. Added packet structure logging to show packet info for
   better debugging capabilities
6. Adds core mask to take advantage of multiple cores if
   server is started with more than default number of cores
7. Adds packets lost logging to RFC2544 Throughput testing

JIRA: VSPERF-559

Change-Id: I7fcfda7ccc408c30830950ee3668e01b8624c20a
Signed-off-by: Christian Trautman <ctrautma@redhat.com>
conf/03_traffic.conf
conf/10_custom.conf
docs/testing/user/configguide/trafficgen.rst
tools/pkt_gen/trex/trex.py

index 6731889..8aff2e3 100644 (file)
@@ -487,6 +487,11 @@ TRAFFICGEN_TREX_LEARNING_MODE = True
 TRAFFICGEN_TREX_LEARNING_DURATION = 5
 # FOR SR-IOV or multistream layer 2 tests to work with T-Rex enable Promiscuous mode
 TRAFFICGEN_TREX_PROMISCUOUS = False
+# Enable below options to force T-rex api to attempt to use speed specified on server
+# side when pushing traffic. For 40G use 40000. For 25G use 25000.
+TRAFFICGEN_TREX_FORCE_PORT_SPEED = False
+TRAFFICGEN_TREX_PORT_SPEED = 10000 # 10G
+
 PATHS['trafficgen'] = {
     'Trex': {
         'type' : 'src',
index 917d16b..0e274aa 100644 (file)
@@ -138,6 +138,10 @@ TRAFFICGEN_TREX_LEARNING_MODE = True
 TRAFFICGEN_TREX_LEARNING_DURATION = 5
 # FOR SR-IOV or multistream layer 2 tests to work with T-Rex enable Promiscuous mode
 TRAFFICGEN_TREX_PROMISCUOUS = False
+# Enable below options to force T-rex api to attempt to use speed specified on server
+# side when pushing traffic. For 40G use 40000. For 25G use 25000.
+TRAFFICGEN_TREX_FORCE_PORT_SPEED = False
+TRAFFICGEN_TREX_PORT_SPEED = 10000 # 10G
 # TRex validation option for RFC2544
 TRAFFICGEN_TREX_VERIFICATION_MODE = False
 TRAFFICGEN_TREX_VERIFICATION_DURATION = 60
index 3382448..061d3d7 100644 (file)
@@ -795,6 +795,13 @@ It is neccesary for proper connection between Trex server and VSPERF.
 Firewall must allow a connection from DUT (VSPERF) to the T-Rex server running
 at TCP port 4501.
 
+**NOTE:** For high speed cards it may be advantageous to start T-Rex with more transmit queues/cores.
+
+.. code-block:: console
+
+   cd trex-cores/scripts/
+   ./t-rex-64 -i -c 10
+
 For additional information about Trex stateless mode see Trex stateless documentation:
 
 https://trex-tgn.cisco.com/trex/doc/trex_stateless.html
@@ -862,6 +869,22 @@ modified. Enable Promiscuous mode when doing multistream at layer 2 testing with
 
     TRAFFICGEN_TREX_PROMISCUOUS=True
 
+Card Bandwidth Options
+~~~~~~~~~~~~~~~~~~~~~~
+
+T-Rex API will attempt to retrieve the highest possible speed from the card using internal
+calls to port information. If you are using two separate cards then it will take the lowest
+of the two cards as the max speed. If necessary you can try to force the API to use a
+specific maximum speed per port. The below configurations can be adjusted to enable this.
+
+.. code-block:: console
+
+    TRAFFICGEN_TREX_FORCE_PORT_SPEED = True
+    TRAFFICGEN_TREX_PORT_SPEED = 40000 # 40 gig
+
+**Note::** Setting higher than possible speeds will result in unpredictable behavior when running
+tests such as duration inaccuracy and/or complete test failure.
+
 RFC2544 Validation
 ~~~~~~~~~~~~~~~~~~
 
index cfe54b7..e0ce4c4 100644 (file)
@@ -33,6 +33,7 @@ try:
     # pylint: disable=wrong-import-position, import-error
     sys.path.append(settings.getValue('PATHS')['trafficgen']['Trex']['src']['path'])
     from trex_stl_lib.api import *
+    from trex_stl_lib import trex_stl_exceptions
 except ImportError:
     # VSPERF performs detection of T-Rex api during testcase initialization. So if
     # T-Rex is requsted and API is not available it will fail before this code
@@ -68,6 +69,7 @@ _EMPTY_STATS = {
               'tx_pps': 0.0,
               'tx_util': 0.0,}}
 
+
 class Trex(ITrafficGenerator):
     """Trex Traffic generator wrapper."""
     _logger = logging.getLogger(__name__)
@@ -84,6 +86,20 @@ class Trex(ITrafficGenerator):
         self._trex_user = settings.getValue('TRAFFICGEN_TREX_USER')
         self._stlclient = None
         self._verification_params = None
+        self._show_packet_data = False
+
+    def show_packet_info(self, packet_a, packet_b):
+        """
+        Log packet layers to screen
+        :param packet_a: Scapy.layers packet
+        :param packet_b: Scapy.layers packet
+        :return: None
+        """
+        # we only want to show packet data once per test
+        if self._show_packet_data:
+            self._show_packet_data = False
+            self._logger.info(packet_a.show())
+            self._logger.info(packet_b.show())
 
     def connect(self):
         '''Connect to Trex traffic generator
@@ -262,11 +278,29 @@ class Trex(ITrafficGenerator):
         self._stlclient.set_service_mode(ports=my_ports, enabled=False)
 
         ports_info = self._stlclient.get_port_info(my_ports)
+
+        # get max support speed
+        max_speed = 0
+        if settings.getValue('TRAFFICGEN_TREX_FORCE_PORT_SPEED'):
+            max_speed = settings.getValue('TRAFFICGEN_TREX_PORT_SPEED')
+        elif ports_info[0]['supp_speeds']:
+            max_speed_1 = max(ports_info[0]['supp_speeds'])
+            max_speed_2 = max(ports_info[1]['supp_speeds'])
+        else:
+            # if max supported speed not in port info or set manually, just assume 10G
+            max_speed = 10000
+        if not max_speed:
+            # since we can only control both ports at once take the lower of the two
+            max_speed = min(max_speed_1, max_speed_2)
+        gbps_speed = (max_speed / 1000) * (float(traffic['frame_rate']) / 100.0)
+        self._logger.debug('Starting traffic at %s Gpbs speed', gbps_speed)
+
         # for SR-IOV
         if settings.getValue('TRAFFICGEN_TREX_PROMISCUOUS'):
             self._stlclient.set_port_attr(my_ports, promiscuous=True)
 
         packet_1, packet_2 = Trex.create_packets(traffic, ports_info)
+        self.show_packet_info(packet_1, packet_2)
         stream_1, stream_2, stream_1_lat, stream_2_lat = Trex.create_streams(packet_1, packet_2, traffic)
         self._stlclient.add_streams(stream_1, ports=[0])
         self._stlclient.add_streams(stream_2, ports=[1])
@@ -289,7 +323,13 @@ class Trex(ITrafficGenerator):
                     pcap_id[pcap_dir] = self._stlclient.start_capture(**capture)
 
         self._stlclient.clear_stats()
-        self._stlclient.start(ports=my_ports, force=True, duration=duration)
+        # if the user did not start up T-Rex server with more than default cores, use default mask.
+        # Otherwise use mask to take advantage of multiple cores.
+        try:
+            self._stlclient.start(ports=my_ports, force=True, duration=duration, mult="{}gbps".format(gbps_speed),
+                                  core_mask=self._stlclient.CORE_MASK_PIN)
+        except STLError:
+            self._stlclient.start(ports=my_ports, force=True, duration=duration, mult="{}gbps".format(gbps_speed))
         self._stlclient.wait_on_traffic(ports=my_ports)
         stats = self._stlclient.get_stats(sync_now=True)
 
@@ -414,9 +454,11 @@ class Trex(ITrafficGenerator):
                 if test_lossrate <= lossrate:
                     # save the last passing trial for verification
                     self._verification_params = copy.deepcopy(new_params)
-            self._logger.debug("Iteration: %s, frame rate: %s, throughput_rx_fps: %s, frame_loss_percent: %s",
-                               iteration, "{:.3f}".format(new_params['frame_rate']), stats['total']['rx_pps'],
-                               "{:.3f}".format(test_lossrate))
+            packets_lost = stats['total']['opackets'] - stats['total']['ipackets']
+            self._logger.debug("Iteration: %s, frame rate: %s, throughput_rx_fps: %s," +
+                               " frames lost %s, frame_loss_percent: %s", iteration,
+                               "{:.3f}".format(new_params['frame_rate']), stats['total']['rx_pps'],
+                               packets_lost, "{:.3f}".format(test_lossrate))
             if test_lossrate == 0.0 and new_params['frame_rate'] == traffic['frame_rate']:
                 return copy.deepcopy(stats)
             elif test_lossrate > lossrate:
@@ -439,6 +481,8 @@ class Trex(ITrafficGenerator):
         self._logger.info("In Trex send_cont_traffic method")
         self._params.clear()
 
+        self._show_packet_data = True
+
         self._params['traffic'] = self.traffic_defaults.copy()
         if traffic:
             self._params['traffic'] = merge_spec(
@@ -467,6 +511,7 @@ class Trex(ITrafficGenerator):
         """
         self._logger.info("In Trex send_rfc2544_throughput method")
         self._params.clear()
+        self._show_packet_data = True
         self._params['traffic'] = self.traffic_defaults.copy()
         if traffic:
             self._params['traffic'] = merge_spec(