Beispiel #1
0
    def _initiate_cfor_api(self):
        """
    Initialize and setup REST API in a different thread.

    :return: None
    """
        # set bounded layer name here to avoid circular dependency problem
        handler = CONFIG.get_cfor_api_class()
        handler.bounded_layer = self._core_name
        params = CONFIG.get_cfor_agent_params()
        # can override from global config
        if 'prefix' in params:
            handler.prefix = params['prefix']
        if 'unify_interface' in params:
            handler.virtualizer_format_enabled = params['unify_interface']
        if 'diff' in params:
            handler.DEFAULT_DIFF = bool(params['diff'])
        address = (params.get('address'), params.get('port'))
        self.cfor_api = RESTServer(handler, *address)
        # Virtualizer ID of the Cf-Or interface
        self.cfor_api.api_id = handler.LOGGER_NAME = "Cf-Or"
        # Virtualizer type for Cf-Or API
        self.cfor_api.virtualizer_type = CONFIG.get_api_virtualizer(
            layer_name=LAYER_NAME, api_name=self.cfor_api.api_id)
        handler.log.info("Init REST-API for %s on %s:%s!" %
                         (self.cfor_api.api_id, address[0], address[1]))
        self.cfor_api.start()
        handler.log.debug(
            "Enforced configuration for %s: virtualizer type: %s, interface: %s, "
            "diff: %s" % (self.cfor_api.api_id, self.cfor_api.virtualizer_type,
                          "UNIFY" if handler.virtualizer_format_enabled else
                          "Internal-NFFG", handler.DEFAULT_DIFF))
Beispiel #2
0
    def orchestrate(self, input_graph, resource_view):
        """
    Abstract function for wrapping optional steps connected to orchestration.

    Implemented function call the mapping algorithm.

    If a derived class of :any:`AbstractMappingDataProcessor` is set in the
    global config under the name "PROCESSOR" then the this class performs
    pre/post mapping steps.

    After the pre/post-processor steps the relevant Mapping event will be
    raised on the main API class of the layer!

    :param input_graph: graph representation which need to be mapped
    :type input_graph: :any:`NFFG`
    :param resource_view: resource information
    :type resource_view: :any:`AbstractVirtualizer`
    :raise: NotImplementedError
    :return: mapped graph
    :rtype: :any:`NFFG`
    """
        # Get resource info
        resource_graph = resource_view.get_resource_info()
        # If validator is not None call the pre function
        if CONFIG.get_processor_enabled(layer=self._layer_name):
            # Preform pre-mapping validation
            if self.processor is not None and self.processor.pre_mapping_exec(
                    input_graph=input_graph, resource_graph=resource_graph):
                # Raise Error if processor function return with True
                raise ProcessorError("Pre mapping validation is failed!")
        # Raise event for external POX modules
        if core.hasComponent(self._layer_name):
            core.components[self._layer_name].raiseEvent(
                PreMapEvent,
                input_graph=input_graph,
                resource_graph=resource_graph)
        # Invoke mapping algorithm
        mapping_result = self._perform_mapping(input_graph=input_graph,
                                               resource_view=resource_view)
        # Perform post-mapping validation
        # If the mapping is threaded skip post mapping here
        if not self._threaded:
            # If validator is not None call the post function
            if CONFIG.get_processor_enabled(layer=self._layer_name):
                if self.processor is not None and self.processor.post_mapping_exec(
                        input_graph=input_graph,
                        resource_graph=resource_graph,
                        result_graph=mapping_result):
                    # Raise Error if processor function return with True
                    raise ProcessorError("Post mapping validation is failed!")
            # Raise event for external POX modules
            if core.hasComponent(self._layer_name):
                core.components[self._layer_name].raiseEvent(
                    PostMapEvent,
                    input_graph=input_graph,
                    resource_graph=resource_graph,
                    result_graph=mapping_result)
        # Return the mapped NFFG
        return mapping_result
