Пример #1
0
 def initialize(self):
     """
 .. seealso::
   :func:`AbstractAPI.initialize() <escape.util.api.AbstractAPI.initialize>`
 """
     log.debug("Initializing Resource Orchestration Sublayer...")
     self.resource_orchestrator = ResourceOrchestrator(self)
     if self._nffg_file:
         try:
             service_request = self._read_data_from_file(self._nffg_file)
             service_request = NFFG.parse(service_request)
             self.__proceed_instantiation(nffg=service_request)
         except (ValueError, IOError, TypeError) as e:
             log.error("Can't load service request from file because of: " +
                       str(e))
         else:
             log.info("Graph representation is loaded successfully!")
     # Initiate ROS REST-API if needed
     if self._agent or self._rosapi:
         self._initiate_ros_api()
     # Initiate Cf-Or REST-API if needed
     if self._cfor:
         self._initiate_cfor_api()
     log.info("Resource Orchestration Sublayer has been initialized!")
     if self._agent:
         log.warning(
             "In AGENT mode Service Layer is not going to be initialized!")
Пример #2
0
 def collect_mappings(self, mappings, slor_topo):
     dov = self.virtualizerManager.dov.get_resource_info()
     response = mappings.full_copy()
     log.debug("Start checking mappings...")
     for mapping in response:
         bb, nf = detect_bb_nf_from_path(path=mapping.object.get_value(),
                                         topo=slor_topo)
         if not nf:
             # mapping.target.object.set_value("NOT_FOUND")
             mapping.target.domain.set_value("N/A")
             continue
         m_result = self.__collect_binding(dov=dov, nfs=[nf])
         if not m_result:
             log.warning("Mapping is not found for NF: %s!" % nf)
             # mapping.target.object.set_value("NOT_FOUND")
             mapping.target.domain.set_value("N/A")
             continue
         try:
             node = m_result[0]['bisbis']['id']
             domain = m_result[0]['bisbis']['domain']
         except KeyError:
             log.warning("Missing mapping element from: %s" % m_result)
             # mapping.target.object.set_value("NOT_FOUND")
             mapping.target.domain.set_value("N/A")
             continue
         log.debug("Found mapping: %s@%s (domain: %s)" % (nf, node, domain))
         mapping.target.object.set_value(NF_PATH_TEMPLATE % (node, nf))
         mapping.target.domain.set_value(
             CONFIG.get_domain_url(domain=domain))
     return response
Пример #3
0
    def __update_nffg_domain(nffg_part, domain_name=None):
        """
    Update domain descriptor of infras: REMOTE -> INTERNAL

    :param nffg_part: NF-FG need to be updated
    :type nffg_part: :any:`NFFG`
    :return: updated NFFG
    :rtype: :any:`NFFG`
    """
        rewritten = []
        if domain_name is None:
            local_mgr = CONFIG.get_local_manager()
            if local_mgr is None:
                log.error("No local Manager has been initiated! "
                          "Skip domain rewriting!")
            elif len(local_mgr) > 1:
                log.warning("Multiple local Manager has been initiated: %s! "
                            "Arbitrarily use the first..." % local_mgr)
            domain_name = local_mgr.pop()
        log.debug("Rewrite received NFFG domain to %s..." % domain_name)
        for infra in nffg_part.infras:
            infra.domain = domain_name
            rewritten.append(infra.id)
        log.debug("Rewritten infrastructure nodes: %s" % rewritten)
        return nffg_part
Пример #4
0
    def __detect_neo4j_service_name():
        """
    Detect the name of the neo4j service.

    :return: name of the service
    :rtype: str
    """
        import os.path
        if os.path.isfile('/etc/neo4j/neo4j.conf'):
            return "neo4j"
        elif os.path.isfile('/etc/neo4j/neo4j-server.properties'):
            return "neo4j-service"
        else:
            log.warning("No configuration file was found for neo4j service!")
Пример #5
0
 def initialize(self):
     """
 Initialize NFIB with test data.
 """
     try:
         try:
             host, port = CONFIG.get_neo4j_host_port()
             host = host if host else self.DB_HOST
             port = port if port else self.DB_PORT
             log.debug("Initiating Graph database connection[%s:%s]..." %
                       (host, port))
             self.graph_db = Graph(host=host, http_port=port)
         except Unauthorized as e:
             quit_with_error(
                 "Got Unauthorized error on: %s from neo4j! Disable the authorization "
                 "in /etc/neo4j/neoj4-server.properties!" % e)
             return self
         except SocketError:
             log.warning(
                 "NFIBManager has not been initialized! Only cause problem "
                 "if ESCAPE is used as a Local Orchestrator!")
             return self
         self.__initialize()
     except SocketError as e:
         log.error(
             "NFIB is not reachable due to failed neo4j service! Cause: " +
             str(e))
     except KeyboardInterrupt:
         log.warning("NFIB was interrupted by user!")
     except Unauthorized:
         log.error(
             "neo4j responded with Unauthorized error! Maybe you forgot disabling "
             "authentication in '/etc/neo4j/neo4j.conf' ?")
     except IOError as e:
         if ".neo4j/known_hosts" in str(e):
             # Skip Permission denied in case of accessing neo4j cache file (v3.0.2)
             pass
         else:
             raise
     except:
         log.exception("Got unexpected error during NFIB initialization!")
     return self
Пример #6
0
    def collect_mapping_info(self, service_id):
        """
    Return with collected information of mapping of a given service.

    :param service_id: service request ID
    :type service_id: str
    :return: mapping info
    :rtype: dict
    """
        # Get the service NFFG based on service ID
        request = self.nffgManager.get(service_id)
        if request is None:
            log.warning("Service request(id: %s) is not found!" % service_id)
            return "Service request is not found!"
        # Get the overall view a.k.a. DoV
        dov = self.virtualizerManager.dov.get_resource_info()
        # Collect NFs
        nfs = [nf.id for nf in request.nfs]
        log.debug("Collected NFs: %s" % nfs)
        return self.__collect_binding(dov=dov, nfs=nfs)
