fix 1223. Increment ip address on scaling vdus
[osm/RO.git] / RO / osm_ro / nfvo.py
index a28f57f..e346699 100644 (file)
@@ -20,7 +20,7 @@
 # For those usages not covered by the Apache License, Version 2.0 please
 # contact with: nfvlabs@tid.es
 ##
 # For those usages not covered by the Apache License, Version 2.0 please
 # contact with: nfvlabs@tid.es
 ##
-
 '''
 NFVO engine, implementing all the methods for the creation, deletion and management of vnfs, scenarios and instances
 '''
 '''
 NFVO engine, implementing all the methods for the creation, deletion and management of vnfs, scenarios and instances
 '''
@@ -29,12 +29,17 @@ __date__ ="$16-sep-2014 22:05:01$"
 
 # import imp
 import json
 
 # import imp
 import json
+import string
 import yaml
 import yaml
+from random import choice as random_choice
 from osm_ro import utils
 from osm_ro.utils import deprecated
 from osm_ro.vim_thread import vim_thread
 import osm_ro.console_proxy_thread as cli
 from osm_ro import utils
 from osm_ro.utils import deprecated
 from osm_ro.vim_thread import vim_thread
 import osm_ro.console_proxy_thread as cli
-from osm_ro import vimconn
+from osm_ro_plugin.vim_dummy import VimDummyConnector
+from osm_ro_plugin.sdn_dummy import SdnDummyConnector
+from osm_ro_plugin.sdn_failing import SdnFailingConnector
+from osm_ro_plugin import vimconn, sdnconn
 import logging
 import collections
 import math
 import logging
 import collections
 import math
@@ -44,15 +49,7 @@ from osm_ro.db_base import db_base_Exception
 from osm_ro import nfvo_db
 from threading import Lock
 import time as t
 from osm_ro import nfvo_db
 from threading import Lock
 import time as t
-# TODO py3 BEGIN
-# from lib_osm_openvim import ovim as ovim_module
-# from lib_osm_openvim.ovim import ovimException
-from unittest.mock  import MagicMock
-ovim_module = MagicMock()
-class ovimException(Exception):
-   pass
-ovim_module.ovimException = ovimException
-# TODO py3 END
+from osm_ro.sdn import Sdn, SdnException as ovimException
 
 from Crypto.PublicKey import RSA
 
 
 from Crypto.PublicKey import RSA
 
@@ -64,11 +61,9 @@ from pkg_resources import iter_entry_points
 
 
 # WIM
 
 
 # WIM
-import osm_ro.wim.wimconn as wimconn
-import osm_ro.wim.wim_thread as wim_thread
-from osm_ro.http_tools import errors as httperrors
-from osm_ro.wim.engine import WimEngine
-from osm_ro.wim.persistence import WimPersistence
+from .http_tools import errors as httperrors
+from .wim.engine import WimEngine
+from .wim.persistence import WimPersistence
 from copy import deepcopy
 from pprint import pformat
 #
 from copy import deepcopy
 from pprint import pformat
 #
@@ -77,7 +72,7 @@ global global_config
 # WIM
 global wim_engine
 wim_engine  = None
 # WIM
 global wim_engine
 wim_engine  = None
-global wimconn_imported
+global sdnconn_imported
 #
 global logger
 global default_volume_size
 #
 global logger
 global default_volume_size
@@ -90,7 +85,7 @@ plugins = {}   # dictionary with VIM type as key, loaded module as value
 vim_threads = {"running":{}, "deleting": {}, "names": []}      # threads running for attached-VIMs
 vim_persistent_info = {}
 # WIM
 vim_threads = {"running":{}, "deleting": {}, "names": []}      # threads running for attached-VIMs
 vim_persistent_info = {}
 # WIM
-wimconn_imported = {}   # dictionary with WIM type as key, loaded module as value
+sdnconn_imported = {}   # dictionary with WIM type as key, loaded module as value
 wim_threads = {"running":{}, "deleting": {}, "names": []}      # threads running for attached-WIMs
 wim_persistent_info = {}
 #
 wim_threads = {"running":{}, "deleting": {}, "names": []}      # threads running for attached-WIMs
 wim_persistent_info = {}
 #
@@ -101,17 +96,28 @@ last_task_id = 0.0
 db = None
 db_lock = Lock()
 
 db = None
 db_lock = Lock()
 
+worker_id = None
 
 class NfvoException(httperrors.HttpMappedError):
     """Common Class for NFVO errors"""
 
 
 class NfvoException(httperrors.HttpMappedError):
     """Common Class for NFVO errors"""
 
-def _load_vim_plugin(name):
+def _load_plugin(name, type="vim"):
+    # type can be vim or sdn
     global plugins
     global plugins
-    for v in iter_entry_points('osm_rovim.plugins', name):
-        plugins[name] = v.load()
+    try:
+        for v in iter_entry_points('osm_ro{}.plugins'.format(type), name):
+            plugins[name] = v.load()
+    except Exception as e:
+        logger.critical("Cannot load osm_{}: {}".format(name, e))
+        if name:
+            plugins[name] = SdnFailingConnector("Cannot load osm_{}: {}".format(name, e))
     if name and name not in plugins:
     if name and name not in plugins:
-        raise NfvoException("Unknown vim type '{}'. This plugin has not been registered".format(name),
-                            httperrors.Bad_Request)
+        error_text = "Cannot load a module for {t} type '{n}'. The plugin 'osm_{n}' has not been" \
+                     " registered".format(t=type, n=name)
+        logger.critical(error_text)
+        plugins[name] = SdnFailingConnector(error_text)
+        # raise NfvoException("Cannot load a module for {t} type '{n}'. The plugin 'osm_{n}' has not been registered".
+        #                     format(t=type, n=name), httperrors.Bad_Request)
 
 def get_task_id():
     global last_task_id
 
 def get_task_id():
     global last_task_id
@@ -135,20 +141,31 @@ def new_task(name, params, depends=None):
 def is_task_id(id):
     return True if id[:5] == "TASK-" else False
 
 def is_task_id(id):
     return True if id[:5] == "TASK-" else False
 
-
-def get_non_used_vim_name(datacenter_name, datacenter_id, tenant_name, tenant_id):
-    name = datacenter_name[:16]
-    if name not in vim_threads["names"]:
-        vim_threads["names"].append(name)
-        return name
-    if tenant_name:
-        name = datacenter_name[:16] + "." + tenant_name[:16]
-        if name not in vim_threads["names"]:
-            vim_threads["names"].append(name)
-            return name
-    name = datacenter_id
-    vim_threads["names"].append(name)
-    return name
+def get_process_id():
+    """
+    Obtain a unique ID for this process. If running from inside docker, it will get docker ID. If not it
+    will provide a random one
+    :return: Obtained ID
+    """
+    # Try getting docker id. If fails, get pid
+    try:
+        with open("/proc/self/cgroup", "r") as f:
+            for text_id_ in f.readlines():
+                if "docker/" not in text_id_:
+                    continue
+                _, _, text_id = text_id_.rpartition("/")
+                text_id = text_id.replace("\n", "")[:12]
+                if text_id:
+                    return text_id
+    except Exception:
+        pass
+    # Return a random id
+    return "".join(random_choice("0123456789abcdef") for _ in range(12))
+
+def get_non_used_vim_name(datacenter_name, datacenter_id):
+    return "{}:{}:{}".format(
+        worker_id[:12], datacenter_id.replace("-", "")[:32], datacenter_name[:16]
+    )
 
 # -- Move
 def get_non_used_wim_name(wim_name, wim_id, tenant_name, tenant_id):
 
 # -- Move
 def get_non_used_wim_name(wim_name, wim_id, tenant_name, tenant_id):
@@ -166,37 +183,24 @@ def get_non_used_wim_name(wim_name, wim_id, tenant_name, tenant_id):
 
 
 def start_service(mydb, persistence=None, wim=None):
 
 
 def start_service(mydb, persistence=None, wim=None):
-    global db, global_config, plugins
+    global db, global_config, plugins, ovim, worker_id
     db = nfvo_db.nfvo_db(lock=db_lock)
     mydb.lock = db_lock
     db.connect(global_config['db_host'], global_config['db_user'], global_config['db_passwd'], global_config['db_name'])
     db = nfvo_db.nfvo_db(lock=db_lock)
     mydb.lock = db_lock
     db.connect(global_config['db_host'], global_config['db_user'], global_config['db_passwd'], global_config['db_name'])
-    global ovim
 
     persistence = persistence or  WimPersistence(db)
 
 
     persistence = persistence or  WimPersistence(db)
 
-    # Initialize openvim for SDN control
-    # TODO: Avoid static configuration by adding new parameters to openmanod.cfg
-    # TODO: review ovim.py to delete not needed configuration
-    ovim_configuration = {
-        'logger_name': 'openmano.ovim',
-        'network_vlan_range_start': 1000,
-        'network_vlan_range_end': 4096,
-        'db_name': global_config["db_ovim_name"],
-        'db_host': global_config["db_ovim_host"],
-        'db_user': global_config["db_ovim_user"],
-        'db_passwd': global_config["db_ovim_passwd"],
-        'bridge_ifaces': {},
-        'mode': 'normal',
-        'network_type': 'bridge',
-        #TODO: log_level_of should not be needed. To be modified in ovim
-        'log_level_of': 'DEBUG'
-    }
     try:
     try:
+        worker_id = get_process_id()
+        if "rosdn_dummy" not in plugins:
+            plugins["rosdn_dummy"] = SdnDummyConnector
+        if "rovim_dummy" not in plugins:
+            plugins["rovim_dummy"] = VimDummyConnector
         # starts ovim library
         # starts ovim library
-        ovim = ovim_module.ovim(ovim_configuration)
+        ovim = Sdn(db, plugins)
 
         global wim_engine
 
         global wim_engine
-        wim_engine = wim or WimEngine(persistence)
+        wim_engine = wim or WimEngine(persistence, plugins)
         wim_engine.ovim = ovim
 
         ovim.start_service()
         wim_engine.ovim = ovim
 
         ovim.start_service()
@@ -221,38 +225,51 @@ def start_service(mydb, persistence=None, wim=None):
                 extra.update(yaml.load(vim["dt_config"], Loader=yaml.Loader))
             plugin_name = "rovim_" + vim["type"]
             if plugin_name not in plugins:
                 extra.update(yaml.load(vim["dt_config"], Loader=yaml.Loader))
             plugin_name = "rovim_" + vim["type"]
             if plugin_name not in plugins:
-                _load_vim_plugin(plugin_name)
+                _load_plugin(plugin_name, type="vim")
 
             thread_id = vim['datacenter_tenant_id']
             vim_persistent_info[thread_id] = {}
             try:
                 #if not tenant:
                 #    return -httperrors.Bad_Request, "You must provide a valid tenant name or uuid for VIM  %s" % ( vim["type"])
 
             thread_id = vim['datacenter_tenant_id']
             vim_persistent_info[thread_id] = {}
             try:
                 #if not tenant:
                 #    return -httperrors.Bad_Request, "You must provide a valid tenant name or uuid for VIM  %s" % ( vim["type"])
-                myvim = plugins[plugin_name].vimconnector(
+                myvim = plugins[plugin_name](
                     uuid=vim['datacenter_id'], name=vim['datacenter_name'],
                     tenant_id=vim['vim_tenant_id'], tenant_name=vim['vim_tenant_name'],
                     url=vim['vim_url'], url_admin=vim['vim_url_admin'],
                     user=vim['user'], passwd=vim['passwd'],
                     config=extra, persistent_info=vim_persistent_info[thread_id]
                 )
                     uuid=vim['datacenter_id'], name=vim['datacenter_name'],
                     tenant_id=vim['vim_tenant_id'], tenant_name=vim['vim_tenant_name'],
                     url=vim['vim_url'], url_admin=vim['vim_url_admin'],
                     user=vim['user'], passwd=vim['passwd'],
                     config=extra, persistent_info=vim_persistent_info[thread_id]
                 )
-            except vimconn.vimconnException as e:
+            except vimconn.VimConnException as e:
                 myvim = e
                 logger.error("Cannot launch thread for VIM {} '{}': {}".format(vim['datacenter_name'],
                                                                                vim['datacenter_id'], e))
             except Exception as e:
                 myvim = e
                 logger.error("Cannot launch thread for VIM {} '{}': {}".format(vim['datacenter_name'],
                                                                                vim['datacenter_id'], e))
             except Exception as e:
-                raise NfvoException("Error at VIM  {}; {}: {}".format(vim["type"], type(e).__name__, e),
-                                    httperrors.Internal_Server_Error)
-            thread_name = get_non_used_vim_name(vim['datacenter_name'], vim['datacenter_id'], vim['vim_tenant_name'],
-                                                vim['vim_tenant_id'])
-            new_thread = vim_thread(task_lock, plugins, thread_name, vim['datacenter_name'],
-                                    vim['datacenter_tenant_id'], db=db, db_lock=db_lock, ovim=ovim)
+                logger.critical("Cannot launch thread for VIM {} '{}': {}".format(vim['datacenter_name'],
+                                                                                  vim['datacenter_id'], e))
+                # raise NfvoException("Error at VIM  {}; {}: {}".format(vim["type"], type(e).__name__, e),
+                #                     httperrors.Internal_Server_Error)
+            thread_name = get_non_used_vim_name(vim['datacenter_name'], vim['datacenter_id'])
+            new_thread = vim_thread(task_lock, plugins, thread_name, None,
+                                    vim['datacenter_tenant_id'], db=db)
             new_thread.start()
             vim_threads["running"][thread_id] = new_thread
             new_thread.start()
             vim_threads["running"][thread_id] = new_thread
+        wims = mydb.get_rows(FROM="wim_accounts join wims on wim_accounts.wim_id=wims.uuid",
+                             WHERE={"sdn": "true"},
+                             SELECT=("wim_accounts.uuid as uuid", "type", "wim_accounts.name as name"))
+        for wim in wims:
+            plugin_name = "rosdn_" + wim["type"]
+            if plugin_name not in plugins:
+                _load_plugin(plugin_name, type="sdn")
 
 
+            thread_id = wim['uuid']
+            thread_name = get_non_used_vim_name(wim['name'], wim['uuid'])
+            new_thread = vim_thread(task_lock, plugins, thread_name, wim['uuid'], None, db=db)
+            new_thread.start()
+            vim_threads["running"][thread_id] = new_thread
         wim_engine.start_threads()
     except db_base_Exception as e:
         raise NfvoException(str(e) + " at nfvo.get_vim", e.http_code)
         wim_engine.start_threads()
     except db_base_Exception as e:
         raise NfvoException(str(e) + " at nfvo.get_vim", e.http_code)