Beispiel #3
0
  def _all_dependencies_met (self):
    """
    Called when every component on which depends are initialized on POX core.

    Contain dependency relevant initialization.

    :return: None
    """
    try:
      self.initialize()
      # With fully event-driven communication between the layers the dependency
      # handling takes care by listen_to_dependencies() run into a dead-lock.
      # The root of this problem is the bidirectional or cyclic dependency
      # between the components, so basically the layers will always wait to each
      # other to be registered on core. To avoid this situation the naming
      # convention of event handlers on which the dependency checking based is
      # not followed (a.k.a. leave _handle_<component name>_<event name>) and
      # the event listeners is set up manually. For automatic core registration
      # the components have to contain dependencies explicitly.
      for dep in self.dependencies:
        if not self._standalone:
          if core.core.hasComponent(dep):
            dep_layer = core.components[dep]
            # Register actual event handlers on dependent layer
            dep_layer.addListeners(self)
            # Register dependent layer's event handlers on actual layer
            self.addListeners(dep_layer)
          else:
            raise AttributeError("Component is not registered on core")
        else:
          # In case of standalone mode set up a StandaloneHelper in this object
          # with the name of the dependency to handle raised events
          # automatically
          setattr(self, dep, SimpleStandaloneHelper(self, dep))
      # Subscribe for GoingDownEvent to finalize API classes
      # shutdown() function will be called if POX's core going down
      core.addListenerByName('GoingDownEvent', self.shutdown)
      # Subscribe core event for advanced functions
      # Listeners' name must follow POX naming conventions
      core.addListeners(self)
      # Everything is set up an "running" so register the component on pox.core
      # as a final step. Other dependent component can finish initialization
      # now.
      core.core.register(self._core_name, self)
      # Set "running" config for convenience purposes
      CONFIG.set_layer_loaded(self._core_name)
    except KeyboardInterrupt:
      quit_with_error(
        msg="Initialization of %s was interrrupted by user!" %
            self.__class__.__name__)
    except Exception as e:
      quit_with_error(msg="Abort ESCAPEv2 initialization...", exception=e)
Beispiel #4
0
    def __init__(self, layer_API, mapper=None, strategy=None):
        """
    Init.

    :param layer_API: reference os the actual layer performing the orchestration
    :type layer_API: :any:`AbstractAPI`
    :param mapper: additional mapper class (optional)
    :type mapper: :any:`AbstractMapper`
    :param strategy: override strategy class for the used Mapper (optional)
    :type strategy: :any:`AbstractMappingStrategy`
    :return: None
    """
        layer_name = layer_API._core_name
        # Set Mapper
        if mapper is None:
            # Use the Mapper in CONFIG
            mapper = CONFIG.get_mapper(layer_name)
            if mapper is None and self.DEFAULT_MAPPER is not None:
                # Use de default Mapper if it's set
                self.mapper = self.DEFAULT_MAPPER
            if mapper is None:
                raise RuntimeError("Mapper class is not found!")
        assert issubclass(mapper, AbstractMapper), "Mapper is not subclass of " \
                                                   "AbstractMapper!"
        self.mapper = mapper(strategy=strategy)
        # Init Mapper listeners
        # Listeners must be weak references in order the layer API can garbage
        # collected
        # self.mapper is set by the AbstractOrchestrator's constructor
        self.mapper.addListeners(layer_API, weak=True)
        super(AbstractOrchestrator, self).__init__()
Beispiel #5
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
Beispiel #6
0
  def build (self, topo=None):
    """
    Initialize network.

    1. If the additional ``topology`` is given then using that for init.
    2. If TOPO is not given, search topology description in CONFIG with the \
    name 'TOPO'.
    3. If TOPO not found or an Exception was raised, search for the fallback \
    topo with the name ``FALLBACK-TOPO``.
    4. If FALLBACK-TOPO not found raise an exception or run a bare Mininet \
    object if the run_dry attribute is set


    :param topo: optional topology representation
    :type topo: :any:`NFFG` or :any:`AbstractTopology` or ``None``
    :return: object representing the emulated network
    :rtype: :any:`ESCAPENetworkBridge`
    """
    log.debug("Init emulated topology based on Mininet v%s" % MNVERSION)
    # Load topology
    try:
      if topo is None:
        log.info("Get Topology description from CONFIG...")
        self.__init_from_CONFIG()
      elif isinstance(topo, NFFG):
        log.info("Get Topology description from given NFFG...")
        self.__init_from_NFFG(nffg=topo)
      elif isinstance(topo, basestring) and topo.startswith('/'):
        log.info("Get Topology description from given file...")
        self.__init_from_file(path=topo)
      elif isinstance(topo, AbstractTopology):
        log.info("Get Topology description based on Topology class...")
        self.__init_from_AbstractTopology(topo_class=topo)
      else:
        raise TopologyBuilderException(
          "Unsupported topology format: %s - %s" % (type(topo), topo))
      return self.get_network()
    except SystemExit as e:
      quit_with_error(msg="Mininet exited unexpectedly!", logger=log,
                      exception=e)
    except TopologyBuilderException:
      if self.fallback:
        # Search for fallback topology
        fallback = CONFIG.get_fallback_topology()
        if fallback:
          log.info("Load topo from fallback topology description...")
          self.__init_from_AbstractTopology(fallback)
          return self.get_network()
      # fallback topo is not found or set
      if self.run_dry:
        # Return with the bare Mininet object
        log.warning("Topology description is not found! Running dry...")
        return self.get_network()
      else:
        # Re-raise the exception
        raise
    except KeyboardInterrupt:
      quit_with_error(
        msg="Assembly of Mininet network was interrupted by user!",
        logger=log)
