Beispiel #1
0
    def __connect_interface(self, *, interface: Interface):
        """
        Connect a (compute or switch) node interface to network service by transparently
        creating a peer service interface and a link between them
        :param interface
        :return:
        """
        assert interface is not None
        assert isinstance(interface, Interface)

        # we can only connect interfaces connected to (compute or switch) nodes,
        parent = self.topo.get_owner_node(interface)
        if parent is None:
            raise TopologyException(f'Interface {interface} is not owned by a node, as expected.')
        # we can only connect interfaces that aren't already connected
        peer_ids = self.topo.graph_model.find_peer_connection_points(node_id=interface.node_id)
        if peer_ids is not None:
            raise TopologyException(f'Interface {interface} is already connected to another service.')
        # create a peer interface, create a link between them
        peer_if = Interface(name='-'.join([parent.name, interface.name]),
                            parent_node_id=self.node_id,
                            etype=ElementType.NEW, topo=self.topo, itype=InterfaceType.ServicePort)
        # link type is determined by the type of interface = L2Path for shared, Patch for Dedicated
        if interface.type == InterfaceType.SharedPort:
            ltype = LinkType.L2Path
        else:
            ltype = LinkType.Patch

        peer_link = Link(name=peer_if.name + '-link', topo=self.topo, etype=ElementType.NEW,
                         interfaces=[interface, peer_if], ltype=ltype)
        self._interfaces.append(peer_if)
Beispiel #2
0
 def __get_interface_by_name(self, name: str) -> Interface:
     """
     Get an interface of network service by its name
     :param name:
     :return:
     """
     assert name is not None
     node_id = self.topo.graph_model.find_connection_point_by_name(parent_node_id=self.node_id,
                                                                   iname=name)
     return Interface(name=name, node_id=node_id, topo=self.topo)
Beispiel #3
0
 def __get_interface_by_id(self, node_id: str) -> Interface:
     """
     Get an interface of network service by its node_id, return Interface object
     :param node_id:
     :return:
     """
     assert node_id is not None
     _, node_props = self.topo.graph_model.get_node_properties(node_id=node_id)
     assert node_props.get(ABCPropertyGraph.PROP_NAME, None) is not None
     return Interface(name=node_props[ABCPropertyGraph.PROP_NAME], node_id=node_id,
                      topo=self.topo)
Beispiel #4
0
    def add_interface(self, *, name: str, node_id: str = None, itype: InterfaceType = InterfaceType.TrunkPort,
                      **kwargs):
        """
        Add an interface to network service
        :param name:
        :param node_id:
        :param itype: interface type e.g. TrunkPort, AccessPort or VINT
        :param kwargs: additional parameters
        :return:
        """
        assert name is not None

        # check uniqueness
        if name in self.__list_interfaces().keys():
            raise TopologyException('Interface names must be unique within a switch fabric')
        iff = Interface(name=name, node_id=node_id, parent_node_id=self.node_id,
                        etype=ElementType.NEW, topo=self.topo, itype=itype,
                        **kwargs)
        return iff
Beispiel #5
0
    def disconnect_interface(self, *, interface: Interface) -> None:
        """
        Disconnect a node interface from the network service.
        Transparently remove peer service interface and link between them.
        :param interface:
        :return:
        """
        assert interface is not None

        peers = interface.get_peers()
        if peers is None or len(peers) == 0:
            return

        if len(peers) > 1:
            raise TopologyException(f'List of ServicePort peers for interface {interface} is more than one')

        self.topo.graph_model.remove_cp_and_links(node_id=peers[0].node_id)
        # remove from interface list as well
        self._interfaces = list(filter((lambda x: x.node_id != peers[0].node_id), self._interfaces))
