MPLS support + loop_vm_arp test fix
[nfvbench.git] / nfvbench / chain_runner.py
index c120501..62a3751 100644 (file)
@@ -23,11 +23,11 @@ The ChainRunner class is in charge of coordinating:
 
 from collections import OrderedDict
 
-from chaining import ChainManager
-from log import LOG
-from specs import ChainType
-from stats_manager import StatsManager
-from traffic_client import TrafficClient
+from .chaining import ChainManager
+from .log import LOG
+from .specs import ChainType
+from .stats_manager import StatsManager
+from .traffic_client import TrafficClient
 
 
 class ChainRunner(object):
@@ -74,11 +74,44 @@ class ChainRunner(object):
 
         # 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)
-        # or EXT+ARP (because dest MAC will be discovered by TRex ARP)
-        if not config.l2_loopback and (config.service_chain != ChainType.EXT or config.no_arp):
+        # or EXT+ARP+VLAN (because dest MAC will be discovered by TRex ARP)
+        # Note that in the case of EXT+ARP+VxLAN, the dest MACs need to be loaded
+        # because ARP only operates on the dest VTEP IP not on the VM dest MAC
+        if not config.l2_loopback and \
+                (config.service_chain != ChainType.EXT or config.no_arp or config.vxlan):
             gen_config.set_dest_macs(0, self.chain_manager.get_dest_macs(0))
             gen_config.set_dest_macs(1, self.chain_manager.get_dest_macs(1))
 
+        if config.vxlan:
+            # VXLAN is discovered from the networks
+            vtep_vlan = gen_config.gen_config.vtep_vlan
+            src_vteps = gen_config.gen_config.src_vteps
+            dst_vtep = gen_config.gen_config.dst_vtep
+            gen_config.set_vxlans(0, self.chain_manager.get_chain_vxlans(0))
+            gen_config.set_vxlans(1, self.chain_manager.get_chain_vxlans(1))
+            gen_config.set_vtep_vlan(0, vtep_vlan)
+            gen_config.set_vtep_vlan(1, vtep_vlan)
+            # Configuring source an remote VTEPs on TREx interfaces
+            gen_config.set_vxlan_endpoints(0, src_vteps[0], dst_vtep)
+            gen_config.set_vxlan_endpoints(1, src_vteps[1], dst_vtep)
+            self.config['vxlan_gen_config'] = gen_config
+
+        if config.mpls:
+            # MPLS VPN is discovered from the networks
+            src_vteps = gen_config.gen_config.src_vteps
+            vtep_gateway_ips = gen_config.gen_config.vtep_gateway_ips
+            gen_config.set_mpls_inner_labels(0, self.chain_manager.get_chain_mpls_inner_labels(0))
+            gen_config.set_mpls_inner_labels(1, self.chain_manager.get_chain_mpls_inner_labels(1))
+            outer_mpls_labels_left = self.config.internal_networks.left.mpls_transport_labels
+            outer_mpls_labels_right = self.config.internal_networks.right.mpls_transport_labels
+            if outer_mpls_labels_left or outer_mpls_labels_right:
+                gen_config.set_mpls_outer_labels(0, outer_mpls_labels_left)
+                gen_config.set_mpls_outer_labels(1, outer_mpls_labels_right)
+            # Configuring source an remote VTEPs on TREx interfaces
+            gen_config.set_mpls_peers(0, src_vteps[0], vtep_gateway_ips[0])
+            gen_config.set_mpls_peers(1, src_vteps[1], vtep_gateway_ips[1])
+            self.config['mpls_gen_config'] = gen_config
+
         # get an instance of the stats manager
         self.stats_manager = StatsManager(self)
         LOG.info('ChainRunner initialized')
@@ -86,17 +119,20 @@ class ChainRunner(object):
     def __setup_traffic(self):
         self.traffic_client.setup()
         if not self.config.no_traffic:
-            if self.config.service_chain == ChainType.EXT and not self.config.no_arp:
+            # ARP is needed for EXT chain or VxLAN overlay or MPLS unless disabled explicitly
+            if (self.config.service_chain == ChainType.EXT or self.config.mpls or
+                    self.config.vxlan or self.config.l3_router or self.config.loop_vm_arp)\
+                    and not self.config.no_arp:
                 self.traffic_client.ensure_arp_successful()
             self.traffic_client.ensure_end_to_end()
 
-    def __get_result_per_frame_size(self, frame_size, actual_frame_size, bidirectional):
+    def __get_result_per_frame_size(self, frame_size, bidirectional):
         traffic_result = {
             frame_size: {}
         }
         result = {}
         if not self.config.no_traffic:
-            self.traffic_client.set_traffic(actual_frame_size, bidirectional)
+            self.traffic_client.set_traffic(frame_size, bidirectional)
 
             if self.config.single_run:
                 result = self.stats_manager.run_fixed_rate()
@@ -105,9 +141,6 @@ class ChainRunner(object):
 
                 for dr in ['pdr', 'ndr']:
                     if dr in results:
-                        if frame_size != actual_frame_size:
-                            results[dr]['l2frame_size'] = frame_size
-                            results[dr]['actual_l2frame_size'] = actual_frame_size
                         traffic_result[frame_size][dr] = results[dr]
                         if 'warning' in results[dr]['stats'] and results[dr]['stats']['warning']:
                             traffic_result['warning'] = results[dr]['stats']['warning']
@@ -117,8 +150,6 @@ class ChainRunner(object):
                 result['run_config'] = self.traffic_client.get_run_config(result)
                 required = result['run_config']['direction-total']['orig']['rate_pps']
                 actual = result['stats']['total_tx_rate']
-                if frame_size != actual_frame_size:
-                    result['actual_l2frame_size'] = actual_frame_size
                 warning = self.traffic_client.compare_tx_rates(required, actual)
                 if warning is not None:
                     result['run_config']['warning'] = warning
@@ -128,9 +159,8 @@ class ChainRunner(object):
 
     def __get_chain_result(self):
         result = OrderedDict()
-        for fs, actual_fs in zip(self.config.frame_sizes, self.config.actual_frame_sizes):
+        for fs in self.config.frame_sizes:
             result.update(self.__get_result_per_frame_size(fs,
-                                                           actual_fs,
                                                            self.config.traffic.bidirectional))
         chain_result = {
             'flow_count': self.config.flow_count,
@@ -152,10 +182,11 @@ class ChainRunner(object):
             return results
 
         LOG.info('Starting %dx%s benchmark...', self.config.service_chain_count, self.chain_name)
-        self.__setup_traffic()
-        # now that the dest MAC for all VNFs is known in all cases, it is time to create
-        # workers as they might be needed to extract stats prior to sending traffic
         self.stats_manager.create_worker()
+        if self.config.vxlan or self.config.mpls:
+            # Configure vxlan or mpls tunnels
+            self.stats_manager.worker.config_interfaces()
+        self.__setup_traffic()
 
         results[self.chain_name] = {'result': self.__get_chain_result()}