Beispiel #7
0
    def load_component(self, component_name, params=None, parent=None):
        """
    Load given component (DomainAdapter/DomainManager) from config.
    Initiate the given component class, pass the additional attributes,
    register the event listeners and return with the newly created object.

    :param component_name: component's config name
    :type component_name: str
    :param params: component parameters
    :type params: dict
    :param parent: define the parent of the actual component's configuration
    :type parent: dict
    :return: initiated component
    :rtype: :any:`AbstractESCAPEAdapter` or :any:`AbstractDomainManager`
    """
        try:
            # Get component class
            component_class = CONFIG.get_component(component=component_name,
                                                   parent=parent)
            # If it's found
            if component_class is not None:
                # Get optional parameters of this component
                if not params:
                    params = CONFIG.get_component_params(
                        component=component_name, parent=parent)
                # Initialize component
                component = component_class(**params)
                # Set up listeners for e.g. DomainChangedEvents
                component.addListeners(self._ca)
                # Set up listeners for DeployNFFGEvent
                component.addListeners(self._ca._layer_API)
                # Return the newly created object
                return component
            else:
                log.error(
                    "Configuration of '%s' is missing. Skip initialization!" %
                    component_name)
                raise ConfigurationError("Missing component configuration!")
        except AttributeError:
            log.error("%s is not found. Skip component initialization!" %
                      component_name)
            raise
        except ImportError:
            log.error(
                "Could not import module: %s. Skip component initialization!" %
                component_name)
            raise
Beispiel #8
0
 def __init__(self):
     """
 Init.
 """
     super(GlobalResourceManager, self).__init__()
     log.debug("Init DomainResourceManager")
     self.__dov = DomainVirtualizer(self)  # Domain Virtualizer
     self.__tracked_domains = set()  # Cache for detected and stored domains
     self._remerge = CONFIG.use_remerge_update_strategy()