Beispiel #6
0
    def __init__(self, *, name: str, node_id: str = None, topo: Any,
                 etype: ElementType = ElementType.EXISTING,
                 parent_node_id: str = None, direction: MirrorDirection = MirrorDirection.Both,
                 from_interface_name: str = None, to_interface: Interface = None,
                 **kwargs):
        if etype == ElementType.NEW:
            assert to_interface
            assert from_interface_name

            # only the 'to_interface' is actually connected to the service
            # the 'from_interface' is connected to something else
            # to_interface has to be a full-rate interface

            # make sure that to_interface is a DedicatedPort
            if to_interface.type != InterfaceType.DedicatedPort:
                raise TopologyException(f'Adding PortMirrorService {name} failed - only dedicated '
                                        f'ports belonging to SmartNICs can be attached.')
            super().__init__(name=name, node_id=node_id, topo=topo, etype=etype,
                             parent_node_id=parent_node_id, interfaces=[to_interface],
                             nstype=ServiceType.PortMirror, technology=None,
                             mirror_port=from_interface_name, mirror_direction=direction,
                             **kwargs)
        else:
            assert node_id is not None
            super().__init__(name=name, node_id=node_id, topo=topo)
            # check that this node exists
            existing_node_id = self.topo.\
                graph_model.find_node_by_name(node_name=name,
                                              label=ABCPropertyGraph.CLASS_NetworkService)
            if existing_node_id != node_id:
                raise TopologyException(f'Service name {name} node id does not match the expected node id.')
            # collect a list of interface nodes it attaches to
            interface_list = self.topo.graph_model.get_all_ns_or_link_connection_points(link_id=self.node_id)
            name_id_tuples = list()
            # need to look up their names - a bit inefficient, need to think about this /ib
            for iff in interface_list:
                _, props = self.topo.graph_model.get_node_properties(node_id=iff)
                name_id_tuples.append((props[ABCPropertyGraph.PROP_NAME], iff))
            self._interfaces = [Interface(node_id=tup[1], topo=topo, name=tup[0]) for tup in name_id_tuples]
Beispiel #7
0
    def __init__(self, *, name: str, node_id: str = None, topo: Any,
                 etype: ElementType = ElementType.EXISTING,
                 parent_node_id: str = None,
                 interfaces: List[Interface] = None,
                 nstype: ServiceType = None, technology: str = None,
                 **kwargs):
        """
        Don't call this method yourself, call topology.add_network_service()
        node_id will be generated if not provided for experiment topologies

        :param name:
        :param node_id:
        :param topo:
        :param etype: is this supposed to exist or new should be created
        :param parent_node_id: node_id of the parent Node if any (for new components)
        :param interfaces: list of interface objects to connect
        :param nstype: service type if new
        :param technology: service technology
        :param kwargs: any additional properties
        """
        assert name is not None
        assert topo is not None

        site = None
        if etype == ElementType.NEW:
            # node id myst be specified for new nodes in substrate topologies
            if node_id is None:
                node_id = str(uuid.uuid4())
            super().__init__(name=name, node_id=node_id, topo=topo)
            if nstype is None:
                raise TopologyException("When creating new services you must specify ServiceType")
            # cant use isinstance as it would create circular import dependencies
            # We do more careful checks for ExperimentTopologies, but for substrate we let things loose
            if str(self.topo.__class__) == "<class 'fim.user.topology.ExperimentTopology'>" and interfaces:
                sites = self.__validate_nstype_constraints(nstype, interfaces)

                # if a single-site service
                if len(sites) == 1:
                    site = sites.pop()

            sliver = NetworkServiceSliver()
            sliver.node_id = self.node_id
            sliver.set_name(self.name)
            sliver.set_type(nstype)
            sliver.set_site(site)
            # set based on service type
            sliver.set_layer(NetworkServiceSliver.ServiceConstraints[nstype].layer)
            sliver.set_technology(technology)
            sliver.set_properties(**kwargs)
            self.topo.graph_model.add_network_service_sliver(parent_node_id=parent_node_id, network_service=sliver)
            self._interfaces = list()
            if interfaces is not None and len(interfaces) > 0:
                for i in interfaces:
                    # run through guardrails, then connect
                    self.__service_guardrails(sliver, i)
                    self.__connect_interface(interface=i)
        else:
            assert node_id is not None
            super().__init__(name=name, node_id=node_id, topo=topo)
            # check that this node exists
            existing_node_id = self.topo.\
                graph_model.find_node_by_name(node_name=name,
                                              label=ABCPropertyGraph.CLASS_NetworkService)
            if existing_node_id != node_id:
                raise TopologyException(f'Service name {name} node id does not match the expected node id.')
            # collect a list of interface nodes it attaches to
            interface_list = self.topo.graph_model.get_all_ns_or_link_connection_points(link_id=self.node_id)
            name_id_tuples = list()
            # need to look up their names - a bit inefficient, need to think about this /ib
            for iff in interface_list:
                _, props = self.topo.graph_model.get_node_properties(node_id=iff)
                name_id_tuples.append((props[ABCPropertyGraph.PROP_NAME], iff))
            self._interfaces = [Interface(node_id=tup[1], topo=topo, name=tup[0]) for tup in name_id_tuples]
