From 3f0fe318257a7d1c73a17081302946cdc4e69c00 Mon Sep 17 00:00:00 2001
From: Christian Trautman <ctrautma@redhat.com>
Date: Tue, 6 Feb 2018 13:57:42 -0500
Subject: Trex_speed_improvement: Add logic for dealing with high speed cards

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>
---
 tools/pkt_gen/trex/trex.py | 53 ++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 49 insertions(+), 4 deletions(-)

(limited to 'tools')

diff --git a/tools/pkt_gen/trex/trex.py b/tools/pkt_gen/trex/trex.py
index cfe54b78..e0ce4c48 100644
--- a/tools/pkt_gen/trex/trex.py
+++ b/tools/pkt_gen/trex/trex.py
@@ -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(
-- 
cgit