Пример #7
0
 def initialize (self):
   """
   Initialize NFIB with test data.
   """
   try:
     self.__initialize()
   except SocketError as e:
     log.error(
       "NFIB is not reachable due to failed neo4j service! Cause: " + str(e))
   except KeyboardInterrupt:
     log.warning("NFIB was interrupted by user!")
   except Unauthorized:
     log.error(
       "neo4j responded with Unauthorized error! Maybe you forgot disabling "
       "authentication in '/etc/neo4j/neo4j.conf' ?")
   except IOError as e:
     if ".neo4j/known_hosts" in str(e):
       # Skip Permission denied in case of accessing neo4j cache file (v3.0.2)
       pass
     else:
       raise
   except:
     log.exception("Got unexpected error during NFIB initialization!")
Пример #8
0
    def __proceed_instantiation(self, nffg):
        """
    Helper function to instantiate the NFFG mapping from different source.

    :param nffg: pre-mapped service request
    :type nffg: :any:`NFFG`
    :return: None
    """
        log.getChild('API').info(
            "Invoke instantiate_nffg on %s with NF-FG: %s " %
            (self.__class__.__name__, nffg.name))
        # Initiate request mapping
        mapped_nffg = self.resource_orchestrator.instantiate_nffg(nffg=nffg)
        log.getChild('API').debug(
            "Invoked instantiate_nffg on %s is finished" %
            self.__class__.__name__)
        # If mapping is not threaded and finished with OK
        if mapped_nffg is not None and not \
           self.resource_orchestrator.mapper.threaded:
            self._proceed_to_install_NFFG(mapped_nffg=mapped_nffg)
        else:
            log.warning(
                "Something went wrong in service request instantiation: "
                "mapped service request is missing!")
Пример #9
0
    def map(cls, graph, resource):
        """
    Default mapping algorithm of ESCAPEv2.

    :param graph: Network Function forwarding Graph
    :type graph: :any:`NFFG`
    :param resource: global virtual resource info
    :type resource: :any:`NFFG`
    :return: mapped Network Function Forwarding Graph
    :rtype: :any:`NFFG`
    """
        log.debug("Invoke mapping algorithm: %s - request: %s resource: %s" %
                  (cls.__name__, graph, resource))
        if graph is None:
            log.error("Missing request NFFG! Abort mapping process...")
            return
        if resource is None:
            log.error("Missing resource NFFG! Abort mapping process...")
            return
        try:
            # print graph.dump()
            mapper_params = CONFIG.get_mapping_config(layer=LAYER_NAME)
            mapped_nffg = MAP(request=graph.copy(),
                              network=resource.copy(),
                              **mapper_params)
            # Set mapped NFFG id for original SG request tracking
            mapped_nffg.id = graph.id
            mapped_nffg.name = graph.name + "-ros-mapped"
            log.debug("Mapping algorithm: %s is finished on NF-FG: %s" %
                      (cls.__name__, graph))
            # print mapped_nffg.dump()
            return mapped_nffg
        except MappingException as e:
            log.error(
                "Mapping algorithm unable to map given request! Cause:\n%s" %
                e.msg)
            log.warning("Mapping algorithm on %s is aborted!" % graph)
            return
        except BadInputException as e:
            log.error("Mapping algorithm refuse given input! Cause:\n%s" %
                      e.msg)
            log.warning("Mapping algorithm on %s is aborted!" % graph)
            return
        except InternalAlgorithmException as e:
            log.critical(
                "Mapping algorithm fails due to implementation error or conceptual "
                "error! Cause:\n%s" % e.msg)
            log.warning("Mapping algorithm on %s is aborted!" % graph)
            raise
        except:
            log.exception("Got unexpected error during mapping process!")
Пример #10
0
    def __collect_binding(dov, nfs):
        """
    Collect mapping of given NFs on the global view(DoV).

    :param dov: global topology
    :type dov: :class:`NFFG`
    :param nfs: list of NFs
    :type nfs: list
    :return: mapping
    :rtype: list of dict
    """
        mappings = []
        # Process NFs
        for nf_id in nfs:
            mapping = {}
            # Get the connected infra node
            if nf_id not in dov:
                log.warning(
                    "NF: %s is not found in the global topology(DoV)!" % nf_id)
                continue
            bisbis = [n.id for n in dov.infra_neighbors(nf_id)]
            log.log(VERBOSE, "Detected mapped BiSBiS node:" % bisbis)
            if len(bisbis) != 1:
                log.warning("Detected unexpected number of BiSBiS node: %s!" %
                            bisbis)
                continue
            bisbis = bisbis.pop()
            # Add NF id
            nf = {"id": nf_id, "ports": []}
            for dyn_link in dov.network[nf_id][bisbis].itervalues():
                port = OrderedDict(id=dyn_link.src.id)
                if dyn_link.src.l4 is not None:
                    try:
                        port['management'] = ast.literal_eval(dyn_link.src.l4)
                    except SyntaxError:
                        log.warning(
                            "L4 address entry: %s is not valid Python expression! "
                            "Add the original string..." % dyn_link.src.l4)
                        port['management'] = dyn_link.src.l4
                nf['ports'].append(port)
            mapping['nf'] = nf
            # Add infra node ID and domain name
            bisbis = bisbis.split('@')
            bb_mapping = {
                "id": bisbis[0],
                "domain": bisbis[1] if len(bisbis) > 1 else None
            }
            mapping['bisbis'] = bb_mapping
            mappings.append(mapping)
        return mappings