-    except ovim_module.ovimException as e:
+    except ovimException as e:
         message = str(e)
         if message[:22] == "DATABASE wrong version":
             message = "DATABASE wrong version of lib_osm_openvim {msg} -d{dbname} -u{dbuser} -p{dbpass} {ver}' "\
         message = str(e)
         if message[:22] == "DATABASE wrong version":
             message = "DATABASE wrong version of lib_osm_openvim {msg} -d{dbname} -u{dbuser} -p{dbpass} {ver}' "\
@@ -397,7 +414,7 @@ def get_vim(mydb, nfvo_tenant=None, datacenter_id=None, datacenter_name=None, da
             plugin_name = "rovim_" + vim["type"]
             if plugin_name not in plugins:
                 try:
             plugin_name = "rovim_" + vim["type"]
             if plugin_name not in plugins:
                 try:
-                    _load_vim_plugin(plugin_name)
+                    _load_plugin(plugin_name, type="vim")
                 except NfvoException as e:
                     if ignore_errors:
                         logger.error("{}".format(e))
                 except NfvoException as e:
                     if ignore_errors:
                         logger.error("{}".format(e))
@@ -414,7 +431,7 @@ def get_vim(mydb, nfvo_tenant=None, datacenter_id=None, datacenter_name=None, da
                     persistent_info = {}
                 #if not tenant:
                 #    return -httperrors.Bad_Request, "You must provide a valid tenant name or uuid for VIM  %s" % ( vim["type"])
                     persistent_info = {}
                 #if not tenant:
                 #    return -httperrors.Bad_Request, "You must provide a valid tenant name or uuid for VIM  %s" % ( vim["type"])
-                vim_dict[vim['datacenter_id']] = plugins[plugin_name].vimconnector(
+                vim_dict[vim['datacenter_id']] = plugins[plugin_name](
                                 uuid=vim['datacenter_id'], name=vim['datacenter_name'],
                                 tenant_id=vim.get('vim_tenant_id',vim_tenant),
                                 tenant_name=vim.get('vim_tenant_name',vim_tenant_name),
                                 uuid=vim['datacenter_id'], name=vim['datacenter_name'],
                                 tenant_id=vim.get('vim_tenant_id',vim_tenant),
                                 tenant_name=vim.get('vim_tenant_name',vim_tenant_name),
@@ -427,7 +444,7 @@ def get_vim(mydb, nfvo_tenant=None, datacenter_id=None, datacenter_name=None, da
                     logger.error("Error at VIM  {}; {}: {}".format(vim["type"], type(e).__name__, str(e)))
                     continue
                 http_code = httperrors.Internal_Server_Error
                     logger.error("Error at VIM  {}; {}: {}".format(vim["type"], type(e).__name__, str(e)))
                     continue
                 http_code = httperrors.Internal_Server_Error
-                if isinstance(e, vimconn.vimconnException):
+                if isinstance(e, vimconn.VimConnException):
                     http_code = e.http_code
                 raise NfvoException("Error at VIM  {}; {}: {}".format(vim["type"], type(e).__name__, str(e)), http_code)
         return vim_dict
                     http_code = e.http_code
                 raise NfvoException("Error at VIM  {}; {}: {}".format(vim["type"], type(e).__name__, str(e)), http_code)
         return vim_dict
@@ -457,7 +474,7 @@ def rollback(mydb,  vims, rollback_list):
                     vim.delete_network(item["uuid"])
                 elif item["what"]=="vm":
                     vim.delete_vminstance(item["uuid"])
                     vim.delete_network(item["uuid"])
                 elif item["what"]=="vm":
                     vim.delete_vminstance(item["uuid"])
-            except vimconn.vimconnException as e:
+            except vimconn.VimConnException as e:
                 logger.error("Error in rollback. Not possible to delete VIM %s '%s'. Message: %s", item['what'], item["uuid"], str(e))
                 undeleted_items.append("{} {} from VIM {}".format(item['what'], item["uuid"], vim["name"]))
             except db_base_Exception as e:
                 logger.error("Error in rollback. Not possible to delete VIM %s '%s'. Message: %s", item['what'], item["uuid"], str(e))
                 undeleted_items.append("{} {} from VIM {}".format(item['what'], item["uuid"], vim["name"]))
             except db_base_Exception as e:
@@ -473,9 +490,9 @@ def rollback(mydb,  vims, rollback_list):
                 logger.error("Error in rollback. Not possible to delete %s '%s' from DB. Message: %s", item['what'], item["uuid"], str(e))
                 undeleted_items.append("{} '{}'".format(item['what'], item["uuid"]))
     if len(undeleted_items)==0:
                 logger.error("Error in rollback. Not possible to delete %s '%s' from DB. Message: %s", item['what'], item["uuid"], str(e))
                 undeleted_items.append("{} '{}'".format(item['what'], item["uuid"]))
     if len(undeleted_items)==0:
-        return True,Rollback successful."
+        return True, "Rollback successful."
     else:
     else:
-        return False,Rollback fails to delete: " + str(undeleted_items)
+        return False, "Rollback fails to delete: " + str(undeleted_items)
 
 
 def check_vnf_descriptor(vnf_descriptor, vnf_descriptor_version=1):
 
 
 def check_vnf_descriptor(vnf_descriptor, vnf_descriptor_version=1):
@@ -634,14 +651,14 @@ def create_or_use_image(mydb, vims, image_dict, rollback_list, only_create_at_vi
                 vim_images = vim.get_image_list(filter_dict)
                 #logger.debug('>>>>>>>> VIM images: %s', str(vim_images))
                 if len(vim_images) > 1:
                 vim_images = vim.get_image_list(filter_dict)
                 #logger.debug('>>>>>>>> VIM images: %s', str(vim_images))
                 if len(vim_images) > 1:
-                    raise vimconn.vimconnException("More than one candidate VIM image found for filter: {}".format(str(filter_dict)), httperrors.Conflict)
+                    raise vimconn.VimConnException("More than one candidate VIM image found for filter: {}".format(str(filter_dict)), httperrors.Conflict)
                 elif len(vim_images) == 0:
                 elif len(vim_images) == 0:
-                    raise vimconn.vimconnNotFoundException("Image not found at VIM with filter: '{}'".format(str(filter_dict)))
+                    raise vimconn.VimConnNotFoundException("Image not found at VIM with filter: '{}'".format(str(filter_dict)))
                 else:
                     #logger.debug('>>>>>>>> VIM image 0: %s', str(vim_images[0]))
                     image_vim_id = vim_images[0]['id']
 
                 else:
                     #logger.debug('>>>>>>>> VIM image 0: %s', str(vim_images[0]))
                     image_vim_id = vim_images[0]['id']
 
-        except vimconn.vimconnNotFoundException as e:
+        except vimconn.VimConnNotFoundException as e:
             #Create the image in VIM only if image_dict['location'] or image_dict['new_location'] is not None
             try:
                 #image_dict['location']=image_dict.get('new_location') if image_dict['location'] is None
             #Create the image in VIM only if image_dict['location'] or image_dict['new_location'] is not None
             try:
                 #image_dict['location']=image_dict.get('new_location') if image_dict['location'] is None
@@ -651,15 +668,15 @@ def create_or_use_image(mydb, vims, image_dict, rollback_list, only_create_at_vi
                     image_created="true"
                 else:
                     #If we reach this point, then the image has image name, and optionally checksum, and could not be found
                     image_created="true"
                 else:
                     #If we reach this point, then the image has image name, and optionally checksum, and could not be found
-                    raise vimconn.vimconnException(str(e))
-            except vimconn.vimconnException as e:
+                    raise vimconn.VimConnException(str(e))
+            except vimconn.VimConnException as e:
                 if return_on_error:
                     logger.error("Error creating image at VIM '%s': %s", vim["name"], str(e))
                     raise
                 image_vim_id = None
                 logger.warn("Error creating image at VIM '%s': %s", vim["name"], str(e))
                 continue
                 if return_on_error:
                     logger.error("Error creating image at VIM '%s': %s", vim["name"], str(e))
                     raise
                 image_vim_id = None
                 logger.warn("Error creating image at VIM '%s': %s", vim["name"], str(e))
                 continue
-        except vimconn.vimconnException as e:
+        except vimconn.VimConnException as e:
             if return_on_error:
                 logger.error("Error contacting VIM to know if the image exists at VIM: %s", str(e))
                 raise
             if return_on_error:
                 logger.error("Error contacting VIM to know if the image exists at VIM: %s", str(e))
                 raise
@@ -797,7 +814,7 @@ def create_or_use_flavor(mydb, vims, flavor_dict, rollback_list, only_create_at_
             try:
                 vim.get_flavor(flavor_vim_id)
                 continue #flavor exist
             try:
                 vim.get_flavor(flavor_vim_id)
                 continue #flavor exist
-            except vimconn.vimconnException:
+            except vimconn.VimConnException:
                 pass
         #create flavor at vim
         logger.debug("nfvo.create_or_use_flavor() adding flavor to VIM %s", vim["name"])
                 pass
         #create flavor at vim
         logger.debug("nfvo.create_or_use_flavor() adding flavor to VIM %s", vim["name"])
@@ -805,14 +822,14 @@ def create_or_use_flavor(mydb, vims, flavor_dict, rollback_list, only_create_at_
             flavor_vim_id = None
             flavor_vim_id=vim.get_flavor_id_from_data(flavor_dict)
             flavor_created="false"
             flavor_vim_id = None
             flavor_vim_id=vim.get_flavor_id_from_data(flavor_dict)
             flavor_created="false"
-        except vimconn.vimconnException as e:
+        except vimconn.VimConnException as e:
             pass
         try:
             if not flavor_vim_id:
                 flavor_vim_id = vim.new_flavor(flavor_dict)
                 rollback_list.append({"where":"vim", "vim_id": vim_id, "what":"flavor","uuid":flavor_vim_id})
                 flavor_created="true"
             pass
         try:
             if not flavor_vim_id:
                 flavor_vim_id = vim.new_flavor(flavor_dict)
                 rollback_list.append({"where":"vim", "vim_id": vim_id, "what":"flavor","uuid":flavor_vim_id})
                 flavor_created="true"
-        except vimconn.vimconnException as e:
+        except vimconn.VimConnException as e:
             if return_on_error:
                 logger.error("Error creating flavor at VIM %s: %s.", vim["name"], str(e))
                 raise
             if return_on_error:
                 logger.error("Error creating flavor at VIM %s: %s.", vim["name"], str(e))
                 raise
@@ -970,6 +987,7 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor):
 
             # table nets (internal-vld)
             net_id2uuid = {}  # for mapping interface with network
 
             # table nets (internal-vld)
             net_id2uuid = {}  # for mapping interface with network
+            net_id2index = {}  # for mapping interface with network
             for vld in vnfd.get("internal-vld").values():
                 net_uuid = str(uuid4())
                 uuid_list.append(net_uuid)
             for vld in vnfd.get("internal-vld").values():
                 net_uuid = str(uuid4())
                 uuid_list.append(net_uuid)
@@ -982,6 +1000,7 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor):
                     "type": "bridge",   # TODO adjust depending on connection point type
                 }
                 net_id2uuid[vld.get("id")] = net_uuid
                     "type": "bridge",   # TODO adjust depending on connection point type
                 }
                 net_id2uuid[vld.get("id")] = net_uuid
+                net_id2index[vld.get("id")] = len(db_nets)
                 db_nets.append(db_net)
                 # ip-profile, link db_ip_profile with db_sce_net
                 if vld.get("ip-profile-ref"):
                 db_nets.append(db_net)
                 # ip-profile, link db_ip_profile with db_sce_net
                 if vld.get("ip-profile-ref"):
@@ -1174,7 +1193,7 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor):
                                 raise KeyError()
 
                             if vdu_id in vdu_id2cp_name:
                                 raise KeyError()
 
                             if vdu_id in vdu_id2cp_name:
-                                vdu_id2cp_name[vdu_id] = None  # more than two connecdtion point for this VDU
+                                vdu_id2cp_name[vdu_id] = None  # more than two connection point for this VDU
                             else:
                                 vdu_id2cp_name[vdu_id] = db_interface["external_name"]
 
                             else:
                                 vdu_id2cp_name[vdu_id] = db_interface["external_name"]
 
@@ -1209,6 +1228,10 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor):
                             if not icp:
                                 raise KeyError("is not referenced by any 'internal-vld'")
 
                             if not icp:
                                 raise KeyError("is not referenced by any 'internal-vld'")
 
+                            # set network type as data
+                            if iface.get("virtual-interface") and iface["virtual-interface"].get("type") in \
+                                    ("SR-IOV", "PCI-PASSTHROUGH"):
+                                db_nets[net_id2index[icp_vld.get("id")]]["type"] = "data"
                             db_interface["net_id"] = net_id2uuid[icp_vld.get("id")]
                             if str(icp_descriptor.get("port-security-enabled")).lower() == "false":
                                 db_interface["port_security"] = 0
                             db_interface["net_id"] = net_id2uuid[icp_vld.get("id")]
                             if str(icp_descriptor.get("port-security-enabled")).lower() == "false":
                                 db_interface["port_security"] = 0
@@ -1348,7 +1371,7 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor):
 
             if vnfd["mgmt-interface"].get("ip-address"):
                 mgmt_access["ip-address"] = str(vnfd["mgmt-interface"].get("ip-address"))
 
             if vnfd["mgmt-interface"].get("ip-address"):
                 mgmt_access["ip-address"] = str(vnfd["mgmt-interface"].get("ip-address"))
-            if vnfd["mgmt-interface"].get("cp"):
+            if vnfd["mgmt-interface"].get("cp") and vnfd.get("vdu"):
                 if vnfd["mgmt-interface"]["cp"] not in cp_name2iface_uuid:
                     raise NfvoException("Error. Invalid VNF descriptor at 'vnfd[{vnf}]':'mgmt-interface':'cp'['{cp}']. "
                                         "Reference to a non-existing connection-point".format(
                 if vnfd["mgmt-interface"]["cp"] not in cp_name2iface_uuid:
                     raise NfvoException("Error. Invalid VNF descriptor at 'vnfd[{vnf}]':'mgmt-interface':'cp'['{cp}']. "
                                         "Reference to a non-existing connection-point".format(
@@ -1525,7 +1548,7 @@ def new_vnf(mydb, tenant_id, vnf_descriptor):
         # Step 8. Adding the VNF to the NFVO DB
         vnf_id = mydb.new_vnf_as_a_whole(tenant_id,vnf_name,vnf_descriptor,VNFCDict)
         return vnf_id
         # Step 8. Adding the VNF to the NFVO DB
         vnf_id = mydb.new_vnf_as_a_whole(tenant_id,vnf_name,vnf_descriptor,VNFCDict)
         return vnf_id
-    except (db_base_Exception, vimconn.vimconnException, KeyError) as e:
+    except (db_base_Exception, vimconn.VimConnException, KeyError) as e:
         _, message = rollback(mydb, vims, rollback_list)
         if isinstance(e, db_base_Exception):
             error_text = "Exception at database"
         _, message = rollback(mydb, vims, rollback_list)
         if isinstance(e, db_base_Exception):
             error_text = "Exception at database"
@@ -1661,7 +1684,7 @@ def new_vnf_v02(mydb, tenant_id, vnf_descriptor):
         # Step 8. Adding the VNF to the NFVO DB
         vnf_id = mydb.new_vnf_as_a_whole2(tenant_id,vnf_name,vnf_descriptor,VNFCDict)
         return vnf_id
         # Step 8. Adding the VNF to the NFVO DB
         vnf_id = mydb.new_vnf_as_a_whole2(tenant_id,vnf_name,vnf_descriptor,VNFCDict)
         return vnf_id
-    except (db_base_Exception, vimconn.vimconnException, KeyError) as e:
+    except (db_base_Exception, vimconn.VimConnException, KeyError) as e:
         _, message = rollback(mydb, vims, rollback_list)
         if isinstance(e, db_base_Exception):
             error_text = "Exception at database"
         _, message = rollback(mydb, vims, rollback_list)
         if isinstance(e, db_base_Exception):
             error_text = "Exception at database"
@@ -1790,10 +1813,10 @@ def delete_vnf(mydb,tenant_id,vnf_id,datacenter=None,vim_tenant=None):
                     continue
                 try:
                     myvim.delete_flavor(flavor_vim["vim_id"])
                     continue
                 try:
                     myvim.delete_flavor(flavor_vim["vim_id"])
-                except vimconn.vimconnNotFoundException:
+                except vimconn.VimConnNotFoundException:
                     logger.warn("VIM flavor %s not exist at datacenter %s", flavor_vim["vim_id"],
                                 flavor_vim["datacenter_vim_id"] )
                     logger.warn("VIM flavor %s not exist at datacenter %s", flavor_vim["vim_id"],
                                 flavor_vim["datacenter_vim_id"] )
-                except vimconn.vimconnException as e:
+                except vimconn.VimConnException as e:
                     logger.error("Not possible to delete VIM flavor %s from datacenter %s: %s %s",
                             flavor_vim["vim_id"], flavor_vim["datacenter_vim_id"], type(e).__name__, str(e))
                     undeletedItems.append("flavor {} from VIM {}".format(flavor_vim["vim_id"],
                     logger.error("Not possible to delete VIM flavor %s from datacenter %s: %s %s",
                             flavor_vim["vim_id"], flavor_vim["datacenter_vim_id"], type(e).__name__, str(e))
                     undeletedItems.append("flavor {} from VIM {}".format(flavor_vim["vim_id"],
@@ -1823,9 +1846,9 @@ def delete_vnf(mydb,tenant_id,vnf_id,datacenter=None,vim_tenant=None):
                 myvim=vims[ image_vim["datacenter_id"] ]
                 try:
                     myvim.delete_image(image_vim["vim_id"])
                 myvim=vims[ image_vim["datacenter_id"] ]
                 try:
                     myvim.delete_image(image_vim["vim_id"])
-                except vimconn.vimconnNotFoundException as e:
+                except vimconn.VimConnNotFoundException as e:
                     logger.warn("VIM image %s not exist at datacenter %s", image_vim["vim_id"], image_vim["datacenter_id"] )
                     logger.warn("VIM image %s not exist at datacenter %s", image_vim["vim_id"], image_vim["datacenter_id"] )
-                except vimconn.vimconnException as e:
+                except vimconn.VimConnException as e:
                     logger.error("Not possible to delete VIM image %s from datacenter %s: %s %s",
                             image_vim["vim_id"], image_vim["datacenter_id"], type(e).__name__, str(e))
                     undeletedItems.append("image {} from VIM {}".format(image_vim["vim_id"], image_vim["datacenter_id"] ))
                     logger.error("Not possible to delete VIM image %s from datacenter %s: %s %s",
                             image_vim["vim_id"], image_vim["datacenter_id"], type(e).__name__, str(e))
                     undeletedItems.append("image {} from VIM {}".format(image_vim["vim_id"], image_vim["datacenter_id"] ))
@@ -1887,7 +1910,7 @@ def get_hosts(mydb, nfvo_tenant_id):
 
         #print 'datacenters '+ json.dumps(datacenter, indent=4)
         return datacenter
 
         #print 'datacenters '+ json.dumps(datacenter, indent=4)
         return datacenter
-    except vimconn.vimconnException as e:
+    except vimconn.VimConnException as e:
         raise NfvoException("Not possible to get_host_list from VIM: {}".format(str(e)), e.http_code)
 
 
         raise NfvoException("Not possible to get_host_list from VIM: {}".format(str(e)), e.http_code)
 
 
@@ -2428,45 +2451,48 @@ def new_nsd_v3(mydb, tenant_id, nsd_descriptor):
 
                 # table sce_interfaces (vld:vnfd-connection-point-ref)
                 for iface in vld.get("vnfd-connection-point-ref").values():
 
                 # table sce_interfaces (vld:vnfd-connection-point-ref)
                 for iface in vld.get("vnfd-connection-point-ref").values():
+                    # Check if there are VDUs in the descriptor
                     vnf_index = str(iface['member-vnf-index-ref'])
                     vnf_index = str(iface['member-vnf-index-ref'])
-                    # check correct parameters
-                    if vnf_index not in vnf_index2vnf_uuid:
-                        raise NfvoException("Error. Invalid NS descriptor at 'nsd[{}]':'vld[{}]':'vnfd-connection-point"
-                                            "-ref':'member-vnf-index-ref':'{}'. Reference to a non-existing index at "
-                                            "'nsd':'constituent-vnfd'".format(
-                                                str(nsd["id"]), str(vld["id"]), str(iface["member-vnf-index-ref"])),
-                                            httperrors.Bad_Request)
-
-                    existing_ifaces = mydb.get_rows(SELECT=('i.uuid as uuid', 'i.type as iface_type'),
-                                                    FROM="interfaces as i join vms on i.vm_id=vms.uuid",
-                                                    WHERE={'vnf_id': vnf_index2vnf_uuid[vnf_index],
-                                                           'external_name': get_str(iface, "vnfd-connection-point-ref",
-                                                                                    255)})
-                    if not existing_ifaces:
-                        raise NfvoException("Error. Invalid NS descriptor at 'nsd[{}]':'vld[{}]':'vnfd-connection-point"
-                                            "-ref':'vnfd-connection-point-ref':'{}'. Reference to a non-existing "
-                                            "connection-point name at VNFD '{}'".format(
-                                                str(nsd["id"]), str(vld["id"]), str(iface["vnfd-connection-point-ref"]),
-                                                str(iface.get("vnfd-id-ref"))[:255]),
-                                            httperrors.Bad_Request)
-                    interface_uuid = existing_ifaces[0]["uuid"]
-                    if existing_ifaces[0]["iface_type"] == "data":
-                        db_sce_net["type"] = "data"
-                    sce_interface_uuid = str(uuid4())
-                    uuid_list.append(sce_net_uuid)
-                    iface_ip_address = None
-                    if iface.get("ip-address"):
-                        iface_ip_address = str(iface.get("ip-address"))
-                    db_sce_interface = {
-                        "uuid": sce_interface_uuid,
-                        "sce_vnf_id": vnf_index2scevnf_uuid[vnf_index],
-                        "sce_net_id": sce_net_uuid,
-                        "interface_id": interface_uuid,
-                        "ip_address": iface_ip_address,
-                    }
-                    db_sce_interfaces.append(db_sce_interface)
-                if not db_sce_net["type"]:
-                    db_sce_net["type"] = "bridge"
+                    existing_vdus = mydb.get_rows(SELECT=('vms.uuid'), FROM="vms", WHERE={'vnf_id': vnf_index2vnf_uuid[vnf_index]})
+                    if existing_vdus:
+                        # check correct parameters
+                        if vnf_index not in vnf_index2vnf_uuid:
+                            raise NfvoException("Error. Invalid NS descriptor at 'nsd[{}]':'vld[{}]':'vnfd-connection-point"
+                                              "-ref':'member-vnf-index-ref':'{}'. Reference to a non-existing index at "
+                                              "'nsd':'constituent-vnfd'".format(
+                                                  str(nsd["id"]), str(vld["id"]), str(iface["member-vnf-index-ref"])),
+                                              httperrors.Bad_Request)
+
+                        existing_ifaces = mydb.get_rows(SELECT=('i.uuid as uuid', 'i.type as iface_type'),
+                                                      FROM="interfaces as i join vms on i.vm_id=vms.uuid",
+                                                      WHERE={'vnf_id': vnf_index2vnf_uuid[vnf_index],
+                                                             'external_name': get_str(iface, "vnfd-connection-point-ref",
+                                                                                      255)})
+                        if not existing_ifaces:
+                            raise NfvoException("Error. Invalid NS descriptor at 'nsd[{}]':'vld[{}]':'vnfd-connection-point"
+                                              "-ref':'vnfd-connection-point-ref':'{}'. Reference to a non-existing "
+                                              "connection-point name at VNFD '{}'".format(
+                                                  str(nsd["id"]), str(vld["id"]), str(iface["vnfd-connection-point-ref"]),
+                                                  str(iface.get("vnfd-id-ref"))[:255]),
+                                              httperrors.Bad_Request)
+                        interface_uuid = existing_ifaces[0]["uuid"]
+                        if existing_ifaces[0]["iface_type"] == "data":
+                            db_sce_net["type"] = "data"
+                        sce_interface_uuid = str(uuid4())
+                        uuid_list.append(sce_net_uuid)
+                        iface_ip_address = None
+                        if iface.get("ip-address"):
+                            iface_ip_address = str(iface.get("ip-address"))
+                        db_sce_interface = {
+                            "uuid": sce_interface_uuid,
+                            "sce_vnf_id": vnf_index2scevnf_uuid[vnf_index],
+                            "sce_net_id": sce_net_uuid,
+                            "interface_id": interface_uuid,
+                            "ip_address": iface_ip_address,
+                        }
+                        db_sce_interfaces.append(db_sce_interface)
+                        if not db_sce_net["type"]:
+                            db_sce_net["type"] = "bridge"
 
             # table sce_vnffgs (vnffgd)
             for vnffg in nsd.get("vnffgd").values():
 
             # table sce_vnffgs (vnffgd)
             for vnffg in nsd.get("vnffgd").values():
@@ -2668,11 +2694,12 @@ def start_scenario(mydb, tenant_id, scenario_id, instance_scenario_name, instanc
             myNetDict["type"] = myNetType
             myNetDict["tenant_id"] = myvim_tenant
             myNetIPProfile = sce_net.get('ip_profile', None)
             myNetDict["type"] = myNetType
             myNetDict["tenant_id"] = myvim_tenant
             myNetIPProfile = sce_net.get('ip_profile', None)
+            myProviderNetwork = sce_net.get('provider_network', None)
             #TODO:
             #We should use the dictionary as input parameter for new_network
             #print myNetDict
             if not sce_net["external"]:
             #TODO:
             #We should use the dictionary as input parameter for new_network
             #print myNetDict
             if not sce_net["external"]:
-                network_id, _ = myvim.new_network(myNetName, myNetType, myNetIPProfile)
+                network_id, _ = myvim.new_network(myNetName, myNetType, myNetIPProfile, provider_network_profile=myProviderNetwork)
                 #print "New VIM network created for scenario %s. Network id:  %s" % (scenarioDict['name'],network_id)
                 sce_net['vim_id'] = network_id
                 auxNetDict['scenario'][sce_net['uuid']] = network_id
                 #print "New VIM network created for scenario %s. Network id:  %s" % (scenarioDict['name'],network_id)
                 sce_net['vim_id'] = network_id
                 auxNetDict['scenario'][sce_net['uuid']] = network_id
@@ -2703,10 +2730,11 @@ def start_scenario(mydb, tenant_id, scenario_id, instance_scenario_name, instanc
                 myNetDict["type"] = myNetType
                 myNetDict["tenant_id"] = myvim_tenant
                 myNetIPProfile = net.get('ip_profile', None)
                 myNetDict["type"] = myNetType
                 myNetDict["tenant_id"] = myvim_tenant
                 myNetIPProfile = net.get('ip_profile', None)
+                myProviderNetwork = sce_net.get('provider_network', None)
                 #print myNetDict
                 #TODO:
                 #We should use the dictionary as input parameter for new_network
                 #print myNetDict
                 #TODO:
                 #We should use the dictionary as input parameter for new_network
-                network_id, _  = myvim.new_network(myNetName, myNetType, myNetIPProfile)
+                network_id, _  = myvim.new_network(myNetName, myNetType, myNetIPProfile, provider_network_profile=myProviderNetwork)
                 #print "VIM network id for scenario %s: %s" % (scenarioDict['name'],network_id)
                 net['vim_id'] = network_id
                 if sce_vnf['uuid'] not in auxNetDict:
                 #print "VIM network id for scenario %s: %s" % (scenarioDict['name'],network_id)
                 net['vim_id'] = network_id
                 if sce_vnf['uuid'] not in auxNetDict:
@@ -2847,7 +2875,7 @@ def start_scenario(mydb, tenant_id, scenario_id, instance_scenario_name, instanc
         instance_id = mydb.new_instance_scenario_as_a_whole(tenant_id,instance_scenario_name, instance_scenario_description, scenarioDict)
         return mydb.get_instance_scenario(instance_id)
 
         instance_id = mydb.new_instance_scenario_as_a_whole(tenant_id,instance_scenario_name, instance_scenario_description, scenarioDict)
         return mydb.get_instance_scenario(instance_id)
 
-    except (db_base_Exception, vimconn.vimconnException) as e:
+    except (db_base_Exception, vimconn.VimConnException) as e:
         _, message = rollback(mydb, vims, rollbackList)
         if isinstance(e, db_base_Exception):
             error_text = "Exception at database"
         _, message = rollback(mydb, vims, rollbackList)
         if isinstance(e, db_base_Exception):
             error_text = "Exception at database"
@@ -2943,6 +2971,7 @@ def unify_cloud_config(cloud_config_preserve, cloud_config):
 
 
 def get_vim_thread(mydb, tenant_id, datacenter_id_name=None, datacenter_tenant_id=None):
 
 
 def get_vim_thread(mydb, tenant_id, datacenter_id_name=None, datacenter_tenant_id=None):
+    global plugins
     datacenter_id = None
     datacenter_name = None
     thread = None
     datacenter_id = None
     datacenter_name = None
     thread = None
@@ -2950,7 +2979,7 @@ def get_vim_thread(mydb, tenant_id, datacenter_id_name=None, datacenter_tenant_i
         if datacenter_tenant_id:
             thread_id = datacenter_tenant_id
             thread = vim_threads["running"].get(datacenter_tenant_id)
         if datacenter_tenant_id:
             thread_id = datacenter_tenant_id
             thread = vim_threads["running"].get(datacenter_tenant_id)
-        else:
+        if not thread:
             where_={"td.nfvo_tenant_id": tenant_id}
             if datacenter_id_name:
                 if utils.check_valid_uuid(datacenter_id_name):
             where_={"td.nfvo_tenant_id": tenant_id}
             if datacenter_id_name:
                 if utils.check_valid_uuid(datacenter_id_name):
@@ -2962,7 +2991,7 @@ def get_vim_thread(mydb, tenant_id, datacenter_id_name=None, datacenter_tenant_i
             if datacenter_tenant_id:
                 where_["dt.uuid"] = datacenter_tenant_id
             datacenters = mydb.get_rows(
             if datacenter_tenant_id:
                 where_["dt.uuid"] = datacenter_tenant_id
             datacenters = mydb.get_rows(
-                SELECT=("dt.uuid as datacenter_tenant_id",),
+                SELECT=("dt.uuid as datacenter_tenant_id, d.name as datacenter_name", "d.type as type"),
                 FROM="datacenter_tenants as dt join tenants_datacenters as td on dt.uuid=td.datacenter_tenant_id "
                      "join datacenters as d on d.uuid=dt.datacenter_id",
                 WHERE=where_)
                 FROM="datacenter_tenants as dt join tenants_datacenters as td on dt.uuid=td.datacenter_tenant_id "
                      "join datacenters as d on d.uuid=dt.datacenter_id",
                 WHERE=where_)
@@ -2970,7 +2999,18 @@ def get_vim_thread(mydb, tenant_id, datacenter_id_name=None, datacenter_tenant_i
                 raise NfvoException("More than one datacenters found, try to identify with uuid", httperrors.Conflict)
             elif datacenters:
                 thread_id = datacenters[0]["datacenter_tenant_id"]
                 raise NfvoException("More than one datacenters found, try to identify with uuid", httperrors.Conflict)
             elif datacenters:
                 thread_id = datacenters[0]["datacenter_tenant_id"]
+                datacenter_name = datacenters[0]["datacenter_name"]
                 thread = vim_threads["running"].get(thread_id)
                 thread = vim_threads["running"].get(thread_id)
+                if not thread:
+                    datacenter_type = datacenters[0]["type"]
+                    plugin_name = "rovim_" + datacenter_type
+                    if plugin_name not in plugins:
+                        _load_plugin(plugin_name, type="vim")
+                    thread_name = get_non_used_vim_name(datacenter_name, datacenter_id)
+                    thread = vim_thread(task_lock, plugins, thread_name, None,
+                                        thread_id, db=mydb)
+                    thread.start()
+                    vim_threads["running"][thread_id] = thread
         if not thread:
             raise NfvoException("datacenter '{}' not found".format(str(datacenter_id_name)), httperrors.Not_Found)
         return thread_id, thread
         if not thread:
             raise NfvoException("datacenter '{}' not found".format(str(datacenter_id_name)), httperrors.Not_Found)
         return thread_id, thread
@@ -2991,13 +3031,14 @@ def get_datacenter_uuid(mydb, tenant_id, datacenter_id_name):
                " dt on td.datacenter_tenant_id=dt.uuid"
     else:
         from_ = 'datacenters as d'
                " dt on td.datacenter_tenant_id=dt.uuid"
     else:
         from_ = 'datacenters as d'
-    vimaccounts = mydb.get_rows(FROM=from_, SELECT=("d.uuid as uuid, d.name as name",), WHERE=WHERE_dict )
+    vimaccounts = mydb.get_rows(FROM=from_, SELECT=("d.uuid as uuid", "d.name as name", "d.type as type"),
+                                WHERE=WHERE_dict)
     if len(vimaccounts) == 0:
         raise NfvoException("datacenter '{}' not found".format(str(datacenter_id_name)), httperrors.Not_Found)
     if len(vimaccounts) == 0:
         raise NfvoException("datacenter '{}' not found".format(str(datacenter_id_name)), httperrors.Not_Found)
-    elif len(vimaccounts)>1:
-        #print "nfvo.datacenter_action() error. Several datacenters found"
+    elif len(vimaccounts) > 1:
+        # print "nfvo.datacenter_action() error. Several datacenters found"
         raise NfvoException("More than one datacenters found, try to identify with uuid", httperrors.Conflict)
         raise NfvoException("More than one datacenters found, try to identify with uuid", httperrors.Conflict)
-    return vimaccounts[0]["uuid"], vimaccounts[0]["name"]
+    return vimaccounts[0]["uuid"], vimaccounts[0]
 
 
 def get_datacenter_by_name_uuid(mydb, tenant_id, datacenter_id_name=None, **extra_filter):
 
 
 def get_datacenter_by_name_uuid(mydb, tenant_id, datacenter_id_name=None, **extra_filter):
@@ -3030,9 +3071,18 @@ def update(d, u):
     return d
 
 
     return d
 
 
+def _get_wim(db, wim_account_id):
+    # get wim from wim_account
+    wim_accounts = db.get_rows(FROM='wim_accounts', WHERE={"uuid": wim_account_id})
+    if not wim_accounts:
+        raise NfvoException("Not found sdn id={}".format(wim_account_id), http_code=httperrors.Not_Found)
+    return wim_accounts[0]["wim_id"]
+
+
 def create_instance(mydb, tenant_id, instance_dict):
     # print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
     # logger.debug("Creating instance...")
 def create_instance(mydb, tenant_id, instance_dict):
     # print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
     # logger.debug("Creating instance...")
+
     scenario = instance_dict["scenario"]
 
     # find main datacenter
     scenario = instance_dict["scenario"]
 
     # find main datacenter
@@ -3094,6 +3144,7 @@ def create_instance(mydb, tenant_id, instance_dict):
     }
 
     # Auxiliary dictionaries from x to y
     }
 
     # Auxiliary dictionaries from x to y
+    sce_net2wim_instance = {}
     sce_net2instance = {}
     net2task_id = {'scenario': {}}
     # Mapping between local networks and WIMs
     sce_net2instance = {}
     net2task_id = {'scenario': {}}
     # Mapping between local networks and WIMs
@@ -3182,6 +3233,13 @@ def create_instance(mydb, tenant_id, instance_dict):
                     else:
                         update(scenario_net['ip_profile'], ipprofile_db)
 
                     else:
                         update(scenario_net['ip_profile'], ipprofile_db)
 
+                if net_instance_desc.get('provider-network'):
+                    provider_network_db = net_instance_desc['provider-network']
+                    if 'provider_network' not in scenario_net:
+                        scenario_net['provider_network'] = provider_network_db
+                    else:
+                        update(scenario_net['provider_network'], provider_network_db)
+
             for vdu_id, vdu_instance_desc in vnf_instance_desc.get("vdus", {}).items():
                 for scenario_vm in scenario_vnf['vms']:
                     if vdu_id == scenario_vm['osm_id'] or vdu_id == scenario_vm["name"]:
             for vdu_id, vdu_instance_desc in vnf_instance_desc.get("vdus", {}).items():
                 for scenario_vm in scenario_vnf['vms']:
                     if vdu_id == scenario_vm['osm_id'] or vdu_id == scenario_vm["name"]:
@@ -3214,6 +3272,14 @@ def create_instance(mydb, tenant_id, instance_dict):
                             scenario_net['ip_profile'] = ipprofile_db
                         else:
                             update(scenario_net['ip_profile'], ipprofile_db)
                             scenario_net['ip_profile'] = ipprofile_db
                         else:
                             update(scenario_net['ip_profile'], ipprofile_db)
+                    if 'provider-network' in net_instance_desc:
+                        provider_network_db = net_instance_desc['provider-network']
+
+                        if 'provider-network' not in scenario_net:
+                            scenario_net['provider_network'] = provider_network_db
+                        else:
+                            update(scenario_net['provider-network'], provider_network_db)
+
             for interface in net_instance_desc.get('interfaces', ()):
                 if 'ip_address' in interface:
                     for vnf in scenarioDict['vnfs']:
             for interface in net_instance_desc.get('interfaces', ()):
                 if 'ip_address' in interface:
                     for vnf in scenarioDict['vnfs']:
@@ -3226,10 +3292,13 @@ def create_instance(mydb, tenant_id, instance_dict):
         # logger.debug("Creating instance scenario-dict MERGED:\n%s",
         #              yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False))
 
         # logger.debug("Creating instance scenario-dict MERGED:\n%s",
         #              yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False))
 
+
         # 1. Creating new nets (sce_nets) in the VIM"
         number_mgmt_networks = 0
         db_instance_nets = []
         # 1. Creating new nets (sce_nets) in the VIM"
         number_mgmt_networks = 0
         db_instance_nets = []
+        db_instance_wim_nets = []
         for sce_net in scenarioDict['nets']:
         for sce_net in scenarioDict['nets']:
+
             sce_net_uuid = sce_net.get('uuid', sce_net["name"])
             # get involved datacenters where this network need to be created
             involved_datacenters = []
             sce_net_uuid = sce_net.get('uuid', sce_net["name"])
             # get involved datacenters where this network need to be created
             involved_datacenters = []
@@ -3246,28 +3315,6 @@ def create_instance(mydb, tenant_id, instance_dict):
                 involved_datacenters.append(default_datacenter_id)
             target_wim_account = sce_net.get("wim_account", default_wim_account)
 
                 involved_datacenters.append(default_datacenter_id)
             target_wim_account = sce_net.get("wim_account", default_wim_account)
 
-            # --> WIM
-            # TODO: use this information during network creation
-            wim_account_id = wim_account_name = None
-            if len(involved_datacenters) > 1 and 'uuid' in sce_net:
-                if target_wim_account is None or target_wim_account is True:  # automatic selection of WIM
-                    # OBS: sce_net without uuid are used internally to VNFs
-                    # and the assumption is that VNFs will not be split among
-                    # different datacenters
-                    wim_account = wim_engine.find_suitable_wim_account(
-                        involved_datacenters, tenant_id)
-                    wim_account_id = wim_account['uuid']
-                    wim_account_name = wim_account['name']
-                    wim_usage[sce_net['uuid']] = wim_account_id
-                elif isinstance(target_wim_account, str):     # manual selection of WIM
-                    wim_account.persist.get_wim_account_by(target_wim_account, tenant_id)
-                    wim_account_id = wim_account['uuid']
-                    wim_account_name = wim_account['name']
-                    wim_usage[sce_net['uuid']] = wim_account_id
-                else:  # not WIM usage
-                    wim_usage[sce_net['uuid']] = False
-            # <-- WIM
-
             descriptor_net = {}
             if instance_dict.get("networks"):
                 if sce_net.get("uuid") in instance_dict["networks"]:
             descriptor_net = {}
             if instance_dict.get("networks"):
                 if sce_net.get("uuid") in instance_dict["networks"]:
@@ -3286,6 +3333,7 @@ def create_instance(mydb, tenant_id, instance_dict):
                     if site.get("datacenter") and site["datacenter"] not in involved_datacenters:
                         involved_datacenters.append(site["datacenter"])
             sce_net2instance[sce_net_uuid] = {}
                     if site.get("datacenter") and site["datacenter"] not in involved_datacenters:
                         involved_datacenters.append(site["datacenter"])
             sce_net2instance[sce_net_uuid] = {}
+            sce_net2wim_instance[sce_net_uuid] = {}
             net2task_id['scenario'][sce_net_uuid] = {}
 
             use_network = None
             net2task_id['scenario'][sce_net_uuid] = {}
 
             use_network = None
@@ -3299,14 +3347,39 @@ def create_instance(mydb, tenant_id, instance_dict):
                 )
                 if not target_instance_nets:
                     raise NfvoException(
                 )
                 if not target_instance_nets:
                     raise NfvoException(
-                        "Cannot find the target network at instance:networks[{}]:use-network".format(descriptor_net_name),
-                        httperrors.Bad_Request)
+                        "Cannot find the target network at instance:networks[{}]:use-network".format(
+                            descriptor_net_name), httperrors.Bad_Request)
                 else:
                     use_network = target_instance_nets[0]["related"]
 
             if sce_net["external"]:
                 number_mgmt_networks += 1
 
                 else:
                     use_network = target_instance_nets[0]["related"]
 
             if sce_net["external"]:
                 number_mgmt_networks += 1
 
+            # --> WIM
+            # TODO: use this information during network creation
+            wim_account_id = wim_account_name = None
+            if len(involved_datacenters) > 1 and 'uuid' in sce_net:
+                urls = [myvims[v].url for v in involved_datacenters]
+                if len(set(urls)) < 2:
+                    wim_usage[sce_net['uuid']] = False
+                elif target_wim_account is None or target_wim_account is True:  # automatic selection of WIM
+                    # OBS: sce_net without uuid are used internally to VNFs
+                    # and the assumption is that VNFs will not be split among
+                    # different datacenters
+                    wim_account = wim_engine.find_suitable_wim_account(
+                        involved_datacenters, tenant_id)
+                    wim_account_id = wim_account['uuid']
+                    wim_account_name = wim_account['name']
+                    wim_usage[sce_net['uuid']] = wim_account_id
+                elif isinstance(target_wim_account, str):     # manual selection of WIM
+                    wim_account.persist.get_wim_account_by(target_wim_account, tenant_id)
+                    wim_account_id = wim_account['uuid']
+                    wim_account_name = wim_account['name']
+                    wim_usage[sce_net['uuid']] = wim_account_id
+                else:  # not WIM usage
+                    wim_usage[sce_net['uuid']] = False
+            # <-- WIM
+
             for datacenter_id in involved_datacenters:
                 netmap_use = None
                 netmap_create = None
             for datacenter_id in involved_datacenters:
                 netmap_use = None
                 netmap_create = None
@@ -3380,7 +3453,9 @@ def create_instance(mydb, tenant_id, instance_dict):
                 task_extra = {}
                 if create_network:
                     task_action = "CREATE"
                 task_extra = {}
                 if create_network:
                     task_action = "CREATE"
-                    task_extra["params"] = (net_vim_name, net_type, sce_net.get('ip_profile', None), wim_account_name)
+                    task_extra["params"] = (net_vim_name, net_type, sce_net.get('ip_profile', None), False,
+                                            sce_net.get('provider_network', None), wim_account_name)
+
                     if lookfor_network:
                         task_extra["find"] = (lookfor_filter,)
                 elif lookfor_network:
                     if lookfor_network:
                         task_extra["find"] = (lookfor_filter,)
                 elif lookfor_network:
@@ -3393,6 +3468,45 @@ def create_instance(mydb, tenant_id, instance_dict):
                 sce_net2instance[sce_net_uuid][datacenter_id] = net_uuid
                 if not related_network:   # all db_instance_nets will have same related
                     related_network = use_network or net_uuid
                 sce_net2instance[sce_net_uuid][datacenter_id] = net_uuid
                 if not related_network:   # all db_instance_nets will have same related
                     related_network = use_network or net_uuid
+                sdn_net_id = None
+                sdn_controller = vim.config.get('sdn-controller')
+                sce_net2wim_instance[sce_net_uuid][datacenter_id] = None
+                if sdn_controller and net_type in ("data", "ptp"):
+                    wim_id = _get_wim(mydb, sdn_controller)
+                    sdn_net_id = str(uuid4())
+                    sce_net2wim_instance[sce_net_uuid][datacenter_id] = sdn_net_id
+                    task_extra["sdn_net_id"] = sdn_net_id
+                    db_instance_wim_nets.append({
+                        "uuid": sdn_net_id,
+                        "instance_scenario_id": instance_uuid,
+                        "sce_net_id": sce_net.get("uuid"),
+                        "wim_id": wim_id,
+                        "wim_account_id": sdn_controller,
+                        'status': 'BUILD',  # if create_network else "ACTIVE"
+                        "related": related_network,
+                        'multipoint': True if net_type=="data" else False,
+                        "created": create_network, # TODO py3
+                        "sdn": True,
+                    })
+
+                    task_wim_extra = {"params": [net_type, wim_account_name]}
+                    # add sdn interfaces
+                    if sce_net.get('provider_network') and sce_net['provider_network'].get("sdn-ports"):
+                        task_wim_extra["sdn-ports"] = sce_net['provider_network'].get("sdn-ports")
+                    db_vim_action = {
+                        "instance_action_id": instance_action_id,
+                        "status": "SCHEDULED",
+                        "task_index": task_index,
+                        # "datacenter_vim_id": myvim_thread_id,
+                        "wim_account_id": sdn_controller,
+                        "action": task_action,
+                        "item": "instance_wim_nets",
+                        "item_id": sdn_net_id,
+                        "related": related_network,
+                        "extra": yaml.safe_dump(task_wim_extra, default_flow_style=True, width=256)
+                    }
+                    task_index += 1
+                    db_vim_actions.append(db_vim_action)
                 db_net = {
                     "uuid": net_uuid,
                     "osm_id": sce_net.get("osm_id") or sce_net["name"],
                 db_net = {
                     "uuid": net_uuid,
                     "osm_id": sce_net.get("osm_id") or sce_net["name"],
@@ -3404,7 +3518,8 @@ def create_instance(mydb, tenant_id, instance_dict):
                     "created": create_network,
                     'datacenter_id': datacenter_id,
                     'datacenter_tenant_id': myvim_thread_id,
                     "created": create_network,
                     'datacenter_id': datacenter_id,
                     'datacenter_tenant_id': myvim_thread_id,
-                    'status': 'BUILD' #  if create_network else "ACTIVE"
+                    'status': 'BUILD', #  if create_network else "ACTIVE"
+                    'sdn_net_id': sdn_net_id,
                 }
                 db_instance_nets.append(db_net)
                 db_vim_action = {
                 }
                 db_instance_nets.append(db_net)
                 db_vim_action = {
@@ -3451,6 +3566,7 @@ def create_instance(mydb, tenant_id, instance_dict):
             "task_index": task_index,
             "uuid_list": uuid_list,
             "db_instance_nets": db_instance_nets,
             "task_index": task_index,
             "uuid_list": uuid_list,
             "db_instance_nets": db_instance_nets,
+            "db_instance_wim_nets": db_instance_wim_nets,
             "db_vim_actions": db_vim_actions,
             "db_ip_profiles": db_ip_profiles,
             "db_instance_vnfs": db_instance_vnfs,
             "db_vim_actions": db_vim_actions,
             "db_ip_profiles": db_ip_profiles,
             "db_instance_vnfs": db_instance_vnfs,
@@ -3458,6 +3574,7 @@ def create_instance(mydb, tenant_id, instance_dict):
             "db_instance_interfaces": db_instance_interfaces,
             "net2task_id": net2task_id,
             "sce_net2instance": sce_net2instance,
             "db_instance_interfaces": db_instance_interfaces,
             "net2task_id": net2task_id,
             "sce_net2instance": sce_net2instance,
+            "sce_net2wim_instance": sce_net2wim_instance,
         }
         # sce_vnf_list = sorted(scenarioDict['vnfs'], key=lambda k: k['name'])
         for sce_vnf in scenarioDict.get('vnfs', ()):  # sce_vnf_list:
         }
         # sce_vnf_list = sorted(scenarioDict['vnfs'], key=lambda k: k['name'])
         for sce_vnf in scenarioDict.get('vnfs', ()):  # sce_vnf_list:
@@ -3584,7 +3701,8 @@ def create_instance(mydb, tenant_id, instance_dict):
                             "source_ip": match["source_ip"],
                             "destination_ip": match["destination_ip"],
                             "source_port": match["source_port"],
                             "source_ip": match["source_ip"],
                             "destination_ip": match["destination_ip"],
                             "source_port": match["source_port"],
-                            "destination_port": match["destination_port"]
+                            "destination_port": match["destination_port"],
+                            "logical_source_port": classifier["interface_id"]
                         }
                         db_vim_action = {
                             "instance_action_id": instance_action_id,
                         }
                         db_vim_action = {
                             "instance_action_id": instance_action_id,
@@ -3655,7 +3773,7 @@ def create_instance(mydb, tenant_id, instance_dict):
             {"instance_sfs": db_instance_sfs},
             {"instance_classifications": db_instance_classifications},
             {"instance_sfps": db_instance_sfps},
             {"instance_sfs": db_instance_sfs},
             {"instance_classifications": db_instance_classifications},
             {"instance_sfps": db_instance_sfps},
-            {"instance_wim_nets": wan_links},
+            {"instance_wim_nets": db_instance_wim_nets + wan_links},
             {"vim_wim_actions": db_vim_actions + wim_actions}
         ]
 
             {"vim_wim_actions": db_vim_actions + wim_actions}
         ]
 
@@ -3670,21 +3788,40 @@ def create_instance(mydb, tenant_id, instance_dict):
         returned_instance = mydb.get_instance_scenario(instance_uuid)
         returned_instance["action_id"] = instance_action_id
         return returned_instance
         returned_instance = mydb.get_instance_scenario(instance_uuid)
         returned_instance["action_id"] = instance_action_id
         return returned_instance
-    except (NfvoException, vimconn.vimconnException, wimconn.WimConnectorError, db_base_Exception) as e:
-        message = rollback(mydb, myvims, rollbackList)
+    except (NfvoException, vimconn.VimConnException, sdnconn.SdnConnectorError, db_base_Exception) as e:
+        _, message = rollback(mydb, myvims, rollbackList)
         if isinstance(e, db_base_Exception):
             error_text = "database Exception"
         if isinstance(e, db_base_Exception):
             error_text = "database Exception"
-        elif isinstance(e, vimconn.vimconnException):
+        elif isinstance(e, vimconn.VimConnException):
             error_text = "VIM Exception"
             error_text = "VIM Exception"
-        elif isinstance(e, wimconn.WimConnectorError):
+        elif isinstance(e, sdnconn.SdnConnectorError):
             error_text = "WIM Exception"
         else:
             error_text = "WIM Exception"
         else:
-            error_text = "Exception"
-        error_text += " {} {}. {}".format(type(e).__name__, str(e), message)
+            error_text = "Exception " + str(type(e).__name__)
+        error_text += " {}. {}".format(e, message)
         # logger.error("create_instance: %s", error_text)
         logger.exception(e)
         raise NfvoException(error_text, e.http_code)
 
         # logger.error("create_instance: %s", error_text)
         logger.exception(e)
         raise NfvoException(error_text, e.http_code)
 
+def increment_ip_mac(ip_mac, vm_index=1):
+    if not isinstance(ip_mac, str):
+        return ip_mac
+    try:
+        # try with ipv4 look for last dot
+        i = ip_mac.rfind(".")
+        if i > 0:
+            i += 1
+            return "{}{}".format(ip_mac[:i], int(ip_mac[i:]) + vm_index)
+        # try with ipv6 or mac look for last colon. Operate in hex
+        i = ip_mac.rfind(":")
+        if i > 0:
+            i += 1
+            # format in hex, len can be 2 for mac or 4 for ipv6
+            return ("{}{:0" + str(len(ip_mac) - i) + "x}").format(ip_mac[:i], int(ip_mac[i:], 16) + vm_index)
+    except:
+        pass
+    return None
+
 
 def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
     default_datacenter_id = params["default_datacenter_id"]
 
 def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
     default_datacenter_id = params["default_datacenter_id"]
@@ -3699,6 +3836,7 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
     task_index = params_out["task_index"]
     uuid_list = params_out["uuid_list"]
     db_instance_nets = params_out["db_instance_nets"]
     task_index = params_out["task_index"]
     uuid_list = params_out["uuid_list"]
     db_instance_nets = params_out["db_instance_nets"]
+    db_instance_wim_nets = params_out["db_instance_wim_nets"]
     db_vim_actions = params_out["db_vim_actions"]
     db_ip_profiles = params_out["db_ip_profiles"]
     db_instance_vnfs = params_out["db_instance_vnfs"]
     db_vim_actions = params_out["db_vim_actions"]
     db_ip_profiles = params_out["db_ip_profiles"]
     db_instance_vnfs = params_out["db_instance_vnfs"]
@@ -3706,15 +3844,19 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
     db_instance_interfaces = params_out["db_instance_interfaces"]
     net2task_id = params_out["net2task_id"]
     sce_net2instance = params_out["sce_net2instance"]
     db_instance_interfaces = params_out["db_instance_interfaces"]
     net2task_id = params_out["net2task_id"]
     sce_net2instance = params_out["sce_net2instance"]
+    sce_net2wim_instance = params_out["sce_net2wim_instance"]
 
     vnf_net2instance = {}
 
     vnf_net2instance = {}
+    vnf_net2wim_instance = {}
 
     # 2. Creating new nets (vnf internal nets) in the VIM"
     # For each vnf net, we create it and we add it to instanceNetlist.
     if sce_vnf.get("datacenter"):
 
     # 2. Creating new nets (vnf internal nets) in the VIM"
     # For each vnf net, we create it and we add it to instanceNetlist.
     if sce_vnf.get("datacenter"):
+        vim = myvims[sce_vnf["datacenter"]]
         datacenter_id = sce_vnf["datacenter"]
         myvim_thread_id = myvim_threads_id[sce_vnf["datacenter"]]
     else:
         datacenter_id = sce_vnf["datacenter"]
         myvim_thread_id = myvim_threads_id[sce_vnf["datacenter"]]
     else:
+        vim = myvims[default_datacenter_id]
         datacenter_id = default_datacenter_id
         myvim_thread_id = myvim_threads_id[default_datacenter_id]
     for net in sce_vnf['nets']:
         datacenter_id = default_datacenter_id
         myvim_thread_id = myvim_threads_id[default_datacenter_id]
     for net in sce_vnf['nets']:
@@ -3731,12 +3873,30 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
             vnf_net2instance[sce_vnf['uuid']] = {}
         if sce_vnf['uuid'] not in net2task_id:
             net2task_id[sce_vnf['uuid']] = {}
             vnf_net2instance[sce_vnf['uuid']] = {}
         if sce_vnf['uuid'] not in net2task_id:
             net2task_id[sce_vnf['uuid']] = {}
-        net2task_id[sce_vnf['uuid']][net['uuid']] = task_index
 
         # fill database content
         net_uuid = str(uuid4())
         uuid_list.append(net_uuid)
         vnf_net2instance[sce_vnf['uuid']][net['uuid']] = net_uuid
 
         # fill database content
         net_uuid = str(uuid4())
         uuid_list.append(net_uuid)
         vnf_net2instance[sce_vnf['uuid']][net['uuid']] = net_uuid
+
+        sdn_controller = vim.config.get('sdn-controller')
+        sdn_net_id = None
+        if sdn_controller and net_type in ("data", "ptp"):
+            wim_id = _get_wim(mydb, sdn_controller)
+            sdn_net_id = str(uuid4())
+            db_instance_wim_nets.append({
+                "uuid": sdn_net_id,
+                "instance_scenario_id": instance_uuid,
+                "wim_id": wim_id,
+                "wim_account_id": sdn_controller,
+                'status': 'BUILD',  # if create_network else "ACTIVE"
+                "related": net_uuid,
+                'multipoint': True if net_type == "data" else False,
+                "created": True,  # TODO py3
+                "sdn": True,
+            })
+            vnf_net2wim_instance[net_uuid] = sdn_net_id
+
         db_net = {
             "uuid": net_uuid,
             "related": net_uuid,
         db_net = {
             "uuid": net_uuid,
             "related": net_uuid,
@@ -3747,6 +3907,7 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
             "created": True,
             'datacenter_id': datacenter_id,
             'datacenter_tenant_id': myvim_thread_id,
             "created": True,
             'datacenter_id': datacenter_id,
             'datacenter_tenant_id': myvim_thread_id,
+            'sdn_net_id': sdn_net_id,
         }
         db_instance_nets.append(db_net)
 
         }
         db_instance_nets.append(db_net)
 
@@ -3761,7 +3922,25 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
         else:
             task_action = "CREATE"
             task_extra = {"params": (net_name, net_type, net.get('ip_profile', None))}
         else:
             task_action = "CREATE"
             task_extra = {"params": (net_name, net_type, net.get('ip_profile', None))}
+        if sdn_net_id:
+            task_extra["sdn_net_id"] = sdn_net_id
 
 
+        if sdn_net_id:
+            task_wim_extra = {"params": [net_type, None]}
+            db_vim_action = {
+                "instance_action_id": instance_action_id,
+                "status": "SCHEDULED",
+                "task_index": task_index,
+                # "datacenter_vim_id": myvim_thread_id,
+                "wim_account_id": sdn_controller,
+                "action": task_action,
+                "item": "instance_wim_nets",
+                "item_id": sdn_net_id,
+                "related": net_uuid,
+                "extra": yaml.safe_dump(task_wim_extra, default_flow_style=True, width=256)
+            }
+            task_index += 1
+            db_vim_actions.append(db_vim_action)
         db_vim_action = {
             "instance_action_id": instance_action_id,
             "task_index": task_index,
         db_vim_action = {
             "instance_action_id": instance_action_id,
             "task_index": task_index,
@@ -3773,6 +3952,7 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
             "related": net_uuid,
             "extra": yaml.safe_dump(task_extra, default_flow_style=True, width=256)
         }
             "related": net_uuid,
             "extra": yaml.safe_dump(task_extra, default_flow_style=True, width=256)
         }
+        net2task_id[sce_vnf['uuid']][net['uuid']] = task_index
         task_index += 1
         db_vim_actions.append(db_vim_action)
 
         task_index += 1
         db_vim_actions.append(db_vim_action)
 
@@ -3946,11 +4126,13 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
                         netDict['net_id'] = "TASK-{}".format(
                             net2task_id['scenario'][vnf_iface['sce_net_id']][datacenter_id])
                         instance_net_id = sce_net2instance[vnf_iface['sce_net_id']][datacenter_id]
                         netDict['net_id'] = "TASK-{}".format(
                             net2task_id['scenario'][vnf_iface['sce_net_id']][datacenter_id])
                         instance_net_id = sce_net2instance[vnf_iface['sce_net_id']][datacenter_id]
+                        instance_wim_net_id = sce_net2wim_instance[vnf_iface['sce_net_id']][datacenter_id]
                         task_depends_on.append(net2task_id['scenario'][vnf_iface['sce_net_id']][datacenter_id])
                         break
             else:
                 netDict['net_id'] = "TASK-{}".format(net2task_id[sce_vnf['uuid']][iface['net_id']])
                 instance_net_id = vnf_net2instance[sce_vnf['uuid']][iface['net_id']]
                         task_depends_on.append(net2task_id['scenario'][vnf_iface['sce_net_id']][datacenter_id])
                         break
             else:
                 netDict['net_id'] = "TASK-{}".format(net2task_id[sce_vnf['uuid']][iface['net_id']])
                 instance_net_id = vnf_net2instance[sce_vnf['uuid']][iface['net_id']]
+                instance_wim_net_id = vnf_net2wim_instance.get(instance_net_id)
                 task_depends_on.append(net2task_id[sce_vnf['uuid']][iface['net_id']])
             # skip bridge ifaces not connected to any net
             if 'net_id' not in netDict or netDict['net_id'] == None:
                 task_depends_on.append(net2task_id[sce_vnf['uuid']][iface['net_id']])
             # skip bridge ifaces not connected to any net
             if 'net_id' not in netDict or netDict['net_id'] == None:
@@ -3960,9 +4142,11 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
                 # "uuid"
                 # 'instance_vm_id': instance_vm_uuid,
                 "instance_net_id": instance_net_id,
                 # "uuid"
                 # 'instance_vm_id': instance_vm_uuid,
                 "instance_net_id": instance_net_id,
+                "instance_wim_net_id": instance_wim_net_id,
                 'interface_id': iface['uuid'],
                 # 'vim_interface_id': ,
                 'type': 'external' if iface['external_name'] is not None else 'internal',
                 'interface_id': iface['uuid'],
                 # 'vim_interface_id': ,
                 'type': 'external' if iface['external_name'] is not None else 'internal',
+                'model': iface['model'],
                 'ip_address': iface.get('ip_address'),
                 'mac_address': iface.get('mac'),
                 'floating_ip': int(iface.get('floating-ip', False)),
                 'ip_address': iface.get('ip_address'),
                 'mac_address': iface.get('mac'),
                 'floating_ip': int(iface.get('floating-ip', False)),
@@ -3996,16 +4180,11 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
             av_index = None
         for vm_index in range(0, vm.get('count', 1)):
             vm_name = myVMDict['name'] + "-" + str(vm_index+1)
             av_index = None
         for vm_index in range(0, vm.get('count', 1)):
             vm_name = myVMDict['name'] + "-" + str(vm_index+1)
+            vm_networks = deepcopy(myVMDict['networks'])
             task_params = (vm_name, myVMDict['description'], myVMDict.get('start', None),
             task_params = (vm_name, myVMDict['description'], myVMDict.get('start', None),
-                           myVMDict['imageRef'], myVMDict['flavorRef'], myVMDict['networks'], cloud_config_vm,
+                           myVMDict['imageRef'], myVMDict['flavorRef'], vm_networks, cloud_config_vm,
                            myVMDict['disks'], av_index, vnf_availability_zones)
                            myVMDict['disks'], av_index, vnf_availability_zones)
-            # put interface uuid back to scenario[vnfs][vms[[interfaces]
-            for net in myVMDict['networks']:
-                if "vim_id" in net:
-                    for iface in vm['interfaces']:
-                        if net["name"] == iface["internal_name"]:
-                            iface["vim_id"] = net["vim_id"]
-                            break
+
             vm_uuid = str(uuid4())
             uuid_list.append(vm_uuid)
             db_vm = {
             vm_uuid = str(uuid4())
             uuid_list.append(vm_uuid)
             db_vm = {
@@ -4019,28 +4198,32 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList):
             }
             db_instance_vms.append(db_vm)
 
             }
             db_instance_vms.append(db_vm)
 
-            iface_index = 0
-            for db_vm_iface in db_vm_ifaces:
+            # put interface uuid back to scenario[vnfs][vms[[interfaces]
+            for net in vm_networks:
+                if "vim_id" in net:
+                    for iface in vm['interfaces']:
+                        if net["name"] == iface["internal_name"]:
+                            iface["vim_id"] = net["vim_id"]
+                            break
+
+                if vm_index > 0:
+                    if net.get("ip_address"):
+                        net["ip_address"] = increment_ip_mac(net.get("ip_address"), vm_index)
+                    if net.get("mac_address"):
+                        net["mac_address"] = increment_ip_mac(net.get("mac_address"), vm_index)
+
+            for iface_index, db_vm_iface in enumerate(db_vm_ifaces):
                 iface_uuid = str(uuid4())
                 uuid_list.append(iface_uuid)
                 db_vm_iface_instance = {
                     "uuid": iface_uuid,
                 iface_uuid = str(uuid4())
                 uuid_list.append(iface_uuid)
                 db_vm_iface_instance = {
                     "uuid": iface_uuid,
-                    "instance_vm_id": vm_uuid
+                    "instance_vm_id": vm_uuid,
+                    "ip_address": vm_networks[iface_index].get("ip_address"),
+                    "mac_address": vm_networks[iface_index].get("mac_address")
                 }
                 db_vm_iface_instance.update(db_vm_iface)
                 }
                 db_vm_iface_instance.update(db_vm_iface)
-                if db_vm_iface_instance.get("ip_address"):  # increment ip_address
-                    ip = db_vm_iface_instance.get("ip_address")
-                    i = ip.rfind(".")
-                    if i > 0:
-                        try:
-                            i += 1
-                            ip = ip[i:] + str(int(ip[:i]) + 1)
-                            db_vm_iface_instance["ip_address"] = ip
-                        except:
-                            db_vm_iface_instance["ip_address"] = None
                 db_instance_interfaces.append(db_vm_iface_instance)
                 db_instance_interfaces.append(db_vm_iface_instance)
-                myVMDict['networks'][iface_index]["uuid"] = iface_uuid
-                iface_index += 1
+                vm_networks[iface_index]["uuid"] = iface_uuid
 
             db_vim_action = {
                 "instance_action_id": instance_action_id,
 
             db_vim_action = {
                 "instance_action_id": instance_action_id,
@@ -4349,6 +4532,23 @@ def delete_instance(mydb, tenant_id, instance_id):
         }
         task_index += 1
         db_vim_actions.append(db_vim_action)
         }
         task_index += 1
         db_vim_actions.append(db_vim_action)
+    for sdn_net in instanceDict['sdn_nets']:
+        if not sdn_net["sdn"]:
+            continue
+        extra = {}
+        db_vim_action = {
+            "instance_action_id": instance_action_id,
+            "task_index": task_index,
+            "wim_account_id": sdn_net["wim_account_id"],
+            "action": "DELETE",
+            "status": "SCHEDULED",
+            "item": "instance_wim_nets",
+            "item_id": sdn_net["uuid"],
+            "related": sdn_net["related"],
+            "extra": yaml.safe_dump(extra, default_flow_style=True, width=256)
+        }
+        task_index += 1
+        db_vim_actions.append(db_vim_action)
 
     db_instance_action["number_tasks"] = task_index
 
 
     db_instance_action["number_tasks"] = task_index
 
@@ -4383,18 +4583,19 @@ def get_instance_id(mydb, tenant_id, instance_id):
     #obtain data
 
     instance_dict = mydb.get_instance_scenario(instance_id, tenant_id, verbose=True)
     #obtain data
 
     instance_dict = mydb.get_instance_scenario(instance_id, tenant_id, verbose=True)
-    for net in instance_dict["nets"]:
-        if net.get("sdn_net_id"):
-            net_sdn = ovim.show_network(net["sdn_net_id"])
-            net["sdn_info"] = {
-                "admin_state_up": net_sdn.get("admin_state_up"),
-                "flows": net_sdn.get("flows"),
-                "last_error": net_sdn.get("last_error"),
-                "ports": net_sdn.get("ports"),
-                "type": net_sdn.get("type"),
-                "status": net_sdn.get("status"),
-                "vlan": net_sdn.get("vlan"),
-            }
+    # TODO py3
+    # for net in instance_dict["nets"]:
+    #     if net.get("sdn_net_id"):
+    #         net_sdn = ovim.show_network(net["sdn_net_id"])
+    #         net["sdn_info"] = {
+    #             "admin_state_up": net_sdn.get("admin_state_up"),
+    #             "flows": net_sdn.get("flows"),
+    #             "last_error": net_sdn.get("last_error"),
+    #             "ports": net_sdn.get("ports"),
+    #             "type": net_sdn.get("type"),
+    #             "status": net_sdn.get("status"),
+    #             "vlan": net_sdn.get("vlan"),
+    #         }
     return instance_dict
 
 @deprecated("Instance is automatically refreshed by vim_threads")
     return instance_dict
 
 @deprecated("Instance is automatically refreshed by vim_threads")
@@ -4463,7 +4664,7 @@ def refresh_instance(mydb, nfvo_tenant, instanceDict, datacenter=None, vim_tenan
     #         try:
     #             vm_dict.update(myvims[datacenter_key].refresh_vms_status(vm_list[datacenter_key]) )
     #             failed = False
     #         try:
     #             vm_dict.update(myvims[datacenter_key].refresh_vms_status(vm_list[datacenter_key]) )
     #             failed = False
-    #         except vimconn.vimconnException as e:
+    #         except vimconn.VimConnException as e:
     #             logger.error("VIM exception %s %s", type(e).__name__, str(e))
     #             failed_message = str(e)
     #     if failed:
     #             logger.error("VIM exception %s %s", type(e).__name__, str(e))
     #             failed_message = str(e)
     #     if failed:
@@ -4525,7 +4726,7 @@ def refresh_instance(mydb, nfvo_tenant, instanceDict, datacenter=None, vim_tenan
     #         try:
     #             net_dict.update(myvims[datacenter_key].refresh_nets_status(net_list[datacenter_key]) )
     #             failed = False
     #         try:
     #             net_dict.update(myvims[datacenter_key].refresh_nets_status(net_list[datacenter_key]) )
     #             failed = False
-    #         except vimconn.vimconnException as e:
+    #         except vimconn.VimConnException as e:
     #             logger.error("VIM exception %s %s", type(e).__name__, str(e))
     #             failed_message = str(e)
     #     if failed:
     #             logger.error("VIM exception %s %s", type(e).__name__, str(e))
     #             failed_message = str(e)
     #     if failed:
@@ -4649,6 +4850,16 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict):
                         "extra": yaml.safe_dump({"params": vm_interfaces},
                                                 default_flow_style=True, width=256)
                     }
                         "extra": yaml.safe_dump({"params": vm_interfaces},
                                                 default_flow_style=True, width=256)
                     }
+                    # get affected instance_interfaces (deleted on cascade) to check if a wim_network must be updated
+                    deleted_interfaces = mydb.get_rows(
+                        SELECT=("instance_wim_net_id", ),
+                        FROM="instance_interfaces",
+                        WHERE={"instance_vm_id": vdu_id, "instance_wim_net_id<>": None},
+                    )
+                    for deleted_interface in deleted_interfaces:
+                        db_vim_actions.append({"TO-UPDATE": {}, "WHERE": {
+                            "item": "instance_wim_nets", "item_id": deleted_interface["instance_wim_net_id"]}})
+
                     task_index += 1
                     db_vim_actions.append(db_vim_action)
                     vm_result["deleted"].append(vdu_id)
                     task_index += 1
                     db_vim_actions.append(db_vim_action)
                     vm_result["deleted"].append(vdu_id)
@@ -4669,7 +4880,6 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict):
                 # TODO do the same for flavor and image when available
                 task_depends_on = []
                 task_params = extra["params"]
                 # TODO do the same for flavor and image when available
                 task_depends_on = []
                 task_params = extra["params"]
-                task_params_networks = deepcopy(task_params[5])
                 for iface in task_params[5]:
                     if iface["net_id"].startswith("TASK-"):
                         if "." not in iface["net_id"]:
                 for iface in task_params[5]:
                     if iface["net_id"].startswith("TASK-"):
                         if "." not in iface["net_id"]:
@@ -4679,8 +4889,6 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict):
                                                                   iface["net_id"][5:])
                         else:
                             task_depends_on.append(iface["net_id"][5:])
                                                                   iface["net_id"][5:])
                         else:
                             task_depends_on.append(iface["net_id"][5:])
-                    if "mac_address" in iface:
-                        del iface["mac_address"]
 
                 vm_ifaces_to_clone = mydb.get_rows(FROM="instance_interfaces", WHERE={"instance_vm_id": target_vm["uuid"]})
                 for index in range(0, vdu_count):
 
                 vm_ifaces_to_clone = mydb.get_rows(FROM="instance_interfaces", WHERE={"instance_vm_id": target_vm["uuid"]})
                 for index in range(0, vdu_count):
@@ -4707,26 +4915,26 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict):
                             "uuid": iface_uuid,
                             'instance_vm_id': vm_uuid,
                             "instance_net_id": vm_iface["instance_net_id"],
                             "uuid": iface_uuid,
                             'instance_vm_id': vm_uuid,
                             "instance_net_id": vm_iface["instance_net_id"],
+                            "instance_wim_net_id": vm_iface["instance_wim_net_id"],
                             'interface_id': vm_iface['interface_id'],
                             'type': vm_iface['type'],
                             'interface_id': vm_iface['interface_id'],
                             'type': vm_iface['type'],
+                            'model': vm_iface['model'],
                             'floating_ip': vm_iface['floating_ip'],
                             'port_security': vm_iface['port_security']
                         }
                         db_instance_interfaces.append(db_vm_iface)
                             'floating_ip': vm_iface['floating_ip'],
                             'port_security': vm_iface['port_security']
                         }
                         db_instance_interfaces.append(db_vm_iface)
+                        if db_vm_iface["instance_wim_net_id"]:
+                            db_vim_actions.append({"TO-UPDATE": {}, "WHERE": {
+                                "item": "instance_wim_nets", "item_id": db_vm_iface["instance_wim_net_id"]}})
                     task_params_copy = deepcopy(task_params)
                     for iface in task_params_copy[5]:
                         iface["uuid"] = iface2iface[iface["uuid"]]
                         # increment ip_address
                     task_params_copy = deepcopy(task_params)
                     for iface in task_params_copy[5]:
                         iface["uuid"] = iface2iface[iface["uuid"]]
                         # increment ip_address
-                        if "ip_address" in iface:
-                            ip = iface.get("ip_address")
-                            i = ip.rfind(".")
-                            if i > 0:
-                                try:
-                                    i += 1
-                                    ip = ip[i:] + str(int(ip[:i]) + 1)
-                                    iface["ip_address"] = ip
-                                except:
-                                    iface["ip_address"] = None
+                        if iface.get("ip_address"):
+                            iface["ip_address"] = increment_ip_mac(iface.get("ip_address"), index+1)
+                        if iface.get("mac_address"):
+                            iface["mac_address"] = increment_ip_mac(iface.get("mac_address"), index+1)
+
                     if vm_name:
                         task_params_copy[0] = vm_name
                     db_vim_action = {
                     if vm_name:
                         task_params_copy[0] = vm_name
                     db_vim_action = {
@@ -4800,10 +5008,9 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict):
                                                           action_dict['add_public_key'],
                                                           password=password, ro_key=priv_RO_key)
                                     vm_result[ vm['uuid'] ] = {"vim_result": 200,
                                                           action_dict['add_public_key'],
                                                           password=password, ro_key=priv_RO_key)
                                     vm_result[ vm['uuid'] ] = {"vim_result": 200,
-                                                       "description": "Public key injected",
-                                                       "name":vm['name']
+                                                    "description": "Public key injected",
+                                                    "name":vm['name']
                                                     }
                                                     }
