Example #1
0
  def __init__ (self, network=None, topo_desc=None):
    """
    Initialize Mininet implementation with proper attributes.
    Use network as the hided Mininet topology if it's given.

    :param topo_desc: static topology description e.g. the related NFFG
    :type topo_desc: :any:`NFFG`
    :param network: use this specific Mininet object for init (default: None)
    :type network: :class:`mininet.net.MininetWithControlNet`
    :return: None
    """
    log.debug("Init ESCAPENetworkBridge with topo description: %s" % topo_desc)
    if network is not None:
      self.__mininet = network
    else:
      log.warning(
        "Network implementation object is missing! Use Builder class instead "
        "of direct initialization. Creating bare Mininet object anyway...")
      self.__mininet = MininetWithControlNet()
    # Topology description which is emulated by the Mininet
    self.topo_desc = topo_desc
    # Duplicate static links for ensure undirected neighbour relationship
    if self.topo_desc is not None:
      back_links = [l.id for u, v, l in
                    self.topo_desc.network.edges_iter(data=True) if
                    l.backward is True]
      if len(back_links) == 0:
        log.debug("No backward link has been detected! Duplicate STATIC links "
                  "to ensure undirected relationship for mapping...")
      self.topo_desc.duplicate_static_links()
    # Need to clean after shutdown
    self._need_clean = None
    # There is no such flag in the Mininet class so using this
    self.started = False
    self.xterms = []