Пример #11
0
    def collect_mappings(self, mappings, slor_topo):
        """
    Collect mapping information of NF in given mappings and return with an
    extended mapping structure.

    :param mappings: received mapping object
    :type mappings: :class:`Virtualizer`
    :param slor_topo: layer view of topology
    :type slor_topo: :class:`NFFG`
    :return: mapping structure extended with embedding info
    :rtype: :class:`Virtualizer`
    """
        dov = self.virtualizerManager.dov.get_resource_info()
        response = mappings.yang_copy()
        log.debug("Start checking mappings...")
        for mapping in response:
            bb, nf = detect_bb_nf_from_path(path=mapping.object.get_value(),
                                            topo=slor_topo)
            if not nf:
                mapping.target.object.set_value("NOT_FOUND")
                mapping.target.domain.set_value("N/A")
                continue
            m_result = self.__collect_binding(dov=dov, nfs=[nf])
            if not m_result:
                log.warning("Mapping is not found for NF: %s!" % nf)
                mapping.target.object.set_value("NOT_FOUND")
                mapping.target.domain.set_value("N/A")
                continue
            try:
                node = m_result[0]['bisbis']['id']
            except KeyError:
                log.warning("Missing mapping node element from: %s" % m_result)
                node = "NOT_FOUND"
            try:
                domain = m_result[0]['bisbis']['domain']
            except KeyError:
                log.warning("Missing mapping domain element from: %s" %
                            m_result)
                domain = "N/A"
            log.debug("Found mapping: %s@%s (domain: %s)" % (nf, node, domain))
            mapping.target.object.set_value(NF_PATH_TEMPLATE % (node, nf))
            mapping.target.domain.set_value(domain)
        return response
Пример #12
0
  def preprocess_nffg(self, nffg):

    try:
      # if there is at least ONE SGHop in the graph, we don't do SGHop retrieval.
      next(nffg.sg_hops)
    except StopIteration:
      # retrieve the SGHops from the TAG values of the flow rules, in case they
      # are cannot be found in the request graph and can only be deduced from the 
      # flows
      log.warning("No SGHops were given in the Service Graph, retrieving them"
                      " based on the flowrules...")
      sg_hops_given = False
      sg_hop_info = NFFGToolBox.retrieve_all_SGHops(nffg)
      if len(sg_hop_info) == 0:
        raise uet.BadInputException("If SGHops are not given, flowrules should be"
                                    " in the NFFG",
                                    "No SGHop could be retrieved based on the "
                                    "flowrules of the NFFG.")
      for k, v in sg_hop_info.iteritems():
        # VNF ports are given to the function
        nffg.add_sglink(v[0], v[1], flowclass=v[2], bandwidth=v[3], delay=v[4],
                           id=k[2])

    DPDK_COST=0
    VHOST_COST=0
    KNI_COST=0

    for sap in nffg.saps:
      if sap.id.startswith("dpdk"):
        dpdk=sap.id.split('-')[0]
        dpdk_nf=nffg.add_nf(id=dpdk)
        dpdk_nf.resources.cpu=DPDK_COST
        dpdk_nf.resources.mem=0
        dpdk_nf.resources.storage=0
        dpdk_nf.functional_type=dpdk

    hops= [hop for hop in nffg.sg_hops]
    for hop in hops:
      if hop.src.node.id.startswith("dpdk") and hop.dst.node.id.startswith("dpdk"):
        dpdk_in_id=hop.src.node.id.split('-')[0]
        dpdk_out_id=hop.dst.node.id.split('-')[0]
        dpdk_in=nffg.network.node[dpdk_in_id]
        dpdk_out=nffg.network.node[dpdk_out_id]
        link_in=nffg.add_sglink(hop.src,dpdk_in.add_port())
        link_out=nffg.add_sglink(dpdk_out.add_port(), hop.dst)
        link=hop.copy()
        link.src=dpdk_in.add_port()
        link.dst=dpdk_out.add_port()
        nffg.del_edge(hop.src,hop.dst,hop.id)
        nffg.add_sglink(link.src,link.dst,hop=link)

        for req in nffg.reqs: 
          if hop.id in req.sg_path:
            req.sg_path.insert(0,link_in.id)
            req.sg_path.insert(len(req.sg_path),link_out.id)

        
    nfs = [nf for nf in nffg.nfs if not nf.functional_type.startswith("dpdk")]
    for nf in nfs:

      if nf.functional_type.endswith("KNI"):
        NF_TYPE="KNI"
        PORT_RES=KNI_COST
      elif nf.functional_type.endswith("VHOST"): 
        NF_TYPE="VHOST"
        PORT_RES=VHOST_COST

      if len(nf.ports) > 1:
        in_nf = nf.copy()
        in_nf.ports.clear()
        in_nf.resources.cpu=PORT_RES
        in_nf.resources.mem=0
        in_nf.id=nf.id + "-in"
        in_nf.functional_type=NF_TYPE
        nffg.add_nf(nf=in_nf)
        out_nf = nf.copy()
        out_nf.ports.clear()
        out_nf.resources.cpu=PORT_RES
        out_nf.resources.mem=0
        out_nf.functional_type=NF_TYPE
        out_nf.id=nf.id + "-out"
        nffg.add_nf(nf=out_nf)
      else:
        in_nf = nf.copy()
        in_nf.ports.clear()
        in_nf.resources.cpu=PORT_RES
        in_nf.resources.mem=0
        in_nf.id=nf.id + "-inout"
        in_nf.functional_type=NF_TYPE
        nffg.add_nf(nf=in_nf)
        out_nf=in_nf

      in_tag=None
      out_tag=None

      dpdk_in=None
      dpdk_out=None

      hops= [hop for hop in nffg.sg_hops]
      for hop in hops:
        if hop.dst.node.id == nf.id:
          in_tag=hop.id
          try:
            in_port = nffg.network.node[in_nf.id].ports[hop.dst.id]
          except KeyError:
            in_port = nffg.network.node[in_nf.id].add_port(id=hop.dst.id)
          old_hop=hop.copy()
          old_hop.dst=in_port
          nffg.del_edge(hop.src,hop.dst,hop.id)
          if hop.src.node.id.startswith("dpdk"):
            dpdk_nf_id=hop.src.node.id.split('-')[0]
            dpdk_nf = nffg.network.node[dpdk_nf_id]
            port1=dpdk_nf.add_port()
            old_hop.src=port1
            nffg.add_sglink(port1,in_port,hop=old_hop)
            port2=dpdk_nf.add_port()
            dpdk_in=nffg.add_sglink(hop.src,port2)
          else:
            nffg.add_sglink(hop.src,in_port,hop=old_hop)

        if hop.src.node.id == nf.id:
          out_tag=hop.id
          try:
            out_port = nffg.network.node[out_nf.id].ports[hop.src.id]
          except KeyError:
            out_port = nffg.network.node[out_nf.id].add_port(id=hop.src.id)
          old_hop=hop.copy()
          old_hop.src=out_port
          nffg.del_edge(hop.src,hop.dst,hop.id)
          if hop.dst.node.id.startswith("dpdk"):
            dpdk_nf_id= hop.dst.node.id.split('-')[0]
            dpdk_nf = nffg.network.node[dpdk_nf_id]
            port1=dpdk_nf.add_port()
            old_hop.dst=port1
            nffg.add_sglink(out_port,port1,hop=old_hop)
            port2=dpdk_nf.add_port()
            dpdk_out=nffg.add_sglink(port2,hop.dst)
          else:
            nffg.add_sglink(out_port,hop.dst,hop=old_hop)

      vport_in=in_nf.add_port()
      vport_out=out_nf.add_port()

      aff_reqs=[]
      prev=None

      for req in nffg.reqs: 
        for elem in req.sg_path:
          if prev == in_tag and elem == out_tag:
            aff_reqs.append(req)
          prev=elem

      cpu_req=int(nf.resources.cpu)
      if cpu_req==0:
        num_cpu=1
      else:
        num_cpu=cpu_req

      for i in range(num_cpu):
        new_nf=nf.copy()
        new_nf.ports.clear()
        new_nf.resources.cpu=cpu_req / num_cpu
        new_nf.resources.mem=nf.resources.mem / num_cpu
        new_nf.id=nf.id + "-core" + str(i)
        nffg.add_nf(nf=new_nf)
        new_port1=new_nf.add_port()
        sg1=nffg.add_sglink(vport_in,new_port1) 
        new_port2=new_nf.add_port()
        sg2=nffg.add_sglink(new_port2,vport_out)
        for req in aff_reqs:
          new_req=req.copy()
          new_req.regenerate_id()
          poz=new_req.sg_path.index(in_tag)
          new_req.sg_path.insert(poz+1, sg1.id)
          new_req.sg_path.insert(poz+2, sg2.id) 
          if dpdk_in is not None:
            new_req.sg_path.insert(0, dpdk_in.id)
          if dpdk_out is not None:
            new_req.sg_path.insert(len(new_req.sg_path), dpdk_out.id) 
          nffg.add_req(req.src,req.dst,req=new_req)          
                    
      nffg.del_node(nf.id)
      for req in aff_reqs:
        nffg.del_edge(req.src,req.dst,req.id)

    print nffg.dump()
    return nffg