-
                         except KeyError:
                             raise NfvoException("Unable to inject ssh key in vm: {} - Aborting".format(vm['uuid']),
                                                 httperrors.Internal_Server_Error)
                         except KeyError:
                             raise NfvoException("Unable to inject ssh key in vm: {} - Aborting".format(vm['uuid']),
                                                 httperrors.Internal_Server_Error)
@@ -4849,7 +5056,7 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict):
                     else:
                         vm_result[ vm['uuid'] ] = {"vim_result": 200, "description": "ok", "name":vm['name']}
                         vm_ok +=1
                     else:
                         vm_result[ vm['uuid'] ] = {"vim_result": 200, "description": "ok", "name":vm['name']}
                         vm_ok +=1
-            except vimconn.vimconnException as e:
+            except vimconn.VimConnException as e:
                 vm_result[ vm['uuid'] ] = {"vim_result": e.http_code, "name":vm['name'], "description": str(e)}
                 vm_error+=1
 
                 vm_result[ vm['uuid'] ] = {"vim_result": e.http_code, "name":vm['name'], "description": str(e)}
                 vm_error+=1
 
@@ -4940,10 +5147,19 @@ def new_datacenter(mydb, datacenter_descriptor):
     datacenter_type = datacenter_descriptor.get("type", "openvim");
     # module_info = None
 
     datacenter_type = datacenter_descriptor.get("type", "openvim");
     # module_info = None
 
