NFVBENCH-177: Add a config item 'user_info' and theoretical max rate value
[nfvbench.git] / nfvbench / traffic_gen / traffic_base.py
index 568fae2..df28772 100644 (file)
 #    under the License.
 
 import abc
+import sys
+
+import bitmath
 
 from nfvbench.log import LOG
-import traffic_utils
+from . import traffic_utils
 
 
-class TrafficGeneratorException(Exception):
-    pass
+class Latency(object):
+    """A class to hold latency data."""
 
+    def __init__(self, latency_list=None):
+        """Create a latency instance.
 
-class AbstractTrafficGenerator(object):
-    # src_mac (6) + dst_mac (6) + mac_type (2) + frame_check (4) = 18
-    l2_header_size = 18
+        latency_list: aggregate all latency values from list if not None
+        """
+        self.min_usec = sys.maxsize
+        self.max_usec = 0
+        self.avg_usec = 0
+        self.hdrh = None
+        if latency_list:
+            for lat in latency_list:
+                if lat.available():
+                    self.min_usec = min(self.min_usec, lat.min_usec)
+                    self.max_usec = max(self.max_usec, lat.max_usec)
+                    self.avg_usec += lat.avg_usec
+            # round to nearest usec
+            self.avg_usec = int(round(float(self.avg_usec) / len(latency_list)))
 
-    imix_l2_sizes = [64, 594, 1518]
-    imix_l3_sizes = [size - l2_header_size for size in imix_l2_sizes]
-    imix_ratios = [7, 4, 1]
+    def available(self):
+        """Return True if latency information is available."""
+        return self.min_usec != sys.maxsize
 
-    imix_avg_l2_size = sum(
-        [1.0 * imix[0] * imix[1] for imix in zip(imix_l2_sizes, imix_ratios)]) / sum(imix_ratios)
 
-    traffic_utils.imix_avg_l2_sizes = imix_avg_l2_size
+class TrafficGeneratorException(Exception):
+    """Exception for traffic generator."""
 
-    def __init__(self, config):
-        self.config = config
+class AbstractTrafficGenerator(object):
 
-    @abc.abstractmethod
-    def get_version(self):
-        # Must be implemented by sub classes
-        return None
+    def __init__(self, traffic_client):
+        self.traffic_client = traffic_client
+        self.generator_config = traffic_client.generator_config
+        self.config = traffic_client.config
 
     @abc.abstractmethod
-    def init(self):
+    def get_version(self):
         # Must be implemented by sub classes
         return None
 
@@ -54,32 +68,23 @@ class AbstractTrafficGenerator(object):
         return None
 
     @abc.abstractmethod
-    def config_interface(self):
-        # Must be implemented by sub classes
-        return None
-
-    @abc.abstractmethod
-    def create_traffic(self):
+    def create_traffic(self, l2frame_size, rates, bidirectional, latency=True, e2e=False):
         # Must be implemented by sub classes
         return None
 
     def modify_rate(self, rate, reverse):
+        """Change the rate per port.
+
+        rate: new rate in % (0 to 100)
+        reverse: 0 for port 0, 1 for port 1
+        """
         port_index = int(reverse)
         port = self.port_handle[port_index]
         self.rates[port_index] = traffic_utils.to_rate_str(rate)
-        LOG.info('Modified traffic stream for %s, new rate=%s.', port,
-                 traffic_utils.to_rate_str(rate))
-
-    def modify_traffic(self):
-        # Must be implemented by sub classes
-        return None
+        LOG.info('Modified traffic stream for port %s, new rate=%s.', port, self.rates[port_index])
 
     @abc.abstractmethod
-    def get_stats(self):
-        # Must be implemented by sub classes
-        return None
-
-    def clear_traffic(self):
+    def get_stats(self, ifstats):
         # Must be implemented by sub classes
         return None
 
@@ -95,5 +100,60 @@ class AbstractTrafficGenerator(object):
 
     @abc.abstractmethod
     def cleanup(self):
-        # Must be implemented by sub classes
+        """Cleanup the traffic generator."""
         return None
+
+    def clear_streamblock(self):
+        """Clear all streams from the traffic generator."""
+
+    @abc.abstractmethod
+    def resolve_arp(self):
+        """Resolve all configured remote IP addresses.
+
+        return: None if ARP failed to resolve for all IP addresses
+                else a dict of list of dest macs indexed by port#
+                the dest macs in the list are indexed by the chain id
+        """
+
+    @abc.abstractmethod
+    def get_macs(self):
+        """Return the local port MAC addresses.
+
+        return: a list of MAC addresses indexed by the port#
+        """
+
+    @abc.abstractmethod
+    def get_port_speed_gbps(self):
+        """Return the local port speeds.
+
+        return: a list of speed in Gbps indexed by the port#
+        """
+
+    def get_theoretical_rates(self, avg_packet_size):
+
+        result = {}
+
+        intf_speeds = self.get_port_speed_gbps()
+        tg_if_speed = bitmath.parse_string(str(intf_speeds[0]) + 'Gb').bits
+        intf_speed = tg_if_speed
+
+        if hasattr(self.config, 'intf_speed') and self.config.intf_speed is not None:
+            # in case of limitation due to config, TG speed is not accurate
+            # value is overridden by conf
+            if self.config.intf_speed != tg_if_speed:
+                intf_speed = bitmath.parse_string(self.config.intf_speed.replace('ps', '')).bits
+
+        if hasattr(self.config, 'user_info') and self.config.user_info is not None:
+            if "extra_encapsulation_bytes" in self.config.user_info:
+                frame_size_full_encapsulation = avg_packet_size + self.config.user_info[
+                    "extra_encapsulation_bytes"]
+                result['theoretical_tx_rate_pps'] = traffic_utils.bps_to_pps(
+                    intf_speed, frame_size_full_encapsulation) * 2
+                result['theoretical_tx_rate_bps'] = traffic_utils.pps_to_bps(
+                    result['theoretical_tx_rate_pps'], avg_packet_size)
+        else:
+            result['theoretical_tx_rate_pps'] = traffic_utils.bps_to_pps(intf_speed,
+                                                                         avg_packet_size) * 2
+            result['theoretical_tx_rate_bps'] = traffic_utils.pps_to_bps(
+                result['theoretical_tx_rate_pps'], avg_packet_size)
+        return result