Пример #13
0
  def instantiate_nffg (self, nffg):
    """
    Main API function for NF-FG instantiation.

    :param nffg: NFFG instance
    :type nffg: :any:`NFFG`
    :return: mapped NFFG instance
    :rtype: :any:`NFFG`
    """

    log.debug("Invoke %s to instantiate given NF-FG" % self.__class__.__name__)
    # Store newly created NF-FG
    self.nffgManager.save(nffg)
    # Get Domain Virtualizer to acquire global domain view
    global_view = self.virtualizerManager.dov
    # Notify remote visualizer about resource view of this layer if it's needed
    notify_remote_visualizer(data=global_view.get_resource_info(),
                             id=LAYER_NAME)
    # Log verbose mapping request
    log.log(VERBOSE, "Orchestration Layer request graph:\n%s" % nffg.dump())
    # Start Orchestrator layer mapping
    print nffg.dump()
    if global_view is not None:
      if isinstance(global_view, AbstractVirtualizer):
        # If the request is a bare NFFG, it is probably an empty topo for domain
        # deletion --> skip mapping to avoid BadInputException and forward
        # topo to adaptation layer
        if nffg.is_bare():
          log.warning("No valid service request (VNFs/Flowrules/SGhops) has "
                      "been detected in SG request! Skip orchestration in "
                      "layer: %s and proceed with the bare %s..." %
                      (LAYER_NAME, nffg))
          if nffg.is_virtualized():
            if nffg.is_SBB():
              log.debug("Request is a bare SingleBiSBiS representation!")
            else:
              log.warning(
                "Detected virtualized representation with multiple BiSBiS "
                "nodes! Currently this type of virtualization is nut fully"
                "supported!")
          else:
            log.debug("Detected full view representation!")
          # Return with the original request
          return nffg
        else:
          log.info("Request check: detected valid content!")
        try:
          # Run Nf-FG mapping orchestration
          log.debug("Starting request preprocession...")
          log.info(int(round(time.time() * 1000)))
          self.preprocess_nffg(nffg)
          log.debug("Preprocession ended, start mapping")
          log.info(int(round(time.time() * 1000)))
          mapped_nffg = self.mapper.orchestrate(nffg, global_view)
          log.debug("NF-FG instantiation is finished by %s" %
                    self.__class__.__name__)
          log.info(int(round(time.time() * 1000)))
          return mapped_nffg
        except ProcessorError as e:
          log.warning("Mapping pre/post processing was unsuccessful! "
                      "Cause: %s" % e)
      else:
        log.warning("Global view is not subclass of AbstractVirtualizer!")
    else:
      log.warning("Global view is not acquired correctly!")
    log.error("Abort orchestration process!")