+    for url_field in ('vim_url', 'vim_url_admin'):
+        # It is common that users copy and paste the URL from the VIM website
+        # (example OpenStack), therefore a common mistake is to include blank
+        # characters at the end of the URL. Let's remove it and just in case,
+        # lets remove trailing slash as well.
+        url = datacenter_descriptor.get(url_field)
+        if url:
+            datacenter_descriptor[url_field] = url.strip(string.whitespace + '/')
+
     # load plugin
     plugin_name = "rovim_" + datacenter_type
     if plugin_name not in plugins:
     # load plugin
     plugin_name = "rovim_" + datacenter_type
     if plugin_name not in plugins:
-        _load_vim_plugin(plugin_name)
+        _load_plugin(plugin_name, type="vim")
 
     datacenter_id = mydb.new_row("datacenters", datacenter_descriptor, add_uuid=True, confidential_data=True)
     if sdn_port_mapping:
 
     datacenter_id = mydb.new_row("datacenters", datacenter_descriptor, add_uuid=True, confidential_data=True)
     if sdn_port_mapping:
@@ -5023,56 +5239,60 @@ def delete_datacenter(mydb, datacenter):
 
 def create_vim_account(mydb, nfvo_tenant, datacenter_id, name=None, vim_id=None, vim_tenant=None, vim_tenant_name=None,
                        vim_username=None, vim_password=None, config=None):
 
 def create_vim_account(mydb, nfvo_tenant, datacenter_id, name=None, vim_id=None, vim_tenant=None, vim_tenant_name=None,
                        vim_username=None, vim_password=None, config=None):
