NFVBENCH-33 STLError exception when the packet path drops all packets
[nfvbench.git] / nfvbench / traffic_client.py
index 8bfcd76..2a42b87 100644 (file)
@@ -25,6 +25,8 @@ from stats_collector import IterationCollector
 import struct
 import time
 import traffic_gen.traffic_utils as utils
+from trex_stl_lib.api import STLError
+from utils import cast_integer
 
 
 class TrafficClientException(Exception):
@@ -84,7 +86,8 @@ class Device(object):
 
     def __init__(self, port, pci, switch_port=None, vtep_vlan=None, ip=None, tg_gateway_ip=None,
                  gateway_ip=None, ip_addrs_step=None, tg_gateway_ip_addrs_step=None,
-                 gateway_ip_addrs_step=None, chain_count=1, flow_count=1, vlan_tagging=False):
+                 gateway_ip_addrs_step=None, udp_src_port=None, udp_dst_port=None,
+                 chain_count=1, flow_count=1, vlan_tagging=False):
         self.chain_count = chain_count
         self.flow_count = flow_count
         self.dst = None
@@ -111,6 +114,8 @@ class Device(object):
         self.tg_gateway_ip_list = self.expand_ip(self.tg_gateway_ip,
                                                  self.tg_gateway_ip_addrs_step,
                                                  self.chain_count)
+        self.udp_src_port = udp_src_port
+        self.udp_dst_port = udp_dst_port
 
     def set_mac(self, mac):
         if mac is None:
@@ -151,6 +156,8 @@ class Device(object):
                 'ip_dst_addr_max': self.dst.ip_list[max_idx],
                 'ip_dst_count': ip_dst_count,
                 'ip_addrs_step': self.ip_addrs_step,
+                'udp_src_port': self.udp_src_port,
+                'udp_dst_port': self.udp_dst_port,
                 'mac_discovery_gw': self.gateway_ip_list[chain_idx],
                 'ip_src_tg_gw': self.tg_gateway_ip_list[chain_idx],
                 'ip_dst_tg_gw': self.dst.tg_gateway_ip_list[chain_idx],
@@ -253,6 +260,8 @@ class RunningTrafficProfile(object):
             'gateway_ip_addrs_step': self.gateway_ip_addrs_step,
             'tg_gateway_ip': generator_config.tg_gateway_ip_addrs[0],
             'tg_gateway_ip_addrs_step': self.tg_gateway_ip_addrs_step,
+            'udp_src_port': generator_config.udp_src_port,
+            'udp_dst_port': generator_config.udp_dst_port,
             'vlan_tagging': self.vlan_tagging
         }
         dst_config = {
@@ -264,6 +273,8 @@ class RunningTrafficProfile(object):
             'gateway_ip_addrs_step': self.gateway_ip_addrs_step,
             'tg_gateway_ip': generator_config.tg_gateway_ip_addrs[1],
             'tg_gateway_ip_addrs_step': self.tg_gateway_ip_addrs_step,
+            'udp_src_port': generator_config.udp_src_port,
+            'udp_dst_port': generator_config.udp_dst_port,
             'vlan_tagging': self.vlan_tagging
         }
 
@@ -410,12 +421,13 @@ class TrafficClient(object):
 
         # ensures enough traffic is coming back
         threshold = (self.config.service_chain_count - 1) / float(self.config.service_chain_count)
-
-        for it in xrange(self.config.generic_retry_count):
+        retry_count = (self.config.check_traffic_time_sec +
+                       self.config.generic_poll_sec - 1) / self.config.generic_poll_sec
+        for it in xrange(retry_count):
             self.gen.clear_stats()
             self.gen.start_traffic()
             LOG.info('Waiting for packets to be received back... ({} / {})'.format(it + 1,
-                     self.config.generic_retry_count))
+                     retry_count))
             time.sleep(self.config.generic_poll_sec)
             self.gen.stop_traffic()
             stats = self.gen.get_stats()
@@ -528,9 +540,12 @@ class TrafficClient(object):
                     retDict[port]['rx'][key] = int(stats[port]['rx'][key])
                 except ValueError:
                     retDict[port]['rx'][key] = 0
-            retDict[port]['rx']['avg_delay_usec'] = float(stats[port]['rx']['avg_delay_usec'])
-            retDict[port]['rx']['min_delay_usec'] = float(stats[port]['rx']['min_delay_usec'])
-            retDict[port]['rx']['max_delay_usec'] = float(stats[port]['rx']['max_delay_usec'])
+            retDict[port]['rx']['avg_delay_usec'] = cast_integer(
+                stats[port]['rx']['avg_delay_usec'])
+            retDict[port]['rx']['min_delay_usec'] = cast_integer(
+                stats[port]['rx']['min_delay_usec'])
+            retDict[port]['rx']['max_delay_usec'] = cast_integer(
+                stats[port]['rx']['max_delay_usec'])
             retDict[port]['drop_rate_percent'] = self.__get_dropped_rate(retDict[port])
 
         ports = sorted(retDict.keys())
@@ -600,7 +615,8 @@ class TrafficClient(object):
                 indicating the rate to send on each interface
         right   the right side of the range to search as a % of line rate
                 indicating the rate to send on each interface
-        targets a dict of drop rates to search (0.1 = 0.1%), indexed by the DR name or "tag" ('ndr', 'pdr')
+        targets a dict of drop rates to search (0.1 = 0.1%), indexed by the DR name or "tag"
+                ('ndr', 'pdr')
         results a dict to store results
         '''
         if len(targets) == 0:
@@ -614,8 +630,12 @@ class TrafficClient(object):
 
         # Obtain the average drop rate in for middle load
         middle = (left + right) / 2.0
-        stats, rates = self.__run_search_iteration(middle)
-
+        try:
+            stats, rates = self.__run_search_iteration(middle)
+        except STLError:
+            LOG.exception("Got exception from traffic generator during binary search")
+            self.__targets_found(left, targets, results)
+            return
         # Split target dicts based on the avg drop rate
         left_targets = {}
         right_targets = {}
@@ -630,6 +650,21 @@ class TrafficClient(object):
                 })
                 right_targets[tag] = target
             else:
+                # initialize to 0 all fields of result for
+                # the worst case scenario of the binary search (if ndr/pdr is not found)
+                if tag not in results:
+                    results[tag] = dict.fromkeys(rates, 0)
+                    empty_stats = self.__format_output_stats(dict(stats))
+                    for key in empty_stats:
+                        if isinstance(empty_stats[key], dict):
+                            empty_stats[key] = dict.fromkeys(empty_stats[key], 0)
+                        else:
+                            empty_stats[key] = 0
+                    results[tag].update({
+                        'load_percent_per_direction': 0,
+                        'stats': empty_stats,
+                        'timestamp_sec': None
+                    })
                 left_targets[tag] = target
 
         # search lower half
@@ -727,7 +762,7 @@ class TrafficClient(object):
         config['direction-total'] = dict(config['direction-forward'])
         config['direction-total'].update({
             'rate_percent': load_total,
-            'rate_pps': pps_total,
+            'rate_pps': cast_integer(pps_total),
             'rate_bps': bps_total
         })