Пример #14
0
    def instantiate_nffg(self, nffg, continued_request_id=None):
        """
    Main API function for NF-FG instantiation.

    :param nffg: NFFG instance
    :type nffg: :class:`NFFG`
    :param continued_request_id: use explicit request id if request is
      continued after a trial and error (default: False)
    :type continued_request_id: str or None
    :return: mapped NFFG instance
    :rtype: :class:`NFFG`
    """
        log.debug("Invoke %s to instantiate given NF-FG" %
                  self.__class__.__name__)
        if not continued_request_id:
            # Store newly created NF-FG
            self.nffgManager.save(nffg)
        else:
            # Use the original NFFG requested for getting the original request
            nffg = self.nffgManager.get(nffg_id=continued_request_id)
            log.info("Using original request for remapping: %s" % nffg)
        # Get Domain Virtualizer to acquire global domain view
        global_view = self.virtualizerManager.dov
        # Notify remote visualizer about resource view of this layer if it's needed
        # notify_remote_visualizer(data=global_view.get_resource_info(),
        #                          id=LAYER_NAME)
        # Log verbose mapping request
        log.log(VERBOSE,
                "Orchestration Layer request graph:\n%s" % nffg.dump())
        # Start Orchestrator layer mapping
        if global_view is not None:
            # If the request is a bare NFFG, it is probably an empty topo for domain
            # deletion --> skip mapping to avoid BadInputException and forward
            # topo to adaptation layer
            if not continued_request_id:
                if nffg.is_bare():
                    log.warning(
                        "No valid service request (VNFs/Flowrules/SGhops) has "
                        "been detected in SG request! Skip orchestration in "
                        "layer: %s and proceed with the bare %s..." %
                        (LAYER_NAME, nffg))
                    if nffg.is_virtualized():
                        if nffg.is_SBB():
                            log.debug(
                                "Request is a bare SingleBiSBiS representation!"
                            )
                        else:
                            log.warning(
                                "Detected virtualized representation with multiple BiSBiS "
                                "nodes! Currently this type of virtualization is nut fully "
                                "supported!")
                    else:
                        log.debug("Detected full view representation!")
                    # Return with the original request
                    return nffg
                else:
                    log.info("Request check: detected valid NFFG content!")
            try:
                # Run NF-FG mapping orchestration
                mapped_nffg = self.mapper.orchestrate(
                    input_graph=nffg,
                    resource_view=global_view,
                    continued=bool(continued_request_id))
                log.debug("NF-FG instantiation is finished by %s" %
                          self.__class__.__name__)
                return mapped_nffg
            except ProcessorError as e:
                log.warning("Mapping pre/post processing was unsuccessful! "
                            "Cause: %s" % e)
                # Propagate the ProcessError to API layer
                raise
        else:
            log.warning("Global view is not acquired correctly!")
        log.error("Abort orchestration process!")
Пример #15
0
    def _perform_mapping(self, input_graph, resource_view):
        """
    Orchestrate mapping of given NF-FG on given global resource.

    :param input_graph: Network Function Forwarding Graph
    :type input_graph: :any:`NFFG`
    :param resource_view: global resource view
    :type resource_view: :any:`DomainVirtualizer`
    :return: mapped Network Function Forwarding Graph
    :rtype: :any:`NFFG`
    """
        if input_graph is None:
            log.error(
                "Missing mapping request information! Abort mapping process!")
            return None
        log.debug("Request %s to launch orchestration on NF-FG: %s with View: "
                  "%s" % (self.__class__.__name__, input_graph, resource_view))
        # Steps before mapping (optional)
        log.debug("Request global resource info...")
        virt_resource = resource_view.get_resource_info()
        if virt_resource is None:
            log.error("Missing resource information! Abort mapping process!")
            return None
        # log a warning if resource is empty --> possibly mapping will be failed
        if virt_resource.is_empty():
            log.warning("Resource information is empty!")
        # Log verbose resource view if it is exist
        log.log(
            VERBOSE,
            "Orchestration Layer resource graph:\n%s" % virt_resource.dump())
        # Check if the mapping algorithm is enabled
        if not CONFIG.get_mapping_enabled(LAYER_NAME):
            log.warning("Mapping algorithm in Layer: %s is disabled! "
                        "Skip mapping step and return service request "
                        "to lower layer..." % LAYER_NAME)
            # virt_resource.id = input_graph.id
            # return virt_resource
            # Send request forward (probably to Remote ESCAPE)
            return input_graph
        # Run actual mapping algorithm
        if self._threaded:
            # Schedule a microtask which run mapping algorithm in a Python thread
            log.info("Schedule mapping algorithm: %s in a worker thread" %
                     self.strategy.__name__)
            call_as_coop_task(self._start_mapping,
                              graph=input_graph,
                              resource=virt_resource)
            log.info("NF-FG: %s orchestration is finished by %s" %
                     (input_graph, self.__class__.__name__))
            # Return with None
            return None
        else:
            mapped_nffg = self.strategy.map(graph=input_graph,
                                            resource=virt_resource)
            if mapped_nffg is None:
                log.error(
                    "Mapping process is failed! Abort orchestration process.")
            else:
                # Steps after mapping (optional)
                log.info(
                    "NF-FG: %s orchestration is finished by %s successfully!" %
                    (input_graph, self.__class__.__name__))
            return mapped_nffg