+    global plugins
     # get datacenter info
     try:
         if not datacenter_id:
             if not vim_id:
                 raise NfvoException("You must provide 'vim_id", http_code=httperrors.Bad_Request)
             datacenter_id = vim_id
     # get datacenter info
     try:
         if not datacenter_id:
             if not vim_id:
                 raise NfvoException("You must provide 'vim_id", http_code=httperrors.Bad_Request)
             datacenter_id = vim_id
-        datacenter_id, datacenter_name = get_datacenter_uuid(mydb, None, datacenter_id)
+        datacenter_id, datacenter = get_datacenter_uuid(mydb, None, datacenter_id)
+        datacenter_name = datacenter["name"]
+        datacenter_type = datacenter["type"]
 
         create_vim_tenant = True if not vim_tenant and not vim_tenant_name else False
 
         # get nfvo_tenant info
         tenant_dict = mydb.get_table_by_uuid_name('nfvo_tenants', nfvo_tenant)
 
         create_vim_tenant = True if not vim_tenant and not vim_tenant_name else False
 
         # get nfvo_tenant info
         tenant_dict = mydb.get_table_by_uuid_name('nfvo_tenants', nfvo_tenant)
-        if vim_tenant_name==None:
-            vim_tenant_name=tenant_dict['name']
+        if vim_tenant_name is None:
+            vim_tenant_name = tenant_dict['name']
 
 
-        tenants_datacenter_dict={"nfvo_tenant_id":tenant_dict['uuid'], "datacenter_id":datacenter_id }
+        tenants_datacenter_dict = {"nfvo_tenant_id": tenant_dict['uuid'], "datacenter_id": datacenter_id}
         # #check that this association does not exist before
         # tenants_datacenters = mydb.get_rows(FROM='tenants_datacenters', WHERE=tenants_datacenter_dict)
         # if len(tenants_datacenters)>0:
         # #check that this association does not exist before
         # tenants_datacenters = mydb.get_rows(FROM='tenants_datacenters', WHERE=tenants_datacenter_dict)
         # if len(tenants_datacenters)>0:
-        #     raise NfvoException("datacenter '{}' and tenant'{}' are already attached".format(datacenter_id, tenant_dict['uuid']), httperrors.Conflict)
+        #     raise NfvoException("datacenter '{}' and tenant'{}' are already attached".format(
+        #                         datacenter_id, tenant_dict['uuid']), httperrors.Conflict)
 
 
-        vim_tenant_id_exist_atdb=False
+        vim_tenant_id_exist_atdb = False
         if not create_vim_tenant:
             where_={"datacenter_id": datacenter_id}
         if not create_vim_tenant:
             where_={"datacenter_id": datacenter_id}
-            if vim_tenant!=None:
+            if vim_tenant is not None:
                 where_["vim_tenant_id"] = vim_tenant
                 where_["vim_tenant_id"] = vim_tenant
-            if vim_tenant_name!=None:
+            if vim_tenant_name is not None:
                 where_["vim_tenant_name"] = vim_tenant_name
                 where_["vim_tenant_name"] = vim_tenant_name
-            #check if vim_tenant_id is already at database
+            # check if vim_tenant_id is already at database
             datacenter_tenants_dict = mydb.get_rows(FROM='datacenter_tenants', WHERE=where_)
             datacenter_tenants_dict = mydb.get_rows(FROM='datacenter_tenants', WHERE=where_)