Beispiel #8
0
    def __init__(self,
                 *,
                 name: str,
                 node_id: str = None,
                 topo: Any,
                 etype: ElementType = ElementType.EXISTING,
                 interfaces: List[Interface] = None,
                 ltype: LinkType = None,
                 technology: str = None,
                 **kwargs):
        """
        Don't call this method yourself, call topology.add_link()
        node_id will be generated if not provided for experiment topologies

        :param name:
        :param node_id:
        :param topo:
        :param etype: is this supposed to exist or new should be created
        :param interfaces: list of interface objects to connect
        :param ltype: link type if new
        :param technology: link technology
        :param kwargs: any additional properties
        """
        assert name is not None
        assert topo is not None

        if etype == ElementType.NEW:
            # cant use isinstance as it would create circular import dependencies
            # node id myst be specified for new nodes in substrate topologies
            if str(topo.__class__) == "<class 'fim.user.topology.SubstrateTopology'>" and \
                    node_id is None:
                raise TopologyException(
                    "When adding new links to substrate topology nodes you must specify static Node ID"
                )
            if node_id is None:
                node_id = str(uuid.uuid4())
            super().__init__(name=name, node_id=node_id, topo=topo)
            if ltype is None:
                raise TopologyException(
                    "When creating new links you must specify LinkType")
            # FIXME isinstance
            if interfaces is None or len(interfaces) == 0 or (not isinstance(
                    interfaces, tuple) and not isinstance(interfaces, list)):
                raise TopologyException(
                    "When creating new links you must specify the list of interfaces to connect."
                )
            self._interfaces = interfaces
            sliver = NetworkLinkSliver()
            sliver.node_id = self.node_id
            sliver.set_name(self.name)
            sliver.set_type(ltype)
            # set layer based on type
            sliver.set_layer(NetworkLinkSliver.LinkConstraints[ltype].layer)
            sliver.set_technology(technology)
            sliver.set_properties(**kwargs)

            # get a list of node_ids for interfaces
            interface_ids = (iff.node_id for iff in interfaces)
            self.topo.graph_model.add_network_link_sliver(
                interfaces=interface_ids, lsliver=sliver)
        else:
            assert node_id is not None
            super().__init__(name=name, node_id=node_id, topo=topo)
            # check that this node exists
            existing_node_id = self.topo.\
                graph_model.find_node_by_name(node_name=name,
                                              label=ABCPropertyGraph.CLASS_Link)
            if existing_node_id != node_id:
                raise TopologyException(
                    f'Link name {name} is not unique within the topology.')
            # collect a list of interfaces it attaches to
            interface_list = self.topo.graph_model.get_all_ns_or_link_connection_points(
                link_id=self.node_id)
            name_id_tuples = list()
            # need to look up their names - a bit inefficient, need to think about this /ib
            for iff in interface_list:
                _, props = self.topo.graph_model.get_node_properties(
                    node_id=iff)
                name_id_tuples.append((props[ABCPropertyGraph.PROP_NAME], iff))
            self._interfaces = [
                Interface(node_id=tup[1], topo=topo, name=tup[0])
                for tup in name_id_tuples
            ]