Be explicit about text file encoding
[nfvbench.git] / nfvbench / chaining.py
index d035a40..5248d01 100644 (file)
@@ -54,10 +54,10 @@ from neutronclient.neutron import client as neutronclient
 from novaclient.client import Client
 
 from attrdict import AttrDict
-from chain_router import ChainRouter
-import compute
-from log import LOG
-from specs import ChainType
+from .chain_router import ChainRouter
+from . import compute
+from .log import LOG
+from .specs import ChainType
 # Left and right index for network and port lists
 LEFT = 0
 RIGHT = 1
@@ -77,9 +77,6 @@ BOOT_SCRIPT_PATHNAME = os.path.join(os.path.dirname(os.path.abspath(__file__)),
 class ChainException(Exception):
     """Exception while operating the chains."""
 
-    pass
-
-
 class NetworkEncaps(object):
     """Network encapsulation."""
 
@@ -161,6 +158,10 @@ class ChainVnfPort(object):
                     'binding:vnic_type': vnic_type
                 }
             }
+            subnet_id = chain_network.get_subnet_uuid()
+            if subnet_id:
+                body['port']['fixed_ips'] = [{'subnet_id': subnet_id}]
+
             port = self.manager.neutron_client.create_port(body)
             self.port = port['port']
             LOG.info('Created port %s', name)
@@ -243,11 +244,13 @@ class ChainNetwork(object):
             self.name = self.name + suffix
         self.segmentation_id = self._get_item(network_config.segmentation_id,
                                               chain_id, auto_index=True)
+        self.subnet_name = self._get_item(network_config.subnet, chain_id)
         self.physical_network = self._get_item(network_config.physical_network, chain_id)
 
         self.reuse = False
         self.network = None
         self.vlan = None
+        self.router_name = None
         if manager.config.l3_router and hasattr(network_config, 'router_name'):
             self.router_name = network_config.router_name
         try:
@@ -281,7 +284,7 @@ class ChainNetwork(object):
                 return item_field[index]
             except IndexError:
                 raise ChainException("List %s is too short for chain index %d" %
-                                     (str(item_field), index))
+                                     (str(item_field), index)) from IndexError
         # single value is configured
         if auto_index:
             return item_field + index
@@ -354,6 +357,18 @@ class ChainNetwork(object):
         """
         return self.network['id']
 
+    def get_subnet_uuid(self):
+        """
+        Extract UUID of this subnet network.
+
+        :return: UUID of this subnet network
+        """
+        for subnet in self.network['subnets']:
+            if self.subnet_name == self.manager.neutron_client \
+                    .show_subnet(subnet)['subnet']['name']:
+                return subnet
+        return None
+
     def get_vlan(self):
         """
         Extract vlan for this network.
@@ -373,6 +388,15 @@ class ChainNetwork(object):
 
         return self.network['provider:segmentation_id']
 
+    def get_mpls_inner_label(self):
+        """
+        Extract MPLS VPN Label for this network.
+
+        :return: MPLS VPN Label for this network
+        """
+
+        return self.network['provider:segmentation_id']
+
     def delete(self):
         """Delete this network."""
         if not self.reuse and self.network:
@@ -459,8 +483,12 @@ class ChainVnf(object):
         else:
             tg_gateway1_ip = devices[LEFT].tg_gateway_ip_addrs
             tg_gateway2_ip = devices[RIGHT].tg_gateway_ip_addrs