-            if len(datacenter_tenants_dict)>=1:
+            if len(datacenter_tenants_dict) >= 1:
                 datacenter_tenants_dict = datacenter_tenants_dict[0]
                 datacenter_tenants_dict = datacenter_tenants_dict[0]
-                vim_tenant_id_exist_atdb=True
-                #TODO check if a field has changed and edit entry at datacenter_tenants at DB
-            else: #result=0
+                vim_tenant_id_exist_atdb = True
+                # TODO check if a field has changed and edit entry at datacenter_tenants at DB
+            else:  # result=0
                 datacenter_tenants_dict = {}
                 datacenter_tenants_dict = {}
-                #insert at table datacenter_tenants
-        else: #if vim_tenant==None:
-            #create tenant at VIM if not provided
+                # insert at table datacenter_tenants
+        else:  # if vim_tenant==None:
+            # create tenant at VIM if not provided
             try:
             try:
-                _, myvim = get_datacenter_by_name_uuid(mydb, None, datacenter, vim_user=vim_username,
-                                                                   vim_passwd=vim_password)
+                _, myvim = get_datacenter_by_name_uuid(mydb, None, datacenter_id, vim_user=vim_username,
+                                                       vim_passwd=vim_password)
                 datacenter_name = myvim["name"]
                 vim_tenant = myvim.new_tenant(vim_tenant_name, "created by openmano for datacenter "+datacenter_name)
                 datacenter_name = myvim["name"]
                 vim_tenant = myvim.new_tenant(vim_tenant_name, "created by openmano for datacenter "+datacenter_name)
-            except vimconn.vimconnException as e:
-                raise NfvoException("Not possible to create vim_tenant {} at VIM: {}".format(vim_tenant_id, str(e)), httperrors.Internal_Server_Error)
-            datacenter_tenants_dict = {}
-            datacenter_tenants_dict["created"]="true"
+            except vimconn.VimConnException as e:
+                raise NfvoException("Not possible to create vim_tenant {} at VIM: {}".format(vim_tenant_name, e),
+                                    httperrors.Internal_Server_Error)
+            datacenter_tenants_dict = {"created": "true"}
 
 
-        #fill datacenter_tenants table
+        # fill datacenter_tenants table
         if not vim_tenant_id_exist_atdb:
             datacenter_tenants_dict["vim_tenant_id"] = vim_tenant
             datacenter_tenants_dict["vim_tenant_name"] = vim_tenant_name
         if not vim_tenant_id_exist_atdb:
             datacenter_tenants_dict["vim_tenant_id"] = vim_tenant
             datacenter_tenants_dict["vim_tenant_name"] = vim_tenant_name
@@ -5088,20 +5308,22 @@ def create_vim_account(mydb, nfvo_tenant, datacenter_id, name=None, vim_id=None,
             id_ = mydb.new_row('datacenter_tenants', datacenter_tenants_dict, add_uuid=True, confidential_data=True)
             datacenter_tenants_dict["uuid"] = id_
 
             id_ = mydb.new_row('datacenter_tenants', datacenter_tenants_dict, add_uuid=True, confidential_data=True)
             datacenter_tenants_dict["uuid"] = id_
 
-        #fill tenants_datacenters table
+        # fill tenants_datacenters table
         datacenter_tenant_id = datacenter_tenants_dict["uuid"]
         tenants_datacenter_dict["datacenter_tenant_id"] = datacenter_tenant_id
         mydb.new_row('tenants_datacenters', tenants_datacenter_dict)
 
         datacenter_tenant_id = datacenter_tenants_dict["uuid"]
         tenants_datacenter_dict["datacenter_tenant_id"] = datacenter_tenant_id
         mydb.new_row('tenants_datacenters', tenants_datacenter_dict)
 
-        # create thread
-        thread_name = get_non_used_vim_name(datacenter_name, datacenter_id, tenant_dict['name'], tenant_dict['uuid'])
-        new_thread = vim_thread(task_lock, plugins, thread_name, datacenter_name, datacenter_tenant_id,
-                                db=db, db_lock=db_lock, ovim=ovim)
+        # load plugin and create thread
+        plugin_name = "rovim_" + datacenter_type
+        if plugin_name not in plugins:
+            _load_plugin(plugin_name, type="vim")
+        thread_name = get_non_used_vim_name(datacenter_name, datacenter_id)
+        new_thread = vim_thread(task_lock, plugins, thread_name, None, datacenter_tenant_id, db=db)
         new_thread.start()
         thread_id = datacenter_tenants_dict["uuid"]
         vim_threads["running"][thread_id] = new_thread
         return thread_id
         new_thread.start()
         thread_id = datacenter_tenants_dict["uuid"]
         vim_threads["running"][thread_id] = new_thread
         return thread_id
-    except vimconn.vimconnException as e:
+    except vimconn.VimConnException as e:
         raise NfvoException(str(e), httperrors.Bad_Request)
 
 
         raise NfvoException(str(e), httperrors.Bad_Request)
 
 
@@ -5127,7 +5349,7 @@ def edit_vim_account(mydb, nfvo_tenant, datacenter_tenant_id, datacenter_id=None
     if config:
         original_config_dict = yaml.load(original_config, Loader=yaml.Loader)
         original_config_dict.update(config)
     if config:
         original_config_dict = yaml.load(original_config, Loader=yaml.Loader)
         original_config_dict.update(config)
-        update["config"] = yaml.safe_dump(original_config_dict, default_flow_style=True, width=256)
+        update_["config"] = yaml.safe_dump(original_config_dict, default_flow_style=True, width=256)
     if name:
         update_['name'] = name
     if vim_tenant:
     if name:
         update_['name'] = name
     if vim_tenant:
@@ -5180,7 +5402,7 @@ def delete_vim_account(mydb, tenant_id, vim_account_id, datacenter=None):
                 try:
                     datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter)
                     myvim.delete_tenant(vim_tenant_dict['vim_tenant_id'])
                 try:
                     datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter)
                     myvim.delete_tenant(vim_tenant_dict['vim_tenant_id'])
-                except vimconn.vimconnException as e:
+                except vimconn.VimConnException as e:
                     warning = "Not possible to delete vim_tenant_id {} from VIM: {} ".format(vim_tenant_dict['vim_tenant_id'], str(e))
                     logger.warn(warning)
         except db_base_Exception as e:
                     warning = "Not possible to delete vim_tenant_id {} from VIM: {} ".format(vim_tenant_dict['vim_tenant_id'], str(e))
                     logger.warn(warning)
         except db_base_Exception as e:
@@ -5202,14 +5424,14 @@ def datacenter_action(mydb, tenant_id, datacenter, action_dict):
     if 'check-connectivity' in action_dict:
         try:
             myvim.check_vim_connectivity()
     if 'check-connectivity' in action_dict:
         try:
             myvim.check_vim_connectivity()
-        except vimconn.vimconnException as e:
+        except vimconn.VimConnException as e:
             #logger.error("nfvo.datacenter_action() Not possible to get_network_list from VIM: %s ", str(e))
             raise NfvoException(str(e), e.http_code)
     elif 'net-update' in action_dict:
         try:
             nets = myvim.get_network_list(filter_dict={'shared': True, 'admin_state_up': True, 'status': 'ACTIVE'})
             #print content
             #logger.error("nfvo.datacenter_action() Not possible to get_network_list from VIM: %s ", str(e))
             raise NfvoException(str(e), e.http_code)
     elif 'net-update' in action_dict:
         try:
             nets = myvim.get_network_list(filter_dict={'shared': True, 'admin_state_up': True, 'status': 'ACTIVE'})
             #print content