Example #2
0
  def __init_from_file (self, path, 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 path: file path
    :type path: str
    :param format: NF-FG storing format (default: internal NFFG representation)
    :type format: str
    :return: None
    """
    if path is None:
      log.error("Missing file path of Topology description")
      return
    try:
      with open(path, 'r') as f:
        log.info("Load topology from file: %s" % path)
        if format == self.DEFAULT_NFFG_FORMAT:
          log.info("Using file format: %s" % format)
          self.__init_from_NFFG(nffg=NFFG.parse(f.read()))
        else:
          raise TopologyBuilderException("Unsupported file format: %s!" %
                                         format)
    except IOError:
      log.warning("Additional topology file not found: %s" % path)
      raise TopologyBuilderException("Missing topology file!")
    except ValueError as e:
      log.error("An error occurred when load topology from file: %s" %
                e.message)
      raise TopologyBuilderException("File parsing error!")
Example #3
0
  def cleanup (self):
    """
    Clean up junk which might be left over from old runs.

    ..seealso::
      :func:`mininet.clean.cleanup() <mininet.clean.cleanup>`
    """
    if self.started:
      log.warning(
        "Mininet network is not stopped yet! Skipping cleanup task...")
    else:
      log.info("Schedule cleanup task after Mininet emulation...")
      # Kill remained xterms
      log.debug("Close SAP xterms...")
      import os
      import signal
      for term in self.xterms:
        os.killpg(term.pid, signal.SIGTERM)
      # Schedule a cleanup as a coop task to avoid threading issues
      from escape.util.misc import remove_junks
      # call_as_coop_task(remove_junks, log=log)
      # threading.Thread(target=remove_junks, name="cleanup", args=(log,
      # )).start()
      # multiprocessing.Process(target=remove_junks, name="cleanup",
      #                         args=(log,)).start()
      remove_junks(log=log)
Example #4
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)
Example #5
0
    def start_network(self):
        """
    Start network.

    :return: None
    """
        log.debug("Starting Mininet network...")
        if self.__mininet is not None:
            if not self.started:
                try:
                    self.__mininet.start()
                except SystemExit:
                    quit_with_error(
                        msg="Mininet emulation requires root privileges!",
                        logger=LAYER_NAME)
                except KeyboardInterrupt:
                    quit_with_error(
                        msg=
                        "Initiation of Mininet network was interrupted by user!",
                        logger=log)
                self.started = True
                log.debug("Mininet network has been started!")
                self.runXTerms()
            else:
                log.warning(
                    "Mininet network has already started! Skipping start task..."
                )
        else:
            log.error("Missing topology! Skipping emulation...")
Example #6
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")
Example #7
0
    def shutdown(self, event):
        """
    .. seealso::
      :func:`AbstractAPI.shutdown() <escape.util.api.AbstractAPI.shutdown>`

    :param event: event object
    """
        log.info("Infrastructure Layer is going down...")
        if self.topology:
            try:
                self.topology.stop_network()
            except KeyboardInterrupt:
                log.warning(
                    "Shutdown of Mininet network was interrupted by user!")
Example #8
0
 def stop_network (self):
   """
   Stop network.
   """
   log.debug("Shutting down Mininet network...")
   if self.__mininet is not None:
     if self.started:
       self.__mininet.stop()
       self.started = False
       log.debug("Mininet network has been stopped!")
     else:
       log.warning("Mininet network is not started yet! Skipping stop task...")
   if self._need_clean:
     self.cleanup()
Example #9
0
    def bind_inter_domain_SAPs(self, nffg):
        """
    Search for inter-domain SAPs in given :class:`NFFG`, create them as a
    switch port and bind them to a physical interface given in sap.domain
    attribute.

    :param nffg: topology description
    :type nffg: :class:`NFFG`
    :return: None
    """
        log.debug("Search for inter-domain SAPs...")
        # Create the inter-domain SAP ports
        for sap in {s for s in nffg.saps if s.binding is not None}:
            # NFFG is the raw NFFG without link duplication --> iterate over every
            # edges in or out there should be only one link in this case
            # e = (u, v, data)
            sap_switch_links = [
                e for e in nffg.network.edges_iter(data=True) if sap.id in e
            ]
            try:
                if sap_switch_links[0][0] == sap.id:
                    border_node = sap_switch_links[0][1]
                else:
                    border_node = sap_switch_links[0][0]
            except IndexError:
                log.error("Link for inter-domain SAP: %s is not found. "
                          "Skip SAP creation..." % sap)
                continue
            log.debug(
                "Detected inter-domain SAP: %s connected to border Node: %s" %
                (sap, border_node))
            # if sap.delay or sap.bandwidth:
            #   log.debug("Detected resource values for inter-domain connection: "
            #             "delay: %s, bandwidth: %s" % (sap.delay, sap.bandwidth))
            sw_name = nffg.network.node[border_node].id
            for sw in self.mn.switches:
                # print sw.name
                if sw.name == sw_name:
                    if sap.binding not in get_ifaces():
                        log.warning(
                            "Physical interface: %s is not found! Skip binding..."
                            % sap.binding)
                        continue
                    log.debug(
                        "Add physical port as inter-domain SAP: %s -> %s" %
                        (sap.binding, sap.id))
                    # Add interface to border switch in Mininet
                    # os.system('ovs-vsctl add-port %s %s' % (sw_name, sap.domain))
                    sw.addIntf(intf=Intf(name=sap.binding, node=sw))
Example #10
0
  def __init_from_NFFG (self, nffg):
    """
    Initialize topology from an :any:`NFFG` representation.

    :param nffg: topology object structure
    :type nffg: :any:`NFFG`
    :return: None
    """
    # pprint(nffg.network.__dict__)
    log.info("Start topology creation from NFFG(name: %s)..." % nffg.name)
    created_mn_nodes = {}  # created nodes as 'NFFG-id': <node>
    created_mn_links = {}  # created links as 'NFFG-id': <link>
    # If not set then cache the given NFFG as the topology description
    self.topo_desc = nffg
    # Create a Controller which will be the default internal POX controller
    try:
      self.create_Controller("ESCAPE")
    except SystemExit:
      raise TopologyBuilderException("Controller creations was unsuccessful!")
    # Convert INFRAs
    for infra in nffg.infras:
      # Create EE
      if infra.infra_type == NodeInfra.TYPE_EE:
        if infra.domain == "INTERNAL":
          ee_type = self.TYPE_EE_LOCAL
        else:
          log.warning(
            "Detected domain of infra: %s is not INTERNAL! Remote EE creation "
            "for domains other than INTERNAL is not supported yet!" % infra)
          # ee_type = self.TYPE_EE_REMOTE
          ee_type = self.TYPE_EE_LOCAL
          # FIXME - set resource info in MN EE if can - cpu,mem,delay,bandwidth?
        agt, sw = self.create_NETCONF_EE(name=infra.id, type=ee_type)
        created_mn_nodes[infra.id] = sw
      # Create Switch
      elif infra.infra_type == NodeInfra.TYPE_SDN_SWITCH:
        switch = self.create_Switch(name=infra.id)
        created_mn_nodes[infra.id] = switch
      elif infra.infra_type == NodeInfra.TYPE_STATIC_EE:
        static_ee = self.create_static_EE(name=infra.id)
        created_mn_nodes[infra.id] = static_ee
      else:
        quit_with_error(
          msg="Type: %s in %s is not supported by the topology creation "
              "process in %s!" % (
                infra.infra_type, infra, self.__class__.__name__), logger=log)
    # Create SAPs - skip the temporary, inter-domain SAPs
    for sap in {s for s in nffg.saps if not s.binding}:
      # Create SAP
      sap_host = self.create_SAP(name=sap.id)
      created_mn_nodes[sap.id] = sap_host
    # Convert VNFs
    # TODO - implement --> currently the default Mininet topology does not
    # TODO contain NFs but it could be possible
    # Convert connections - copy link ref in a list and iter over it
    for edge in [l for l in nffg.links]:
      # Skip initiation of links which connected to an inter-domain SAP
      if (edge.src.node.type == NFFG.TYPE_SAP and
              edge.src.node.binding is not None) or (
             edge.dst.node.type == NFFG.TYPE_SAP and
             edge.dst.node.binding is not None):
        continue
      # Create Links
      mn_src_node = created_mn_nodes.get(edge.src.node.id)
      mn_dst_node = created_mn_nodes.get(edge.dst.node.id)
      if mn_src_node is None or mn_dst_node is None:
        raise TopologyBuilderException(
          "Created topology node is missing! Something really went wrong!")
      src_port = int(edge.src.id) if int(edge.src.id) < 65535 else None
      if src_port is None:
        log.warning(
          "Source port id of Link: %s is generated dynamically! Using "
          "automatic port assignment based on internal Mininet "
          "implementation!" % edge)
      dst_port = int(edge.dst.id) if int(edge.dst.id) < 65535 else None
      if dst_port is None:
        log.warning(
          "Destination port id of Link: %s is generated dynamically! Using "
          "automatic port assignment based on internal Mininet "
          "implementation!" % edge)
      link = self.create_Link(src=mn_src_node, src_port=src_port,
                              dst=mn_dst_node, dst_port=dst_port,
                              bw=edge.bandwidth, delay=str(edge.delay) + 'ms')
      created_mn_links[edge.id] = link

    # Set port properties of SAP nodes.
    #  A possible excerpt from a escape-mn-topo.nffg file:
    #  "ports": [{ "id": 1,
    #              "property": ["ip:10.0.10.1/24"] }]
    #
    for n in {s for s in nffg.saps if not s.binding}:
      mn_node = self.mn.getNodeByName(n.id)
      for port in n.ports:
        # ip should be something like '10.0.123.1/24'.
        if len(port.l3):
          if len(port.l3) == 1:
            ip = port.l3.container[0].provided
          else:
            log.warning(
              "Multiple L3 address is detected! Skip explicit IP address "
              "definition...")
            ip = None
        else:
          # or None
          ip = port.get_property('ip')
        if port.l2:
          mac = port.l2
        else:
          mac = port.get_property('mac')
        intf = mn_node.intfs.get(port.id)
        if intf is None:
          log.warn(("Port %s of node %s is not connected,"
                    "it will remain unconfigured!") % (port.id, n.name))
          continue
        if intf == mn_node.defaultIntf():
          # Workaround a bug in Mininet
          mn_node.params.update({'ip': ip})
          mn_node.params.update({'mac': mac})
        if ip is not None:
          mn_node.setIP(ip, intf=intf)
          log.debug("Use explicit IP: %s for node: %s" % (ip, n))
        if mac is not None:
          mn_node.setMAC(mac, intf=intf)
          log.debug("Use explicit MAC: %s for node: %s" % (mac, n))

    # For inter-domain SAPs no need to create host/xterm just add the SAP as
    # a port to the border Node
    # Iterate inter-domain SAPs
    self.bind_inter_domain_SAPs(nffg=nffg)
    log.info("Topology creation from NFFG has been finished!")