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))
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
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)
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__()
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
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)
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
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()
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
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__()
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)
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()
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
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")
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)
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!")
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"))
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()
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
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
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!")
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)
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)
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
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!")
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)
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
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
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