-        except vimconn.vimconnException as e:
+        except vimconn.VimConnException as e:
             #logger.error("nfvo.datacenter_action() Not possible to get_network_list from VIM: %s ", str(e))
             raise NfvoException(str(e), httperrors.Internal_Server_Error)
         #update nets Change from VIM format to NFVO format
             #logger.error("nfvo.datacenter_action() Not possible to get_network_list from VIM: %s ", str(e))
             raise NfvoException(str(e), httperrors.Internal_Server_Error)
         #update nets Change from VIM format to NFVO format
@@ -5268,7 +5490,7 @@ def datacenter_new_netmap(mydb, tenant_id, datacenter, action_dict=None):
 
     try:
         vim_nets = myvim.get_network_list(filter_dict=filter_dict)
 
     try:
         vim_nets = myvim.get_network_list(filter_dict=filter_dict)
-    except vimconn.vimconnException as e:
+    except vimconn.VimConnException as e:
         #logger.error("nfvo.datacenter_new_netmap() Not possible to get_network_list from VIM: %s ", str(e))
         raise NfvoException(str(e), httperrors.Internal_Server_Error)
     if len(vim_nets)>1 and action_dict:
         #logger.error("nfvo.datacenter_new_netmap() Not possible to get_network_list from VIM: %s ", str(e))
         raise NfvoException(str(e), httperrors.Internal_Server_Error)
     if len(vim_nets)>1 and action_dict:
@@ -5309,7 +5531,7 @@ def get_sdn_net_id(mydb, tenant_id, datacenter, network_id):
 
         datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter)
         network = myvim.get_network_list(filter_dict=filter_dict)
 
         datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter)
         network = myvim.get_network_list(filter_dict=filter_dict)
-    except vimconn.vimconnException as e:
+    except vimconn.VimConnException as e:
         raise NfvoException("Not possible to get_sdn_net_id from VIM: {}".format(str(e)), e.http_code)
 
     # ensure the network is defined
         raise NfvoException("Not possible to get_sdn_net_id from VIM: {}".format(str(e)), e.http_code)
 
     # ensure the network is defined
@@ -5480,7 +5702,7 @@ def vim_action_get(mydb, tenant_id, datacenter, item, name):
                  datacenter)
         else:
             return {item: content}
                  datacenter)
         else:
             return {item: content}
-    except vimconn.vimconnException as e:
+    except vimconn.VimConnException as e:
         print("vim_action Not possible to get_{}_list from VIM: {} ".format(item, str(e)))
         raise NfvoException("Not possible to get_{}_list from VIM: {}".format(item, str(e)), e.http_code)
 
         print("vim_action Not possible to get_{}_list from VIM: {} ".format(item, str(e)))
         raise NfvoException("Not possible to get_{}_list from VIM: {}".format(item, str(e)), e.http_code)
 
@@ -5544,7 +5766,7 @@ def vim_action_delete(mydb, tenant_id, datacenter, item, name):
             content = myvim.delete_image(item_id)
         else:
             raise NfvoException(item + "?", httperrors.Method_Not_Allowed)
             content = myvim.delete_image(item_id)
         else:
             raise NfvoException(item + "?", httperrors.Method_Not_Allowed)
-    except vimconn.vimconnException as e:
+    except vimconn.VimConnException as e:
         #logger.error( "vim_action Not possible to delete_{} {}from VIM: {} ".format(item, name, str(e)))
         raise NfvoException("Not possible to delete_{} {} from VIM: {}".format(item, name, str(e)), e.http_code)
 
         #logger.error( "vim_action Not possible to delete_{} {}from VIM: {} ".format(item, name, str(e)))
         raise NfvoException("Not possible to delete_{} {} from VIM: {}".format(item, name, str(e)), e.http_code)
 
@@ -5565,7 +5787,10 @@ def vim_action_create(mydb, tenant_id, datacenter, item, descriptor):
             net_public = net.pop("shared", False)
             net_ipprofile = net.pop("ip_profile", None)
             net_vlan = net.pop("vlan", None)
             net_public = net.pop("shared", False)
             net_ipprofile = net.pop("ip_profile", None)
             net_vlan = net.pop("vlan", None)
-            content, _ = myvim.new_network(net_name, net_type, net_ipprofile, shared=net_public, vlan=net_vlan) #, **net)
+            net_provider_network_profile = None
+            if net_vlan:
+                net_provider_network_profile = {"segmentation-id": net_vlan}
+            content, _ = myvim.new_network(net_name, net_type, net_ipprofile, shared=net_public, provider_network_profile=net_provider_network_profile) #, **net)
 
             #If the datacenter has a SDN controller defined and the network is of dataplane type, then create the sdn network
             if get_sdn_controller_id(mydb, datacenter) != None and (net_type == 'data' or net_type == 'ptp'):
 
             #If the datacenter has a SDN controller defined and the network is of dataplane type, then create the sdn network
             if get_sdn_controller_id(mydb, datacenter) != None and (net_type == 'data' or net_type == 'ptp'):
@@ -5603,19 +5828,35 @@ def vim_action_create(mydb, tenant_id, datacenter, item, descriptor):
             content = myvim.new_tenant(tenant["name"], tenant.get("description"))
         else:
             raise NfvoException(item + "?", httperrors.Method_Not_Allowed)
             content = myvim.new_tenant(tenant["name"], tenant.get("description"))
         else:
             raise NfvoException(item + "?", httperrors.Method_Not_Allowed)
-    except vimconn.vimconnException as e:
+    except vimconn.VimConnException as e:
         raise NfvoException("Not possible to create {} at VIM: {}".format(item, str(e)), e.http_code)
 
     return vim_action_get(mydb, tenant_id, datacenter, item, content)
 
 def sdn_controller_create(mydb, tenant_id, sdn_controller):
         raise NfvoException("Not possible to create {} at VIM: {}".format(item, str(e)), e.http_code)
 
     return vim_action_get(mydb, tenant_id, datacenter, item, content)
 
 def sdn_controller_create(mydb, tenant_id, sdn_controller):
-    data = ovim.new_of_controller(sdn_controller)
-    logger.debug('New SDN controller created with uuid {}'.format(data))
-    return data
+    try:
+        wim_id = ovim.new_of_controller(sdn_controller)
+
+        # Load plugin if not previously loaded
+        controller_type = sdn_controller.get("type")
+        plugin_name = "rosdn_" + controller_type
+        if plugin_name not in plugins:
+            _load_plugin(plugin_name, type="sdn")
+
+        thread_name = get_non_used_vim_name(sdn_controller['name'], wim_id)
+        new_thread = vim_thread(task_lock, plugins, thread_name, wim_id, None, db=db)
+        new_thread.start()
+        thread_id = wim_id
+        vim_threads["running"][thread_id] = new_thread
+        logger.debug('New SDN controller created with uuid {}'.format(wim_id))
+        return wim_id
+    except ovimException as e:
+        raise NfvoException(e) from e
 
 def sdn_controller_update(mydb, tenant_id, controller_id, sdn_controller):
     data = ovim.edit_of_controller(controller_id, sdn_controller)
     msg = 'SDN controller {} updated'.format(data)
 
 def sdn_controller_update(mydb, tenant_id, controller_id, sdn_controller):
     data = ovim.edit_of_controller(controller_id, sdn_controller)
     msg = 'SDN controller {} updated'.format(data)
+    vim_threads["running"][controller_id].insert_task("reload")
     logger.debug(msg)
     return msg
 
     logger.debug(msg)
     return msg
 
@@ -5661,20 +5902,25 @@ def datacenter_sdn_port_mapping_set(mydb, tenant_id, datacenter_id, sdn_port_map
         #element = {"ofc_id": sdn_controller_id, "region": datacenter_id, "switch_dpid": switch_dpid}
         element = dict()
         element["compute_node"] = compute_node["compute_node"]
         #element = {"ofc_id": sdn_controller_id, "region": datacenter_id, "switch_dpid": switch_dpid}
         element = dict()
         element["compute_node"] = compute_node["compute_node"]
-        for port in compute_node["ports"]:
-            pci = port.get("pci")
-            element["switch_port"] = port.get("switch_port")
-            element["switch_mac"] = port.get("switch_mac")
-            if not element["switch_port"] and not element["switch_mac"]:
-                raise NfvoException ("The mapping must contain 'switch_port' or 'switch_mac'", httperrors.Bad_Request)
-            for pci_expanded in utils.expand_brackets(pci):
-                element["pci"] = pci_expanded
-                maps.append(dict(element))
-
-    return ovim.set_of_port_mapping(maps, ofc_id=sdn_controller_id, switch_dpid=switch_dpid, region=datacenter_id)
+        if compute_node["ports"]:
+            for port in compute_node["ports"]:
+                pci = port.get("pci")
+                element["switch_port"] = port.get("switch_port")
+                element["switch_mac"] = port.get("switch_mac")
+                element["switch_dpid"] = port.get("switch_dpid")
+                element["switch_id"] = port.get("switch_id")
+                if not element["switch_port"] and not element["switch_mac"]:
+                    raise NfvoException ("The mapping must contain 'switch_port' or 'switch_mac'", httperrors.Bad_Request)
+                for pci_expanded in utils.expand_brackets(pci):
+                    element["pci"] = pci_expanded
+                    maps.append(dict(element))
+
+    out = ovim.set_of_port_mapping(maps, sdn_id=sdn_controller_id, switch_dpid=switch_dpid, vim_id=datacenter_id)
+    vim_threads["running"][sdn_controller_id].insert_task("reload")
+    return out
 
 def datacenter_sdn_port_mapping_list(mydb, tenant_id, datacenter_id):
 
 def datacenter_sdn_port_mapping_list(mydb, tenant_id, datacenter_id):
-    maps = ovim.get_of_port_mappings(db_filter={"region": datacenter_id})
+    maps = ovim.get_of_port_mappings(db_filter={"datacenter_id": datacenter_id})
 
     result = {
         "sdn-controller": None,
 
     result = {
         "sdn-controller": None,
@@ -5703,24 +5949,25 @@ def datacenter_sdn_port_mapping_list(mydb, tenant_id, datacenter_id):
 
     ports_correspondence_dict = dict()
     for link in maps:
 
     ports_correspondence_dict = dict()
     for link in maps:
-        if result["sdn-controller"] != link["ofc_id"]:
+        if result["sdn-controller"] != link["wim_id"]:
             raise NfvoException("The sdn-controller specified for different port mappings differ", httperrors.Internal_Server_Error)
         if result["dpid"] != link["switch_dpid"]:
             raise NfvoException("The dpid specified for different port mappings differ", httperrors.Internal_Server_Error)
             raise NfvoException("The sdn-controller specified for different port mappings differ", httperrors.Internal_Server_Error)
         if result["dpid"] != link["switch_dpid"]:
             raise NfvoException("The dpid specified for different port mappings differ", httperrors.Internal_Server_Error)
+        link_config = link["service_mapping_info"]
         element = dict()
         element = dict()
-        element["pci"] = link["pci"]
+        element["pci"] = link.get("device_interface_id")
         if link["switch_port"]:
             element["switch_port"] = link["switch_port"]
         if link["switch_port"]:
             element["switch_port"] = link["switch_port"]
-        if link["switch_mac"]:
-            element["switch_mac"] = link["switch_mac"]
+        if link_config["switch_mac"]:
+            element["switch_mac"] = link_config.get("switch_mac")
 
 
-        if not link["compute_node"] in ports_correspondence_dict:
+        if not link.get("interface_id") in ports_correspondence_dict:
             content = dict()
             content = dict()
-            content["compute_node"] = link["compute_node"]
+            content["compute_node"] = link.get("interface_id")
             content["ports"] = list()
             content["ports"] = list()
-            ports_correspondence_dict[link["compute_node"]] = content
+            ports_correspondence_dict[link.get("interface_id")] = content
 
 
-        ports_correspondence_dict[link["compute_node"]]["ports"].append(element)
+        ports_correspondence_dict[link["interface_id"]]["ports"].append(element)
 
     for key in sorted(ports_correspondence_dict):
         result["ports_mapping"].append(ports_correspondence_dict[key])
 
     for key in sorted(ports_correspondence_dict):
         result["ports_mapping"].append(ports_correspondence_dict[key])
@@ -5728,7 +5975,7 @@ def datacenter_sdn_port_mapping_list(mydb, tenant_id, datacenter_id):
     return result
 
 def datacenter_sdn_port_mapping_delete(mydb, tenant_id, datacenter_id):
     return result
 
 def datacenter_sdn_port_mapping_delete(mydb, tenant_id, datacenter_id):
-    return ovim.clear_of_port_mapping(db_filter={"region":datacenter_id})
+    return ovim.clear_of_port_mapping(db_filter={"datacenter_id":datacenter_id})
 
 def create_RO_keypair(tenant_id):
     """
 
 def create_RO_keypair(tenant_id):
     """
@@ -5749,6 +5996,10 @@ def create_RO_keypair(tenant_id):
         private_key = key.exportKey(passphrase=tenant_id, pkcs=8)
     except (ValueError, NameError) as e:
         raise NfvoException("Unable to create private key: {}".format(e), httperrors.Internal_Server_Error)
         private_key = key.exportKey(passphrase=tenant_id, pkcs=8)
     except (ValueError, NameError) as e:
         raise NfvoException("Unable to create private key: {}".format(e), httperrors.Internal_Server_Error)
+    if isinstance(public_key, bytes):
+        public_key = public_key.decode(encoding='UTF-8')
+    if isinstance(private_key, bytes):
+        private_key = private_key.decode(encoding='UTF-8')
     return public_key, private_key
 
 def decrypt_key (key, tenant_id):
     return public_key, private_key
 
 def decrypt_key (key, tenant_id):
@@ -5765,6 +6016,8 @@ def decrypt_key (key, tenant_id):
         unencrypted_key = key.exportKey('PEM')
         if isinstance(unencrypted_key, ValueError):
             raise NfvoException("Unable to decrypt the private key: {}".format(unencrypted_key), httperrors.Internal_Server_Error)
         unencrypted_key = key.exportKey('PEM')
         if isinstance(unencrypted_key, ValueError):
             raise NfvoException("Unable to decrypt the private key: {}".format(unencrypted_key), httperrors.Internal_Server_Error)
+        if isinstance(unencrypted_key, bytes):
+            unencrypted_key = unencrypted_key.decode(encoding='UTF-8')
     except ValueError as e:
         raise NfvoException("Unable to decrypt the private key: {}".format(e), httperrors.Internal_Server_Error)
     return unencrypted_key
     except ValueError as e:
         raise NfvoException("Unable to decrypt the private key: {}".format(e), httperrors.Internal_Server_Error)
     return unencrypted_key