Пример #16
0
    def __collect_binding(dov, nfs):
        """
    Collect mapping of given NFs on the global view(DoV) with the structure:

    .. code-block:: json

      [
        {
          "bisbis": {
            "domain": null,
            "id": "EE2"
          },
          "nf": {
            "id": "fwd",
            "ports": [
              {
                "id": 1,
                "management": {
                  "22/tcp": [
                    "0.0.0.0",
                    20000
                  ]
                }
              }
            ]
          }
        }
      ]

    :param dov: global topology
    :type dov: :class:`NFFG`
    :param nfs: list of NFs
    :type nfs: list
    :return: mapping
    :rtype: list of dict
    """
        mappings = []
        # Process NFs
        for nf_id in nfs:
            mapping = {}
            # Get the connected infra node
            if nf_id not in dov:
                log.warning("NF: %s in to in the global topology(DoV)!" %
                            nf_id)
                continue
            bisbis = [n.id for n in dov.infra_neighbors(nf_id)]
            log.log(VERBOSE, "Detected mapped BiSBiS node:" % bisbis)
            if len(bisbis) != 1:
                log.warning("Detected unexpected number of BiSBiS node: %s!" %
                            bisbis)
                continue
            bisbis = bisbis.pop()
            # Add NF id
            nf = {"id": nf_id, "ports": []}
            for dyn_link in dov.network[nf_id][bisbis].itervalues():
                port = OrderedDict(id=dyn_link.src.id)
                if dyn_link.src.l4 is not None:
                    try:
                        port['management'] = ast.literal_eval(dyn_link.src.l4)
                    except SyntaxError:
                        log.warning(
                            "L4 address entry: %s is not valid Python expression! "
                            "Add the original string..." % dyn_link.src.l4)
                        port['management'] = dyn_link.src.l4
                nf['ports'].append(port)
            mapping['nf'] = nf
            # Add infra node ID and domain name
            bisbis = bisbis.split('@')
            bb_mapping = {
                "id": bisbis[0],
                "domain": bisbis[1] if len(bisbis) > 1 else None
            }
            if bb_mapping.get("domain"):
                domain_url = CONFIG.get_domain_url(
                    domain=bb_mapping.get("domain"))
                log.debug("Domain: %s - Detected URL: %s" %
                          (bb_mapping.get("domain"), domain_url))
                if domain_url is not None:
                    bb_mapping["url"] = domain_url
                else:
                    log.warning("Missing URL for domain: %s!" %
                                bb_mapping["domain"])
            mapping['bisbis'] = bb_mapping
            mappings.append(mapping)
        return mappings
Пример #17
0
    def __proceed_instantiation(self, nffg, resource_nffg):
        """
    Helper function to instantiate the NFFG mapping from different source.

    :param nffg: pre-mapped service request
    :type nffg: :class:`NFFG`
    :return: None
    """
        self.log.info("Invoke instantiation on %s with NF-FG: %s" %
                      (self.__class__.__name__, nffg.name))
        stats.add_measurement_start_entry(type=stats.TYPE_ORCHESTRATION,
                                          info=LAYER_NAME)
        # Get shown topology view
        if resource_nffg is None:
            log.error("Missing resource for difference calculation!")
            return
        log.debug("Got resource view for difference calculation: %s" %
                  resource_nffg)
        self.log.debug("Store received NFFG request info...")
        msg_id = self.api_mgr.request_cache.cache_request_by_nffg(nffg=nffg)
        if msg_id is not None:
            self.api_mgr.request_cache.set_in_progress(id=msg_id)
            self.log.debug("Request is stored with id: %s" % msg_id)
        else:
            self.log.debug("No request info detected.")
        # Check if mapping mode is set globally in CONFIG
        mapper_params = CONFIG.get_mapping_config(layer=LAYER_NAME)
        if 'mode' in mapper_params and mapper_params['mode'] is not None:
            mapping_mode = mapper_params['mode']
            log.info("Detected mapping mode from configuration: %s" %
                     mapping_mode)
        elif nffg.mode is not None:
            mapping_mode = nffg.mode
            log.info("Detected mapping mode from NFFG: %s" % mapping_mode)
        else:
            mapping_mode = None
            log.info("No mapping mode was defined explicitly!")
        if not CONFIG.get_mapping_enabled(layer=LAYER_NAME):
            log.warning("Mapping is disabled! Skip difference calculation...")
        elif nffg.status == NFFG.MAP_STATUS_SKIPPED:
            log.debug("Detected NFFG map status: %s! "
                      "Skip difference calculation and "
                      "proceed with original request..." % nffg.status)
        elif mapping_mode != NFFG.MODE_REMAP:
            # Calculated ADD-DELETE difference
            log.debug("Calculate ADD - DELETE difference with mapping mode...")
            # Recreate SG-hops for diff calc.
            log.debug("Recreate SG hops for difference calculation...")
            NFFGToolBox.recreate_all_sghops(nffg=nffg)
            NFFGToolBox.recreate_all_sghops(nffg=resource_nffg)
            log.log(VERBOSE, "New NFFG:\n%s" % nffg.dump())
            log.log(VERBOSE, "Resource NFFG:\n%s" % resource_nffg.dump())
            # Calculate difference
            add_nffg, del_nffg = NFFGToolBox.generate_difference_of_nffgs(
                old=resource_nffg, new=nffg, ignore_infras=True)
            log.log(VERBOSE, "Calculated ADD NFFG:\n%s" % add_nffg.dump())
            log.log(VERBOSE, "Calculated DEL NFFG:\n%s" % del_nffg.dump())
            if not add_nffg.is_bare() and del_nffg.is_bare():
                nffg = add_nffg
                log.info("DEL NFFG is bare! Calculated mapping mode: %s" %
                         nffg.mode)
            elif add_nffg.is_bare() and not del_nffg.is_bare():
                nffg = del_nffg
                log.info("ADD NFFG is bare! Calculated mapping mode: %s" %
                         nffg.mode)
            elif not add_nffg.is_bare() and not del_nffg.is_bare():
                log.warning("Both ADD / DEL mode is not supported currently")
                self.__process_mapping_result(nffg_id=nffg.id, fail=True)
                stats.add_measurement_end_entry(type=stats.TYPE_ORCHESTRATION,
                                                info=LAYER_NAME + "-FAILED")
                self.raiseEventNoErrors(
                    InstantiationFinishedEvent,
                    id=nffg.id,
                    result=InstantiationFinishedEvent.ABORTED)
                return
            else:
                log.debug("Difference calculation resulted empty subNFFGs!")
                log.warning(
                    "No change has been detected in request! Skip mapping...")
                self.log.debug("Invoked instantiation on %s is finished!" %
                               self.__class__.__name__)
                self.__process_mapping_result(nffg_id=nffg.id, fail=False)
                stats.add_measurement_end_entry(type=stats.TYPE_ORCHESTRATION,
                                                info=LAYER_NAME + "-SKIPPED")
                return
        else:
            log.debug(
                "Mode: %s detected from config! Skip difference calculation..."
                % mapping_mode)
        try:
            if CONFIG.get_mapping_enabled(layer=LAYER_NAME):
                # Initiate request mapping
                mapped_nffg = self.orchestrator.instantiate_nffg(nffg=nffg)
            else:
                log.warning("Mapping is disabled! Skip instantiation step...")
                mapped_nffg = nffg
                mapped_nffg.status = NFFG.MAP_STATUS_SKIPPED
                log.debug("Mark NFFG status: %s!" % mapped_nffg.status)
            # Rewrite REMAP mode for backward compatibility
            if mapped_nffg is not None and mapping_mode == NFFG.MODE_REMAP:
                mapped_nffg.mode = mapping_mode
                log.debug("Rewrite mapping mode: %s into mapped NFFG..." %
                          mapped_nffg.mode)
            else:
                log.debug("Skip mapping mode rewriting! Mode remained: %s" %
                          mapping_mode)
                self.log.debug("Invoked instantiate_nffg on %s is finished!" %
                               self.__class__.__name__)
            # If mapping is not threaded and finished with OK
            if mapped_nffg is not None and not self.orchestrator.mapper.threaded:
                self._proceed_to_install_NFFG(mapped_nffg=mapped_nffg,
                                              original_request=nffg)
            else:
                log.warning(
                    "Something went wrong in service request instantiation: "
                    "mapped service request is missing!")
                self.__process_mapping_result(nffg_id=nffg.id, fail=True)
                stats.add_measurement_end_entry(type=stats.TYPE_ORCHESTRATION,
                                                info=LAYER_NAME + "-FAILED")
                self.raiseEventNoErrors(
                    InstantiationFinishedEvent,
                    id=nffg.id,
                    result=InstantiationFinishedEvent.MAPPING_ERROR)
        except ProcessorError as e:
            self.__process_mapping_result(nffg_id=nffg.id, fail=True)
            stats.add_measurement_end_entry(type=stats.TYPE_ORCHESTRATION,
                                            info=LAYER_NAME + "-DENIED")
            self.raiseEventNoErrors(
                InstantiationFinishedEvent,
                id=nffg.id,
                result=InstantiationFinishedEvent.REFUSED_BY_VERIFICATION,
                error=e)
