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)
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)
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)
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
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))
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]
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]
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 ]