-            tg_mac1 = remote_mac_pair[0]
-            tg_mac2 = remote_mac_pair[1]
+            if not config.loop_vm_arp:
+                tg_mac1 = remote_mac_pair[0]
+                tg_mac2 = remote_mac_pair[1]
+            else:
+                tg_mac1 = ""
+                tg_mac2 = ""
 
             g1cidr = devices[LEFT].get_gw_ip(
                 self.chain.chain_id) + self.__get_network_mask(
@@ -472,7 +500,7 @@ class ChainVnf(object):
             vnf_gateway1_cidr = g1cidr
             vnf_gateway2_cidr = g2cidr
 
-        with open(BOOT_SCRIPT_PATHNAME, 'r') as boot_script:
+        with open(BOOT_SCRIPT_PATHNAME, 'r', encoding="utf-8") as boot_script:
             content = boot_script.read()
         vm_config = {
             'forwarder': config.vm_forwarder,
@@ -706,8 +734,8 @@ class ChainVnf(object):
                     # here we MUST wait until this instance is resolved otherwise subsequent
                     # VNF creation can be placed in other hypervisors!
                     config = self.manager.config
-                    max_retries = (config.check_traffic_time_sec +
-                                   config.generic_poll_sec - 1) / config.generic_poll_sec
+                    max_retries = int((config.check_traffic_time_sec +
+                                       config.generic_poll_sec - 1) / config.generic_poll_sec)
                     retry = 0
                     for retry in range(max_retries):
                         status = self.get_status()
@@ -914,7 +942,10 @@ class Chain(object):
         if port_index:
             # this will pick the last item in array
             port_index = -1
-        return self.networks[port_index].get_vlan()
+        # This string filters networks connected to TG, in case of
+        # l3-router feature we have 4 networks instead of 2
+        networks = [x for x in self.networks if not x.router_name]
+        return networks[port_index].get_vlan()
 
     def get_vxlan(self, port_index):
         """Get the VXLAN id on a given port.
@@ -930,6 +961,20 @@ class Chain(object):
             port_index = -1
         return self.networks[port_index].get_vxlan()
 
+    def get_mpls_inner_label(self, port_index):
+        """Get the MPLS VPN Label on a given port.
+
+        port_index: left port is 0, right port is 1
+        return: the mpls_label_id or None if there is no mpls
+        """
+        # for port 1 we need to return the MPLS Label of the last network in the chain
+        # The networks array contains 2 networks for PVP [left, right]
+        # and 3 networks in the case of PVVP [left.middle,right]
+        if port_index:
+            # this will pick the last item in array
+            port_index = -1
+        return self.networks[port_index].get_mpls_inner_label()
+
     def get_dest_mac(self, port_index):
         """Get the dest MAC on a given port.
 
@@ -1167,7 +1212,8 @@ class ChainManager(object):
             self.vlans = [self._check_list('vlans[0]', self.config.vlans[0], re_vlan),
                           self._check_list('vlans[1]', self.config.vlans[1], re_vlan)]
         except IndexError:
-            raise ChainException('vlans parameter is mandatory. Set valid value in config file')
+            raise ChainException(
+                'vlans parameter is mandatory. Set valid value in config file') from IndexError
 
     def _get_dest_macs_from_config(self):
         re_mac = "[0-9a-fA-F]{2}([-:])[0-9a-fA-F]{2}(\\1[0-9a-fA-F]{2}){4}$"
@@ -1181,6 +1227,8 @@ class ChainManager(object):
         # if it is a single int or mac, make it a list of 1 int
         if isinstance(ll, (int, str)):
             ll = [ll]
+        else:
+            ll = list(ll)
         for item in ll:
             if not re.match(pattern, str(item)):
                 raise ChainException("Invalid format '{item}' specified in {fname}"
@@ -1247,7 +1295,6 @@ class ChainManager(object):
         for chain in self.chains:
             instances.extend(chain.get_instances())
         initial_instance_count = len(instances)
-        # Give additional 10 seconds per VM
         max_retries = (self.config.check_traffic_time_sec + (initial_instance_count - 1) * 10 +
                        self.config.generic_poll_sec - 1) / self.config.generic_poll_sec
         retry = 0
@@ -1294,6 +1341,7 @@ class ChainManager(object):
             lookup_only = True
             ext_net = self.config.external_networks
             net_cfg = [AttrDict({'name': name,
+                                 'subnet': None,
                                  'segmentation_id': None,
                                  'physical_network': None})
                        for name in [ext_net.left, ext_net.right]]
@@ -1380,7 +1428,7 @@ class ChainManager(object):
         return: the hypervisor where the matching port runs or None if not found
         """
         # _existing_ports is a dict of list of ports indexed by network id
-        for port_list in self.get_existing_ports().values():
+        for port_list in list(self.get_existing_ports().values()):
             for port in port_list:
                 try:
                     if port['mac_address'] == mac:
@@ -1425,6 +1473,18 @@ class ChainManager(object):
         # no openstack
         raise ChainException('VxLAN is only supported with OpenStack and with admin user')
 
+    def get_chain_mpls_inner_labels(self, port_index):
+        """Get the list of per chain MPLS VPN Labels on a given port.
+
+        port_index: left port is 0, right port is 1
+        return: a MPLSs ID list indexed by the chain index or None if no mpls
+        """
+        if self.chains and self.is_admin:
+            return [self.chains[chain_index].get_mpls_inner_label(port_index)
+                    for chain_index in range(self.chain_count)]
+        # no openstack
+        raise ChainException('MPLS is only supported with OpenStack and with admin user')
+
     def get_dest_macs(self, port_index):
         """Get the list of per chain dest MACs on a given port.