Пример #18
0
    def map(cls, graph, resource):
        """
    Default mapping algorithm of ESCAPEv2.

    :param graph: Network Function forwarding Graph
    :type graph: :class:`NFFG`
    :param resource: global virtual resource info
    :type resource: :class:`NFFG`
    :return: mapped Network Function Forwarding Graph
    :rtype: :class:`NFFG`
    """
        log.info("Invoke mapping algorithm: %s - request: %s resource: %s" %
                 (cls.__name__, graph, resource))
        if graph is None:
            log.error("Missing request NFFG! Abort mapping process...")
            return
        if resource is None:
            log.error("Missing resource NFFG! Abort mapping process...")
            return
        try:
            # Run pre-mapping step to resolve target-less flowrules
            cls._resolve_external_ports(graph, resource)
            # Copy mapping config
            mapper_params = CONFIG.get_mapping_config(
                layer=cls.LAYER_NAME).copy()
            if 'mode' in mapper_params and mapper_params['mode']:
                log.debug("Setup mapping mode from configuration: %s" %
                          mapper_params['mode'])
            elif graph.mode:
                mapper_params['mode'] = graph.mode
                log.debug("Setup mapping mode based on request: %s" %
                          mapper_params['mode'])
            mapped_nffg = cls.call_mapping_algorithm(request=graph.copy(),
                                                     topology=resource.copy(),
                                                     **mapper_params)
            # Set mapped NFFG id for original SG request tracking
            log.debug("Move request metadata into mapping result...")
            mapped_nffg.id = graph.id
            mapped_nffg.name = "%s-%s-mapped" % (graph.name, cls.LAYER_NAME)
            # Explicitly copy metadata
            mapped_nffg.metadata = graph.metadata.copy()
            # Explicit copy of SAP data
            for sap in graph.saps:
                if sap.id in mapped_nffg:
                    mapped_nffg[sap.id].metadata = graph[
                        sap.id].metadata.copy()
            log.info("Mapping algorithm: %s is finished on NF-FG: %s" %
                     (cls.__name__, mapped_nffg))
            return mapped_nffg
        except MappingException as e:
            log.error(
                "Mapping algorithm unable to map given request! Cause:\n%s" %
                e.msg)
            log.warning("Mapping algorithm on %s is aborted!" % graph)
            return
        except BadInputException as e:
            log.error("Mapping algorithm refuse given input! Cause:\n%s" %
                      e.msg)
            log.warning("Mapping algorithm on %s is aborted!" % graph)
            return
        except InternalAlgorithmException as e:
            log.critical(
                "Mapping algorithm fails due to internal error! Cause:\n%s" %
                e.msg)
            log.warning("Mapping algorithm on %s is aborted!" % graph)
            return
        except:
            log.exception("Got unexpected error during mapping process!")