Beispiel #9
0
  def _perform_mapping (self, input_graph, resource_view):
    """
    Orchestrate mapping of given service graph on given virtual resource.

    :param input_graph: Service Graph
    :type input_graph: :any:`NFFG`
    :param resource_view: virtual resource view
    :param resource_view: :any:`AbstractVirtualizer`
    :return: Network Function Forwarding Graph
    :rtype: :any:`NFFG`
    """
    if input_graph is None:
      log.error("Missing service request information! Abort mapping process!")
      return None
    log.debug("Request %s to launch orchestration on SG: %s with View: %s" % (
      self.__class__.__name__, input_graph, resource_view))
    # Steps before mapping (optional)
    log.debug("Request resource info from layer virtualizer...")
    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, "Service layer resource graph:\n%s" % virt_resource.dump())
    # resource_view.sanity_check(input_graph)
    # 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 "
        "forward service request to lower layer..." % LAYER_NAME)
      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("SG: %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)
      # Steps after mapping (optional) if the mapping was not threaded
      if mapped_nffg is None:
        log.error("Mapping process is failed! Abort orchestration process.")
      else:
        log.info("SG: %s orchestration is finished by %s successfully!" % (
          input_graph, self.__class__.__name__))
      return mapped_nffg
Beispiel #10
0
    def __init__(self, layer_name, strategy=None, threaded=None):
        """
    Initialize Mapper class.

    Set given strategy class and threaded value or check in `CONFIG`.

    If no valid value is found for arguments set the default params defined
    in `_default`.

    .. warning::
      Strategy classes must be a subclass of AbstractMappingStrategy

    :param layer_name: name of the layer which initialize this class. This
      value is used to search the layer configuration in `CONFIG`
    :type layer_name: str
    :param strategy: strategy class (optional)
    :type strategy: :any:`AbstractMappingStrategy`
    :param threaded: run mapping algorithm in separate Python thread instead
      of in the coop microtask environment (optional)
    :type threaded: bool
    :return: None
    """
        self._layer_name = layer_name
        # Set threaded
        self._threaded = threaded if threaded is not None else CONFIG.get_threaded(
            layer_name)
        # Set strategy
        if strategy is None:
            # Use the Strategy in CONFIG
            strategy = CONFIG.get_strategy(layer_name)
            if strategy is None and self.DEFAULT_STRATEGY is not None:
                # Use the default Strategy if it's set
                strategy = self.DEFAULT_STRATEGY
            if strategy is None:
                raise RuntimeError("Strategy class is not found!")
        self.strategy = strategy
        assert issubclass(strategy,
                          AbstractMappingStrategy), "Mapping strategy is not " \
                                                    "subclass of " \
                                                    "AbstractMappingStrategy!"
        self.processor = CONFIG.get_mapping_processor(layer_name)(layer_name)
        super(AbstractMapper, self).__init__()
Beispiel #11
0
    def load_default_mgrs(self):
        """
    Initiate and start default DomainManagers defined in CONFIG.

    :return: None
    """
        log.info("Initialize additional DomainManagers from config...")
        # very dummy initialization
        mgrs = CONFIG.get_managers()
        if not mgrs:
            log.info("No DomainManager has been configured!")
            return
        for mgr_name in mgrs:
            # Get manager parameters from config
            mgr_cfg = CONFIG.get_component_params(component=mgr_name)
            if 'domain_name' in mgr_cfg:
                if mgr_cfg['domain_name'] in self.domains:
                    log.warning(
                        "Domain name collision! Domain Manager: %s has already "
                        "initiated with the domain name: %s" %
                        (self.get_component_by_domain(
                            domain_name=mgr_cfg['domain_name']),
                         mgr_cfg['domain_name']))
            else:
                # If no domain name was given, use the manager config name by default
                mgr_cfg['domain_name'] = mgr_name
            # Get manager class
            mgr_class = CONFIG.get_component(component=mgr_name)
            if mgr_class.IS_LOCAL_MANAGER:
                loaded_local_mgr = [
                    name for name, mgr in self.__repository.iteritems()
                    if mgr.IS_LOCAL_MANAGER
                ]
                if loaded_local_mgr:
                    log.warning(
                        "A local DomainManager has already been initiated with "
                        "the name: %s! Skip initiating DomainManager: %s" %
                        (loaded_local_mgr, mgr_name))
                    return
            log.debug("Load DomainManager based on config: %s" % mgr_name)
            # Start domain manager
            self.start_mgr(name=mgr_name, mgr_params=mgr_cfg)
Beispiel #12
0
    def shutdown(self):
        """
    Shutdown ControllerAdapter, related components and stop DomainManagers.

    :return: None
    """
        # Clear DomainManagers config if needed
        if CONFIG.clear_domains_after_shutdown() is True:
            self.domains.clear_initiated_mgrs()
        # Stop initiated DomainManagers
        self.domains.stop_initiated_mgrs()
Beispiel #13
0
    def setup_topology(self, nffg):
        """
    Modify the hwloc topology according to the config file.

    :return: the modified topology description
    :rtype: :any:`NFFG`
    """
        params = CONFIG.get_un_params()

        saps = [sap.id for sap in nffg.saps]

        dpdk_saps = [sap.id for sap in nffg.saps if sap.id.startswith("dpdk")]

        dpdk_lcore = params["ovs_pus"].keys()[0]

        for infra in nffg.infras:

            connected_saps = [
                link for u, v, link in nffg.real_out_edges_iter(infra.id)
                if link.dst.node.id in saps
            ]

            for link in connected_saps:
                if link.dst.node.id in params["inner_saps"]:
                    old_id = link.dst.node.id
                    new_sap = link.dst.node
                    new_sap.id = link.dst.node.id + "-" + "inner"
                    new_sap.name = link.dst.node.name + "-" + "inner"
                    nffg.add_sap(sap_obj=new_sap)
                    nffg.del_node(old_id)
                    nffg.add_link(link.src, link.dst, link=link)
                else:
                    old_id = link.dst.node.id
                    new_sap = link.dst.node
                    new_sap.id = link.dst.node.id + "-" + params["domain"]
                    new_sap.name = link.dst.node.name + "-" + params["domain"]
                    nffg.add_sap(sap_obj=new_sap)
                    nffg.del_node(old_id)
                    nffg.add_link(link.src, link.dst, link=link)

            if infra.infra_type not in (NFFG.TYPE_INFRA_EE,
                                        NFFG.TYPE_INFRA_STATIC_EE):
                continue
            elif infra.id in params["ovs_pus"]:
                if infra.id == dpdk_lcore:
                    infra.supported = ["ovs"]
                else:
                    infra.supported = list(params["ovs_pus"][infra.id])
                    infra.supported.append("VHOST")
                    infra.supported.append("KNI")
            else:
                infra.supported = list(params["supported_vnfs"])
        return nffg
Beispiel #14
0
  def runXTerms (self):
    """
    Start an xterm to every SAP if it's enabled in the global config. SAP are
    stored as hosts in the Mininet class.

    :return: None
    """
    if CONFIG.get_SAP_xterms():
      log.debug("Starting xterm on SAPS...")
      terms = makeTerms(nodes=self.__mininet.hosts, title='SAP', term="xterm")
      self.xterms.extend(terms)
    else:
      log.warning("Skip starting xterms on SAPS according to global config")
Beispiel #15
0
  def __init_from_CONFIG (self, format=DEFAULT_NFFG_FORMAT):
    """
    Build a pre-defined topology from an NFFG stored in a file.
    The file path is searched in CONFIG with tha name ``TOPO``.

    :param format: NF-FG storing format (default: internal NFFG representation)
    :type format: str
    :return: None
    """
    path = CONFIG.get_mininet_topology()
    if path is None:
      raise TopologyBuilderException("Missing Topology!")
    self.__init_from_file(path=path, format=format)
Beispiel #16
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!")
Beispiel #17
0
  def _initiate_rest_api (self):
    """
    Initialize and set up REST API in a different thread.

    :return: None
    """
    # set bounded layer name here to avoid circular dependency problem
    handler = CONFIG.get_sas_api_class()
    handler.bounded_layer = self._core_name
    params = CONFIG.get_sas_agent_params()
    # can override from global config
    if 'prefix' in params:
      handler.prefix = params['prefix']
    if 'unify_interface' in params:
      handler.virtualizer_format_enabled = params['unify_interface']
    address = (params.get('address'), params.get('port'))
    self.rest_api = RESTServer(handler, *address)
    self.rest_api.api_id = handler.LOGGER_NAME = "U-Sl"
    handler.log.debug("Init REST-API for %s on %s:%s!" % (
      self.rest_api.api_id, address[0], address[1]))
    self.rest_api.start()
    handler.log.debug("Enforced configuration for %s: interface: %s" % (
      self.rest_api.api_id,
      "UNIFY" if handler.virtualizer_format_enabled else "Internal-NFFG"))
Beispiel #18
0
    def __init__(self,
                 url=None,
                 rpc=None,
                 timeout=DEFAULT_TIMEOUT,
                 instance_id=None):
        """
    Init.

    :param url: URL of the remote server
    :type url: str
    :param rpc: RPC name
    :type rpc: str
    :param timeout: connections timeout
    :type timeout: int
    :param instance_id: additional id to join to the end of the id
    :type instance_id: str
    :return: None
    """
        super(RemoteVisualizer, self).__init__()
        self.log = core.getLogger("visualizer")
        if url is None:
            url = CONFIG.get_visualization_url()
        if rpc is None:
            rpc = CONFIG.get_visualization_rpc()
        self._url = urlparse.urljoin(url, rpc)
        if self._url is None:
            raise RuntimeError("Missing URL from %s" % self.__class__.__name__)
        self._timeout = timeout
        if instance_id is None:
            self.instance_id = CONFIG.get_visualization_instance_id()
        self.log.info("Setup remote Visualizer with URL: %s" % self._url)
        # Store the last request
        self._response = None
        self.converter = NFFGConverter(domain="ESCAPE", logger=self.log)
        # Suppress low level logging
        self.__suppress_requests_logging()
Beispiel #19
0
  def get_network (self):
    """
    Return the bridge to the constructed network.

    :return: object representing the emulated network
    :rtype: :any:`ESCAPENetworkBridge`
    """
    if self.mn_bridge is None:
      # Create the Interface object and set the topology description as the
      # original NFFG
      self.mn_bridge = ESCAPENetworkBridge(network=self.mn,
                                           topo_desc=self.topo_desc)
      # Additional settings
      self.mn_bridge._need_clean = CONFIG.get_clean_after_shutdown()
    return self.mn_bridge
Beispiel #20
0
  def create_NETCONF_EE (self, name, type=TYPE_EE_LOCAL, **params):
    """
    Create and add a new EE to Mininet network.

    The type of EE can be {local|remote} NETCONF-based.

    :param name: name of the EE: switch: name, agent: agt_+'name'
    :type name: str
    :param type: type of EE {local|remote}
    :type type: str
    :param opts: additional options for the switch in EE
    :type opts: str
    :param dpid: remote switch DPID (remote only)
    :param username: NETCONF username (remote only)
    :param passwd: NETCONF password (remote only)
    :param ip: control Interface for the agent (optional)
    :param agentPort: port to listen on for NETCONF connections, (else set \
    automatically)
    :param minPort: first VNF control port which can be used (else set \
    automatically)
    :param cPort: number of VNF control ports (and VNFs) which can be used ( \
    default: 10)
    :return: tuple of newly created :class:`mininet.node.Agent` and \
    :class:`mininet.node.Switch` object
    :rtype: tuple
    """
    type = type.upper()
    cfg = CONFIG.get_EE_params()
    cfg.update(params)
    cfg['dpid'] = self.__get_new_dpid()
    if type == self.TYPE_EE_LOCAL:
      # create local NETCONF-based
      log.debug("Create local NETCONF EE with name: %s" % name)
      sw = self.mn.addSwitch(name, **cfg)
    elif type == self.TYPE_EE_REMOTE:
      # create remote NETCONF-based
      log.debug("Create remote NETCONF EE with name: %s" % name)
      cfg["inNamespace"] = False
      sw = self.mn.addRemoteSwitch(name, cls=None, **cfg)
    else:
      raise TopologyBuilderException(
        "Unsupported NETCONF-based EE type: %s!" % type)
    agt = self.mn.addAgent('agt_' + name, cls=None, **cfg)
    agt.setSwitch(sw)
    return agt, sw
Beispiel #21
0
 def initialize (self):
   """
   .. seealso::
     :func:`AbstractAPI.initialize() <escape.util.api.AbstractAPI.initialize>`
   """
   log.debug("Initializing Service Layer...")
   self.__sid = CONFIG.get_service_layer_id()
   if self.__sid is not None:
     log.debug("Setup ID for Service Layer: %s" % self.__sid)
   else:
     self.__sid = self.LAYER_ID
     log.error(
       "Missing ID of Service Layer from config. Using default value: %s" %
       self.__sid)
   # Set element manager
   self.elementManager = ClickManager()
   # Init central object of Service layer
   self.service_orchestrator = ServiceOrchestrator(self)
   # Read input from file if it's given and initiate SG
   if self._sg_file:
     try:
       service_request = self._read_data_from_file(self._sg_file)
       log.info("Graph representation is loaded successfully!")
       if service_request.startswith('{'):
         log.debug("Detected format: JSON - Parsing from NFFG format...")
         nffg = NFFG.parse(raw_data=service_request)
       elif service_request.startswith('<'):
         log.debug("Detected format: XML - Parsing from Virtualizer format...")
         converter = NFFGConverter(domain="INTERNAL", logger=log)
         nffg = converter.parse_from_Virtualizer(vdata=service_request)
       else:
         log.warning("Detected unexpected format...")
         return
       log.info("Schedule service request delayed by 3 seconds...")
       self.api_sas_sg_request_delayed(service_nffg=nffg)
     except (ValueError, IOError, TypeError) as e:
       log.error(
         "Can't load service request from file because of: " + str(e))
   else:
     # Init REST-API if no input file is given
     self._initiate_rest_api()
   # Init GUI
   if self._gui:
     self._initiate_gui()
   log.info("Service Layer has been initialized!")
Beispiel #22
0
  def create_SAP (self, name, cls=None, **params):
    """
    Create and add a new SAP to Mininet network.

    Additional parameters are keyword arguments depend on and forwarded to
    the initiated Host class type.

    :param name: name of SAP
    :type name: str
    :param cls: custom hosts class/constructor (optional)
    :type cls: :class:`mininet.node.Host`
    :return: newly created Host object as the SAP
    :rtype: :class:`mininet.node.Host`
    """
    log.debug("Create SAP with name: %s" % name)
    cfg = CONFIG.get_SAP_params()
    cfg.update(params)
    return self.mn.addHost(name=name, cls=cls, **cfg)
Beispiel #23
0
    def _handle_GetVirtResInfoEvent(self, event):
        """
    Generate virtual resource info and send back to SAS.

    :param event: event object contains service layer id
    :type event: :any:`GetVirtResInfoEvent`
    :return: None
    """
        log.getChild('API').debug(
            "Received <Virtual View> request from %s layer" %
            str(event.source._core_name).title())
        # Currently view is a Virtualizer to keep ESCAPE fast
        # Virtualizer type for Sl-Or API
        virtualizer_type = CONFIG.get_api_virtualizer(layer_name=LAYER_NAME,
                                                      api_name=event.sid)
        v = self.resource_orchestrator.virtualizerManager.get_virtual_view(
            event.sid, type=virtualizer_type)
        log.getChild('API').debug("Sending back <Virtual View>: %s..." % v)
        self.raiseEventNoErrors(VirtResInfoEvent, v)
Beispiel #24
0
  def get_topology_resource (self):
    """
    Return with the topology description as an :any:`NFFG`.

    :return: the emulated topology description
    :rtype: :any:`NFFG`
    """
    # Return cached topo if it exists
    if self.cache:
      return self.cache
    # Assemble shell command
    cmd_hwloc2nffg = [os.path.normpath(os.path.join(
      CONFIG.get_project_root_dir(), self.HWLOC2NFFG_BIN))]
    # Add hwlock params
    cmd_hwloc2nffg.extend(self.HWLOC_PARAMS)
    log.debug("Used command: %s" % cmd_hwloc2nffg)
    # Run command
    raw_data = run_cmd(cmd_hwloc2nffg)
    # Basic validation
    if not raw_data.startswith('{'):
      if "not found" in raw_data:
        # hwloc2nffg binary not found
        raise RuntimeError(
          "hwloc2nffg binary was not found under the path: %s" % cmd_hwloc2nffg)
      elif "No such file" in raw_data:
        # Shared library not found
        raise RuntimeError(
          "dependent package of hwloc2nffg is missing: %s" % raw_data)
      else:
        # unexpected error
        raise RuntimeError(raw_data)
    # Parse raw data
    topo = NFFG.parse(raw_data)
    # Modify static topo
    self.setup_topology(topo)
    # Duplicate links for bidirectional connections
    topo.duplicate_static_links()
    # Rewrite infra domains
    self.cache = self.rewrite_domain(nffg=topo)
    print self.cache.dump()
    return self.cache
Beispiel #25
0
  def create_Link (self, src, dst, src_port=None, dst_port=None, **params):
    """
    Create an undirected connection between src and dst.

    Source and destination ports can be given optionally:

    :param src: source Node
    :param dst: destination Node
    :param src_port: source Port (optional)
    :param dst_port: destination Port (optional)
    :param params: additional link parameters
    :return:
    """
    log.debug("Create Link %s%s <--> %s%s" % (
      src, ":%s" % src_port if src_port is not None else "", dst,
      ":%s" % dst_port if dst_port is not None else ""))
    remote = filter(lambda n: isinstance(n, RemoteSwitch), [src, dst])
    local = filter(lambda n: not isinstance(n, RemoteSwitch), [src, dst])
    cfg = CONFIG.get_Link_params()
    cfg.update(params)
    if not remote:
      self.mn.addLink(src, dst, src_port, dst_port, **cfg)
    else:
      # sw = local[0]  # one of the local Node
      # r = remote[0]  # other Node which is the remote
      # intfName = r.params['local_intf_name']
      # r_mac = None  # unknown, r.params['remote_mac']
      # r_port = r.params['remote_port']
      # # self._debug('\tadd hw interface (%s) to node (%s)' % (intfName,
      # # sw.name))
      # # This hack avoids calling __init__ which always makeIntfPair()
      # link = Link.__new__(Link)
      # i1 = Intf(intfName, node=sw, link=link)
      # i2 = Intf(intfName, node=r, mac=r_mac, port=r_port, link=link)
      # i2.mac = r_mac  # mn runs 'ifconfig', which resets mac to None
      # link.intf1, link.intf2 = i1, i2
      raise TopologyBuilderException(
        "Remote Link creation is not supported yet!")
Beispiel #26
0
  def create_Controller (self, name, controller=None, **params):
    """
    Create and add a new OF controller to Mininet network.

    Additional parameters are keyword arguments depend on and forwarded to
    the initiated Controller class type.

    .. warning::
      Should not call this function and use the default InternalControllerProxy!

    :param name: name of controller
    :type name: str
    :param controller: custom controller class/constructor (optional)
    :type controller: :class:`mininet.node.Controller`
    :param inNamespace: override the controller spawn in namespace (optional)
    :type inNamespace: bool
    :return: newly created Controller object
    :rtype: :class:`mininet.node.Controller`
    """
    log.debug("Create Controller with name: %s" % name)
    cfg = CONFIG.get_Controller_params()
    cfg.update(params)
    return self.mn.addController(name=name, controller=controller, **cfg)
Beispiel #27
0
  def create_static_EE (self, name, cls=None, **params):
    """
    Create and add a new EE to Mininet in the static way.

    This function is for only backward compatibility.

    .. warning::
      Not tested yet!

    :param name: name of the Execution Environment
    :type name: str
    :param cls: custom EE class/constructor (optional)
    :type cls: :class:`mininet.node.EE`
    :param cores: Specify (real) cores that our cgroup can run on (optional)
    :type cores: list
    :param frac: Set overall CPU fraction for this EE (optional)
    :type frac: list
    :param vlanif: set vlan interfaces (optional)
    :type vlanif: list
    :return: newly created EE object
    :rtype: :class:`mininet.node.EE`
    """
    # create static EE
    cfg = CONFIG.get_EE_params()
    cfg.update(params)
    cfg['dpid'] = self.__get_new_dpid()
    log.debug("Create static EE with name: %s" % name)
    ee = self.mn.addEE(name=name, cls=cls, **cfg)
    if 'cores' in cfg:
      ee.setCPUs(**cfg['cores'])
    if 'frac' in cfg:
      ee.setCPUFrac(**cfg['frac'])
    if 'vlanif' in cfg:
      for vif in cfg['vlaninf']:
        ee.cmdPrint('vconfig add ' + name + '-eth0 ' + vif[1])
        ee.cmdPrint('ifconfig ' + name + '-eth0.' + vif[1] + ' ' + vif[0])
    return ee
Beispiel #28
0
  def create_Switch (self, name, cls=None, **params):
    """
    Create and add a new OF switch instance to Mininet network.

    Additional parameters are keyword arguments depend on and forwarded to
    the initiated Switch class type.

    :param name: name of switch
    :type name: str
    :param cls: custom switch class/constructor (optional)
    :type cls: :class:`mininet.node.Switch`
    :param dpid: DPID for switch (default: derived from name)
    :type dpid: str
    :param opts: additional switch options
    :type opts: str
    :param listenPort: custom listening port (optional)
    :type listenPort: int
    :param inNamespace: override the switch spawn in namespace (optional)
    :type inNamespace: bool
    :param of_ver: override OpenFlow version (optional)
    :type of_ver: int
    :param ip: set IP address for the switch (optional)
    :type ip:
    :return: newly created Switch object
    :rtype: :class:`mininet.node.Switch`
    """
    log.debug("Create Switch with name: %s" % name)
    cfg = CONFIG.get_Switch_params()
    cfg.update(params)
    cfg['dpid'] = self.__get_new_dpid()
    sw = self.mn.addSwitch(name=name, cls=cls, **cfg)
    if 'of_ver' in cfg:
      sw.setOpenFlowVersion(cfg['of_ver'])
    if 'ip' in cfg:
      sw.setSwitchIP(cfg['ip'])
    return sw
Beispiel #29
0
    def install_nffg(self, mapped_nffg):
        """
    Start NF-FG installation.

    Process given :any:`NFFG`, slice information self.__global_nffg on
    domains and invoke DomainManagers to install domain specific parts.

    :param mapped_nffg: mapped NF-FG instance which need to be installed
    :type mapped_nffg: NFFG
    :return: mapping result
    :rtype: bool
    """
        log.debug("Invoke %s to install NF-FG(%s)" %
                  (self.__class__.__name__, mapped_nffg.name))
        # # Notify remote visualizer about the deployable NFFG if it's needed
        # notify_remote_visualizer(data=mapped_nffg, id=LAYER_NAME)
        slices = NFFGToolBox.split_into_domains(nffg=mapped_nffg, log=log)
        if slices is None:
            log.warning("Given mapped NFFG: %s can not be sliced! "
                        "Skip domain notification steps" % mapped_nffg)
            return
        log.debug("Notify initiated domains: %s" %
                  [d for d in self.domains.initiated])
        # TODO - abstract/inter-domain tag rewrite
        # NFFGToolBox.rewrite_interdomain_tags(slices)
        mapping_result = True
        for domain, part in slices:
            log.debug(
                "Recreate missing TAG matching fields in domain part: %s..." %
                domain)
            # Temporarily rewrite/recreate TAGs here
            NFFGToolBox.recreate_match_TAGs(nffg=part, log=log)
            # Get Domain Manager
            domain_mgr = self.domains.get_component_by_domain(
                domain_name=domain)
            if domain_mgr is None:
                log.warning(
                    "No DomainManager has been initialized for domain: %s! "
                    "Skip install domain part..." % domain)
                continue
            log.log(VERBOSE,
                    "Splitted domain: %s part:\n%s" % (domain, part.dump()))
            log.info("Delegate splitted part: %s to %s" % (part, domain_mgr))
            # Rebind requirement link fragments as e2e reqs
            part = NFFGToolBox.rebind_e2e_req_links(nffg=part, log=log)
            # Check if need to reset domain before install
            if CONFIG.reset_domains_before_install():
                log.debug("Reset %s domain before deploying mapped NFFG..." %
                          domain_mgr.domain_name)
                domain_mgr.clear_domain()
            # Invoke DomainAdapter's install
            res = domain_mgr.install_nffg(part)
            # Update the DoV based on the mapping result covering some corner case
            if not res:
                log.error("Installation of %s in %s was unsuccessful!" %
                          (part, domain))
            # Note result according to others before
            mapping_result = mapping_result and res
            # If installation of the domain was performed without error
            if not res:
                log.warning("Skip DoV update with domain: %s! Cause: "
                            "Domain installation was unsuccessful!" % domain)
                continue
            # If the domain manager does not poll the domain update here
            # else polling takes care of domain updating
            if isinstance(domain_mgr,
                          AbstractRemoteDomainManager) and domain_mgr._poll:
                log.info("Skip explicit DoV update for domain: %s. "
                         "Cause: polling enabled!" % domain)
                continue
            # If the internalDM is the only initiated mgr, we can override the
            # whole DoV
            if domain_mgr.IS_LOCAL_MANAGER:
                if mapped_nffg.is_SBB():
                    # If the request was a cleanup request, we can simply clean the DOV
                    if mapped_nffg.is_bare():
                        log.debug(
                            "Detected cleanup topology (no NF/Flowrule/SG_hop)! Clean DoV..."
                        )
                        self.DoVManager.clean_domain(domain=domain)
                    # If the reset contains some VNF, cannot clean or override
                    else:
                        log.warning(
                            "Detected SingleBiSBiS topology! Local domain has been already "
                            "cleared, skip DoV update...")
                # If the the topology was a GLOBAL view, just override the whole DoV
                elif not mapped_nffg.is_virtualized():
                    self.DoVManager.set_global_view(nffg=mapped_nffg)
                else:
                    log.warning(
                        "Detected virtualized Infrastructure node in mapped NFFG! Skip "
                        "DoV update...")
                # In case of Local manager skip the rest of the update
                continue
            # Explicit domain update
            self.DoVManager.update_domain(domain=domain, nffg=part)
        log.debug("NF-FG installation is finished by %s" %
                  self.__class__.__name__)
        # Post-mapping steps
        if mapping_result:
            log.info(
                "All installation process has been finished with success! ")
            # Notify remote visualizer about the installation result if it's needed
            notify_remote_visualizer(
                data=self.DoVManager.dov.get_resource_info(), id=LAYER_NAME)
        else:
            log.error("%s installation was not successful!" % mapped_nffg)
        return mapping_result