Пример #19
0
    def edit_config(self):
        """
    Receive configuration and initiate orchestration.

    :return: None
    """
        self.log.info("Call %s function: edit-config" % self.LOGGER_NAME)
        # Obtain NFFG from request body
        self.log.debug("Detected response format: %s" %
                       self.headers.get("Content-Type"))
        raw_body = self._get_body()
        # log.getChild("REST-API").debug("Request body:\n%s" % body)
        if raw_body is None or not raw_body:
            log.warning("Received data is empty!")
            self.send_error(400, "Missing body!")
            return
        # Expect XML format --> need to convert first
        if self.virtualizer_format_enabled:
            if self.headers.get("Content-Type") != "application/xml" and \
               not raw_body.startswith("<?xml version="):
                self.log.error(
                    "Received data is not in XML format despite of the "
                    "UNIFY interface is enabled!")
                self.send_error(415)
                return
            # Get received Virtualizer
            received_cfg = Virtualizer.parse_from_text(text=raw_body)
            self.log.log(VERBOSE,
                         "Received request for 'edit-config':\n%s" % raw_body)
            # If there was not get-config request so far
            if self.DEFAULT_DIFF:
                if self.server.last_response is None:
                    self.log.info(
                        "Missing cached Virtualizer! Acquiring topology now..."
                    )
                    config = self._proceed_API_call(self.API_CALL_GET_CONFIG)
                    if config is None:
                        self.log.error("Requested resource info is missing!")
                        self.send_error(404,
                                        message="Resource info is missing!")
                        return
                    elif config is False:
                        self.log.warning(
                            "Requested info is unchanged but has not found!")
                        self.send_error(404,
                                        message="Resource info is missing!")
                    else:
                        # Convert required NFFG if needed
                        if self.virtualizer_format_enabled:
                            self.log.debug(
                                "Convert internal NFFG to Virtualizer...")
                            converter = NFFGConverter(domain=None, logger=log)
                            v_topology = converter.dump_to_Virtualizer(
                                nffg=config)
                            # Cache converted data for edit-config patching
                            self.log.debug("Cache converted topology...")
                            self.server.last_response = v_topology
                        else:
                            self.log.debug("Cache acquired topology...")
                            self.server.last_response = config
                # Perform patching
                full_cfg = self.__recreate_full_request(diff=received_cfg)
            else:
                full_cfg = received_cfg
            self.log.log(VERBOSE, "Generated request:\n%s" % full_cfg.xml())
            # Convert response's body to NFFG
            self.log.info("Converting full request data...")
            converter = NFFGConverter(domain="REMOTE", logger=log)
            nffg = converter.parse_from_Virtualizer(vdata=full_cfg)
        else:
            if self.headers.get("Content-Type") != "application/json":
                self.log.error(
                    "Received data is not in JSON format despite of the "
                    "UNIFY interface is disabled!")
                self.send_error(415)
                return
            # Initialize NFFG from JSON representation
            self.log.info("Parsing request into internal NFFG format...")
            nffg = NFFG.parse(raw_body)
        self.log.debug("Parsed NFFG install request: %s" % nffg)
        self._proceed_API_call(self.API_CALL_EDIT_CONFIG, nffg)
        self.send_acknowledge()
        self.log.debug("%s function: edit-config ended!" % self.LOGGER_NAME)
Пример #20
0
    def _perform_mapping(self, input_graph, resource_view, continued=False):
        """
    Orchestrate mapping of given NF-FG on given global resource.

    :param input_graph: Network Function Forwarding Graph
    :type input_graph: :class:`NFFG`
    :param resource_view: global resource view
    :type resource_view: :any:`DomainVirtualizer`
    :return: mapped Network Function Forwarding Graph
    :rtype: :class:`NFFG`
    """
        if input_graph is None:
            log.error(
                "Missing mapping request information! Abort mapping process!")
            return None
        log.debug(
            "Request %s to launch orchestration on NF-FG: %s with View: "
            "%s, continued remap: %s" %
            (self.__class__.__name__, input_graph, resource_view, continued))
        # Steps before mapping (optional)
        log.debug("Request global resource info...")
        virt_resource = resource_view.get_resource_info()
        if virt_resource is None:
            log.error("Missing resource information! Abort mapping process!")
            return None
        # log a warning if resource is empty --> possibly mapping will be failed
        if virt_resource.is_empty():
            log.warning("Resource information is empty!")
        # Log verbose resource view if it is exist
        log.log(
            VERBOSE,
            "Orchestration Layer resource graph:\n%s" % virt_resource.dump())
        # Check if the mapping algorithm is enabled
        if not CONFIG.get_mapping_enabled(LAYER_NAME):
            log.warning("Mapping algorithm in Layer: %s is disabled! "
                        "Skip mapping step and return service request "
                        "to lower layer..." % LAYER_NAME)
            # virt_resource.id = input_graph.id
            # return virt_resource
            # Send request forward (probably to Remote ESCAPE)
            input_graph.status = NFFG.MAP_STATUS_SKIPPED
            log.debug("Mark NFFG status: %s!" % input_graph.status)
            return input_graph
        # Run actual mapping algorithm
        if self._threaded:
            # Schedule a microtask which run mapping algorithm in a Python thread
            log.info("Schedule mapping algorithm: %s in a worker thread" %
                     self.strategy.__name__)
            call_as_coop_task(self._start_mapping,
                              graph=input_graph,
                              resource=virt_resource)
            log.info("NF-FG: %s orchestration is finished by %s" %
                     (input_graph, self.__class__.__name__))
            # Return with None
            return None
        else:
            state = self.last_mapping_state if continued else None
            mapping_result = self.strategy.map(
                graph=input_graph,
                resource=virt_resource,
                persistent=self.persistent_state,
                pre_state=state)
            if isinstance(mapping_result, tuple or list):
                if len(mapping_result) == 2:
                    mapped_nffg = mapping_result[0]
                    self.persistent_state = mapping_result[1]
                    log.debug("Cache returned persistent state: %s" %
                              self.persistent_state)
                elif len(mapping_result) == 3:
                    mapped_nffg = mapping_result[0]
                    self.persistent_state = mapping_result[1]
                    log.debug("Cache returned persistent state: %s" %
                              self.persistent_state)
                    self.last_mapping_state = mapping_result[2]
                    log.debug("Cache returned mapping state: %s" %
                              self.last_mapping_state)
                else:
                    log.error("Mapping result is invalid: %s" %
                              repr(mapping_result))
                    mapped_nffg = None
            else:
                mapped_nffg = mapping_result
            # Check error result
            if mapped_nffg is None:
                log.error(
                    "Mapping process is failed! Abort orchestration process.")
            else:
                # Steps after mapping (optional)
                log.info(
                    "NF-FG: %s orchestration is finished by %s successfully!" %
                    (input_graph, self.__class__.__name__))
            log.debug("Last mapping state: %s" % self.last_mapping_state)
            if self.last_mapping_state:
                log.debug("Mapping iteration: %s" %
                          self.last_mapping_state.get_number_of_trials()
                          if self.last_mapping_state else None)
            return mapped_nffg