def _parseNRMMapping(nrm_mapping_source): # regular expression for matching nrm mapping lines # basically we allow two type of lines (with and without backend identifier), i.e.: # stp:stp_name "nrm_port" # stp:stp_name backend "nrm_port" STP_MAP_RX = re.compile('''(.+?)\s+(\w+?)?\s*"(.+)"''') # link:link_name backend1 "nrm_port" - backend2 "nrm_port" LINK_RX = re.compile('''(.+?)\s+(\w+?)\s+"(.+)"\s+-\s+(\w+?)\s+"(.+)"''') def parseSTP(entry): m = STP_MAP_RX.match(line) if not m: log.msg('Error parsing stp map %s in NRM description.' % entry, system=LOG_SYSTEM) return stp, backend, local_port = m.groups() if stp.startswith(STP_PREFIX): stp = 'urn:ogf:network:' + stp nrm_port = _createNRMPort(backend, local_port) triples = [ (stp, GLIF_MAPS_TO, nrm_port ), (nrm_port, RDF_TYPE, NRM_PORT_TYPE) ] return triples def parseLink(entry): m = LINK_RX.match(entry) if not m: log.msg('Error parsing link entry %s in NRM description.' % entry, system=LOG_SYSTEM) return _, backend_1, nrm_port_1, backend_2, nrm_port_2 = m.groups() nrm_port_1 = _createNRMPort(backend_1, nrm_port_1) nrm_port_2 = _createNRMPort(backend_2, nrm_port_2) triples = [ (nrm_port_1, GLIF_CONNECTED_TO, nrm_port_2), (nrm_port_2, GLIF_CONNECTED_TO, nrm_port_1), (nrm_port_1, RDF_TYPE, NRM_PORT_TYPE), (nrm_port_2, RDF_TYPE, NRM_PORT_TYPE) ] return triples if isinstance(nrm_mapping_source, file) or isinstance(nrm_mapping_source, StringIO.StringIO): source = nrm_mapping_source elif isinstance(nrm_mapping_source, str): from StringIO import StringIO source = StringIO(nrm_mapping_source) else: raise error.TopologyError('Invalid NRM Mapping Source') triples = set() for line in source: line = line.strip() if not line or line.startswith('#'): continue if line.startswith(URN_STP_PREFIX) or line.startswith(STP_PREFIX): stp_triples = parseSTP(line) if stp_triples: triples.update(stp_triples) elif line.startswith(LINK_PREFIX): link_triples = parseLink(line) if link_triples: triples.update(link_triples) else: # we don't want to have invalid topology descriptions so just raise error raise error.TopologyError('Invalid entry in NRM file: %s' % line) return triples
def getNetwork(self, network_name): for network in self.networks: if network.name == network_name: return network raise error.TopologyError('No network named %s' % network_name)
def reserve(self, header, connection_id, global_reservation_id, description, criteria): # return defer.fail( error.InternalNRMError('test reservation failure') ) sd = criteria.service_def if type(sd) is not nsa.Point2PointService: raise ValueError( 'Cannot handle service of type %s, only Point2PointService is currently supported' % type(sd)) # should perhaps verify nsa, but not that important log.msg('Reserve request. Connection ID: %s' % connection_id, system=self.log_system) if connection_id: # if connection id is specified it is not allowed to be used a priori try: conn = yield self._getConnection(connection_id, header.requester_nsa) raise ValueError('GenericBackend cannot handle modify (yet)') except error.ConnectionNonExistentError: pass # expected source_stp = sd.source_stp dest_stp = sd.dest_stp # check network and ports exist if source_stp.network != self.network: raise error.ConnectionCreateError( 'Source network does not match network this NSA is managing (%s != %s)' % (source_stp.network, self.network)) if dest_stp.network != self.network: raise error.ConnectionCreateError( 'Destination network does not match network this NSA is managing (%s != %s)' % (dest_stp.network, self.network)) # ensure that ports actually exists if not source_stp.port in self.nrm_ports: raise error.STPUnavailableError( 'No STP named %s (ports: %s)' % (source_stp.baseURN(), str(self.nrm_ports.keys()))) if not dest_stp.port in self.nrm_ports: raise error.STPUnavailableError( 'No STP named %s (ports: %s)' % (dest_stp.baseURN(), str(self.nrm_ports.keys()))) start_time = criteria.schedule.start_time or datetime.datetime.utcnow( ).replace(microsecond=0) + datetime.timedelta( seconds=1) # no start time = now (well, in 1 second) end_time = criteria.schedule.end_time duration = (end_time - start_time).total_seconds() if duration < self.minimum_duration: raise error.ConnectionCreateError( 'Duration too short, minimum duration is %i seconds (%i specified)' % (self.minimum_duration, duration), self.network) nrm_source_port = self.nrm_ports[source_stp.port] nrm_dest_port = self.nrm_ports[dest_stp.port] # authz check if not nrm_source_port.isAuthorized(header.security_attributes): raise error.UnauthorizedError( 'Request does not have any valid credentials for port %s' % source_stp.baseURN()) if not nrm_dest_port.isAuthorized(header.security_attributes): raise error.UnauthorizedError( 'Request does not have any valid credentials for port %s' % dest_stp.baseURN()) # transit restriction if nrm_source_port.transit_restricted and nrm_dest_port.transit_restricted: raise error.ConnectionCreateError( 'Cannot connect two transit restricted STPs.') # basic label check if source_stp.label is None: raise error.TopologyError('Source STP must specify a label') if dest_stp.label is None: raise error.TopologyError('Destination STP must specify a label') src_label_candidate = source_stp.label dst_label_candidate = dest_stp.label assert src_label_candidate.type_ == dst_label_candidate.type_, 'Cannot connect ports with different label types' # check that we are connecting an stp to itself if source_stp == dest_stp and source_stp.label.singleValue(): raise error.TopologyError('Cannot connect STP %s to itself.' % source_stp) # now check that the ports have (some of) the specified label values if not nsa.Label.canMatch(nrm_source_port.label, src_label_candidate): raise error.TopologyError( 'Source port %s cannot match label set %s' % (nrm_source_port.name, src_label_candidate)) if not nsa.Label.canMatch(nrm_dest_port.label, dst_label_candidate): raise error.TopologyError( 'Destination port %s cannot match label set %s' % (nrm_dest_port.name, dst_label_candidate)) # do the find the label value dance if self.connection_manager.canSwapLabel(src_label_candidate.type_): for lv in src_label_candidate.enumerateValues(): src_resource = self.connection_manager.getResource( source_stp.port, src_label_candidate.type_, lv) try: self.calendar.checkReservation(src_resource, start_time, end_time) self.calendar.addReservation(src_resource, start_time, end_time) src_label = nsa.Label(src_label_candidate.type_, str(lv)) break except error.STPUnavailableError: pass else: raise error.STPUnavailableError( 'STP %s not available in specified time span' % source_stp) for lv in dst_label_candidate.enumerateValues(): dst_resource = self.connection_manager.getResource( dest_stp.port, dst_label_candidate.type_, lv) try: self.calendar.checkReservation(dst_resource, start_time, end_time) self.calendar.addReservation(dst_resource, start_time, end_time) dst_label = nsa.Label(dst_label_candidate.type_, str(lv)) break except error.STPUnavailableError: pass else: raise error.STPUnavailableError( 'STP %s not available in specified time span' % dest_stp) else: label_candidate = src_label_candidate.intersect( dst_label_candidate) for lv in label_candidate.enumerateValues(): src_resource = self.connection_manager.getResource( source_stp.port, label_candidate.type_, lv) dst_resource = self.connection_manager.getResource( dest_stp.port, label_candidate.type_, lv) try: self.calendar.checkReservation(src_resource, start_time, end_time) self.calendar.checkReservation(dst_resource, start_time, end_time) self.calendar.addReservation(src_resource, start_time, end_time) self.calendar.addReservation(dst_resource, start_time, end_time) src_label = nsa.Label(label_candidate.type_, str(lv)) dst_label = nsa.Label(label_candidate.type_, str(lv)) break except error.STPUnavailableError: continue else: raise error.STPUnavailableError( 'Link %s and %s not available in specified time span' % (source_stp, dest_stp)) now = datetime.datetime.utcnow() source_target = self.connection_manager.getTarget( source_stp.port, src_label.type_, src_label.labelValue()) dest_target = self.connection_manager.getTarget( dest_stp.port, dst_label.type_, dst_label.labelValue()) if connection_id is None: connection_id = self.connection_manager.createConnectionId( source_target, dest_target) # we should check the schedule here # should we save the requester or provider here? conn = GenericBackendConnections( connection_id=connection_id, revision=0, global_reservation_id=global_reservation_id, description=description, requester_nsa=header.requester_nsa, reserve_time=now, reservation_state=state.RESERVE_START, provision_state=state.RELEASED, lifecycle_state=state.CREATED, data_plane_active=False, source_network=source_stp.network, source_port=source_stp.port, source_label=src_label, dest_network=dest_stp.network, dest_port=dest_stp.port, dest_label=dst_label, start_time=start_time, end_time=end_time, symmetrical=sd.symmetric, directionality=sd.directionality, bandwidth=sd.capacity, allocated=False) yield conn.save() reactor.callWhenRunning(self._doReserve, conn, header.correlation_id) defer.returnValue(connection_id)
def parsePortSpec(source): # Parse the entries like the following: ## type name remote label bandwidth interface authz # #ethernet ps - vlan:1780-1783 1000 em0 [email protected] #ethernet netherlight netherlight#nordunet-(in|out) vlan:1780-1783 1000 em1 - #ethernet uvalight uvalight#nordunet-(in|out) vlan:1780-1783 1000 em2 nsa=aruba.net:nsa # Line starting with # and blank lines should be ignored assert isinstance(source, file) or isinstance( source, StringIO.StringIO), 'Topology source must be file or StringIO instance' nrm_ports = [] for line in source: line = line.strip() if not line or line.startswith('#'): continue tokens = [t for t in line.split(' ') if t != ''] if len(tokens) != 7: raise NRMSpecificationError( 'Invalid number of entries for entry: %s' % line) port_type, port_name, remote_spec, label_spec, bandwidth, interface, authz = tokens if not port_type in PORT_TYPES: raise error.TopologyError('Port type %s is not a valid port type' % port_type) remote_network, remote_port, in_suffix, out_suffix = _parseRemoteSpec( remote_spec) label = _parseLabelSpec(label_spec) try: bandwidth = int(bandwidth) except ValueError as e: raise NRMSpecificationError('Invalid bandwidth: %s' % str(e)) if port_type == cnt.NRM_ETHERNET: if remote_network is None: remote_port = None remote_in = None remote_out = None else: if not in_suffix or not out_suffix: raise NRMSpecificationError( 'Suffix not defined for bidirectional port %s' % port_name) remote_port = remote_network + ':' + remote_port remote_in = remote_port + in_suffix remote_out = remote_port + out_suffix else: raise AssertionError('do not know what to with port of type %s' % port_type) # these are more than auth attributes, but thats what they where for initially authz_attributes = [] link_vectors = {} transit_restricted = False if authz != '-': for aa in authz.split(','): if '=' in aa: #authz_attributes.append( nsa.SecurityAttribute(*aa.split('=',2)) ) ak, av = aa.split('=', 2) if ak in AUTH_ATTRIBUTES: authz_attributes.append(nsa.SecurityAttribute(ak, av)) elif ak in PATH_ATTRIBUTES: if not '@' in av: raise config.ConfigurationError( 'Invalid path value: %s' % av) network, weight = av.split('@', 1) link_vectors[network] = int(weight) else: raise config.ConfigurationError( 'Invalid attribute: %s' % aa) elif aa in ATTRIBUTES and aa == cnt.NRM_RESTRICTTRANSIT: transit_restricted = True else: raise config.ConfigurationError('Invalid attribute: %s' % aa) nrm_ports.append( NRMPort(port_type, port_name, remote_network, remote_port, remote_in, remote_out, label, bandwidth, interface, authz_attributes, link_vectors, transit_restricted)) return nrm_ports
def reserve(self, header, connection_id, global_reservation_id, description, criteria, request_info=None): # return defer.fail( error.InternalNRMError('test reservation failure') ) sd = criteria.service_def if type(sd) is not nsa.Point2PointService: raise ValueError( 'Cannot handle service of type %s, only Point2PointService is currently supported' % type(sd)) # should perhaps verify nsa, but not that important log.msg('Reserve request. Connection ID: %s' % connection_id, system=self.log_system) if connection_id: # if connection id is specified it is not allowed to be used a priori try: conn = yield self._getConnection(connection_id, header.requester_nsa) raise ValueError('GenericBackend cannot handle modify (yet)') except error.ConnectionNonExistentError: pass # expected source_stp = sd.source_stp dest_stp = sd.dest_stp # check network and ports exist if source_stp.network != self.network: raise error.ConnectionCreateError( 'Source network does not match network this NSA is managing (%s != %s)' % (source_stp.network, self.network)) if dest_stp.network != self.network: raise error.ConnectionCreateError( 'Destination network does not match network this NSA is managing (%s != %s)' % (dest_stp.network, self.network)) # ensure that ports actually exists if not source_stp.port in self.nrm_ports: raise error.STPUnavailableError( 'No STP named %s (ports: %s)' % (source_stp.baseURN(), str(self.nrm_ports.keys()))) if not dest_stp.port in self.nrm_ports: raise error.STPUnavailableError( 'No STP named %s (ports: %s)' % (dest_stp.baseURN(), str(self.nrm_ports.keys()))) start_time = criteria.schedule.start_time # or datetime.datetime.utcnow().replace(microsecond=0) + datetime.timedelta(seconds=1) # no start time = now (well, in 1 second) end_time = criteria.schedule.end_time if start_time is not None and end_time is not None: duration = (end_time - start_time).total_seconds() if duration < self.minimum_duration: raise error.ConnectionCreateError( 'Duration too short, minimum duration is %i seconds (%i specified)' % (self.minimum_duration, duration), self.network) nrm_source_port = self.nrm_ports[source_stp.port] nrm_dest_port = self.nrm_ports[dest_stp.port] self._authorize(source_stp.port, dest_stp.port, header, request_info, start_time, end_time) # transit restriction if nrm_source_port.transit_restricted and nrm_dest_port.transit_restricted: raise error.ConnectionCreateError( 'Cannot connect two transit restricted STPs.') # check that we are not connecting two identical stp (hairpin) if source_stp.port == dest_stp.port and source_stp.label == dest_stp.label: raise error.ServiceError('Cannot connect STP %s to itself.' % source_stp) labelType = lambda stp: None if stp.label is None else stp.label.type_ # have the backend check if the ports/labels can be connected # this is needed for cases of cross-label switching like ethernet-mpls encapsulation if hasattr(self.connection_manager, 'canConnect'): if not self.connection_manager.canConnect( source_stp.port, dest_stp.port, source_stp.label, dest_stp.label): raise error.TopologyError('Cannot connect STP %s to %s.' % (source_stp, dest_stp)) elif labelType(source_stp) != labelType(dest_stp): # if backend doesn't implement canConnect, we assume only the same label can be connected (old default) raise error.TopologyError( 'Cannot connect ports with different label types') # now check that the ports have (some of) the specified label values if not nsa.Label.canMatch(nrm_source_port.label, source_stp.label): raise error.TopologyError( 'Source port %s cannot match label set %s' % (nrm_source_port.name, source_stp.label)) if not nsa.Label.canMatch(nrm_dest_port.label, dest_stp.label): raise error.TopologyError( 'Destination port %s cannot match label set %s' % (nrm_dest_port.name, dest_stp.label)) labelEnum = lambda label: [None] if label is None else [ nsa.Label(label.type_, lv) for lv in label.enumerateValues() ] # do the find the label value dance if self.connection_manager.canSwapLabel(labelType( source_stp)) and self.connection_manager.canSwapLabel( labelType(dest_stp)): for lv in labelEnum(source_stp.label): src_resource = self.connection_manager.getResource( source_stp.port, lv) try: self.calendar.checkReservation(src_resource, start_time, end_time) src_label = lv break except error.STPUnavailableError: pass else: raise error.STPUnavailableError( 'STP %s not available in specified time span' % source_stp) for lv in labelEnum(dest_stp.label): dst_resource = self.connection_manager.getResource( dest_stp.port, lv) try: self.calendar.checkReservation(dst_resource, start_time, end_time) dst_label = lv break except error.STPUnavailableError: pass else: raise error.STPUnavailableError( 'STP %s not available in specified time span' % dest_stp) # Only add reservations, when src and dest stps are both available self.calendar.addReservation(src_resource, start_time, end_time) self.calendar.addReservation(dst_resource, start_time, end_time) else: if source_stp.label is None: label_candidate = dest_stp.label elif dest_stp.label is None: label_candidate = source_stp.label else: try: label_candidate = source_stp.label.intersect( dest_stp.label) except nsa.EmptyLabelSet: raise error.VLANInterchangeNotSupportedError( 'VLAN re-write not supported and no possible label intersection' ) for lv in labelEnum(label_candidate): src_resource = self.connection_manager.getResource( source_stp.port, lv) dst_resource = self.connection_manager.getResource( dest_stp.port, lv) try: self.calendar.checkReservation(src_resource, start_time, end_time) self.calendar.checkReservation(dst_resource, start_time, end_time) self.calendar.addReservation(src_resource, start_time, end_time) self.calendar.addReservation(dst_resource, start_time, end_time) src_label = lv dst_label = lv break except error.STPUnavailableError: continue else: raise error.STPUnavailableError( 'Link %s and %s not available in specified time span' % (source_stp, dest_stp)) now = datetime.datetime.utcnow() source_target = self.connection_manager.getTarget( source_stp.port, src_label) dest_target = self.connection_manager.getTarget( dest_stp.port, dst_label) if connection_id is None: connection_id = self.connection_manager.createConnectionId( source_target, dest_target) # we should check the schedule here # should we save the requester or provider here? conn = GenericBackendConnections( connection_id=connection_id, revision=0, global_reservation_id=global_reservation_id, description=description, requester_nsa=header.requester_nsa, reserve_time=now, reservation_state=state.RESERVE_START, provision_state=state.RELEASED, lifecycle_state=state.CREATED, data_plane_active=False, source_network=source_stp.network, source_port=source_stp.port, source_label=src_label, dest_network=dest_stp.network, dest_port=dest_stp.port, dest_label=dst_label, start_time=start_time, end_time=end_time, symmetrical=sd.symmetric, directionality=sd.directionality, bandwidth=sd.capacity, allocated=False) yield conn.save() reactor.callWhenRunning(self._doReserve, conn, header.correlation_id) defer.returnValue(connection_id)
def _findPathsRecurse(self, source_stp, dest_stp, bandwidth, exclude_networks=None): source_network = self.getNetwork(source_stp.network) dest_network = self.getNetwork(dest_stp.network) source_port = source_network.getPort(source_stp.port) dest_port = dest_network.getPort(dest_stp.port) if not (source_port.canMatchLabel(source_stp.label) or dest_port.canMatchLabel(dest_stp.label)): return [] # if not (source_port.canProvideBandwidth(bandwidth) and dest_port.canProvideBandwidth(bandwidth)): # return [] if source_port.isBidirectional() and dest_port.isBidirectional(): # bidirectional path finding, easy case first if source_stp.network == dest_stp.network: # while it is possible to cross other network in order to connect to intra-network STPs # it is not something we really want to do in the real world, so we don't try: if source_network.canSwapLabel(source_stp.label.type_): source_label = source_port.label().intersect(source_stp.label) dest_label = dest_port.label().intersect(dest_stp.label) else: source_label = source_port.label().intersect(dest_port.label()).intersect(source_stp.label).intersect(dest_stp.label) dest_label = source_label link = nsa.Link(source_stp.network, source_stp.port, dest_stp.port, source_label, dest_label) return [ [ link ] ] except nsa.EmptyLabelSet: return [] # no path else: # ok, time for real pathfinding link_ports = source_network.findPorts(True, source_stp.label, source_stp.port) link_ports = [ port for port in link_ports if port.hasRemote() ] # filter out termination ports links = [] for lp in link_ports: demarcation = self.findDemarcationPort(lp) if demarcation is None: continue d_network_id, d_port_id = demarcation if exclude_networks is not None and demarcation[0] in exclude_networks: continue # don't do loops in path finding demarcation_label = lp.label() if source_network.canSwapLabel(source_stp.label.type_) else source_stp.label.intersect(lp.label()) demarcation_stp = nsa.STP(demarcation[0], demarcation[1], demarcation_label) sub_exclude_networks = [ source_network.id_ ] + (exclude_networks or []) sub_links = self._findPathsRecurse(demarcation_stp, dest_stp, bandwidth, sub_exclude_networks) # if we didn't find any sub paths, just continue if not sub_links: continue for sl in sub_links: # -- if source_network.canSwapLabel(source_stp.label.type_): source_label = source_port.label().intersect(source_stp.label) dest_label = lp.label().intersect(sl[0].src_stp.label) else: source_label = source_port.label().intersect(source_stp.label).intersect(lp.label()).intersect(sl[0].src_stp.label) dest_label = source_label first_link = nsa.Link(source_stp.network, source_stp.port, lp.id_, source_label, dest_label) path = [ first_link ] + sl links.append(path) return sorted(links, key=len) # sort by length, shortest first else: raise error.TopologyError('Unidirectional path-finding not implemented yet')
def getNSA(self, network_id): try: return self.networks[network_id][1] except KeyError as e: raise error.TopologyError('No NSA for network with id %s (%s)' % (network_id, str(e)))
def getNetwork(self, network_id): try: return self.networks[network_id][0] except KeyError: raise error.TopologyError('No network with id %s' % (network_id))
def reserve(self, requester_nsa, provider_nsa, session_security_attr, global_reservation_id, description, connection_id, service_parameters, sub): # -- log.msg('', system='opennsa') log.msg('Connection %s. Reserve request from %s.' % (connection_id, requester_nsa), system=LOG_SYSTEM) if connection_id in self.connections.get(requester_nsa, {}): return defer.fail( error.ReserveError('Connection with id %s already exists' % connection_id)) source_stp = service_parameters.source_stp dest_stp = service_parameters.dest_stp if source_stp == dest_stp: return defer.fail( error.ReserveError('Cannot connect %s to itself.' % source_stp)) conn = connection.Connection(self.service_registry, requester_nsa, connection_id, source_stp, dest_stp, service_parameters, global_reservation_id, description) self.connections.setdefault(requester_nsa, {})[conn.connection_id] = conn # figure out nature of request path_info = (connection_id, source_stp.network, source_stp.endpoint, dest_stp.network, dest_stp.endpoint, self.network) if source_stp.network == self.network and dest_stp.network == self.network: log.msg( 'Connection %s: Simple path creation: %s:%s -> %s:%s (%s)' % path_info, system=LOG_SYSTEM) link = nsa.Link(source_stp.network, source_stp.endpoint, dest_stp.endpoint) self.setupSubConnection(link, conn, service_parameters) # This code is for chaining requests and is currently not used, but might be needed sometime in the future # Once we get proper a topology service, some chaining will be necessary. #elif source_stp.network == self.network: # # make path and chain on - common chaining # log.msg('Reserve %s: Common chain creation: %s:%s -> %s:%s (%s)' % path_info, system=LOG_SYSTEM) # paths = self.topology.findPaths(source_stp, dest_stp) # # check for no paths # paths.sort(key=lambda e : len(e.endpoint_pairs)) # selected_path = paths[0] # shortest path # log.msg('Attempting to create path %s' % selected_path, system=LOG_SYSTEM) # assert selected_path.source_stp.network == self.network # # setup connection data - does this work with more than one hop? # setupSubConnection(selected_path.source_stp, selected_path.endpoint_pairs[0].sourceSTP(), conn) # setupSubConnection(selected_path.endpoint_pairs[0].destSTP(), dest_stp, conn) #elif dest_stp.network == self.network: # # make path and chain on - backwards chaining # log.msg('Backwards chain creation %s: %s:%s -> %s:%s (%s)' % path_info, system=LOG_SYSTEM) # paths = self.topology.findPaths(source_stp, dest_stp) # # check for no paths # paths.sort(key=lambda e : len(e.endpoint_pairs)) # selected_path = paths[0] # shortest path # log.msg('Attempting to create path %s' % selected_path, system=LOG_SYSTEM) # assert selected_path.dest_stp.network == self.network # # setup connection data # setupSubConnection(selected_path.source_stp, selected_path.endpoint_pairs[0].sourceSTP(), conn) # setupSubConnection(selected_path.endpoint_pairs[0].destSTP(), dest_stp, conn) #else: # log.msg('Tree creation %s: %s:%s -> %s:%s (%s)' % path_info, system=LOG_SYSTEM) # create the connection in tree/fanout style else: # log about creation and the connection type log.msg( 'Connection %s: Aggregate path creation: %s:%s -> %s:%s (%s)' % path_info, system=LOG_SYSTEM) # making the connection is the same for all though :-) paths = self.topology.findPaths(source_stp, dest_stp) # error out if we could not find a path if not paths: error_msg = 'Could not find a path for route %s:%s -> %s:%s' % ( source_stp.network, source_stp.endpoint, dest_stp.network, dest_stp.endpoint) log.msg(error_msg, system=LOG_SYSTEM) raise error.TopologyError(error_msg) # check for no paths paths.sort(key=lambda e: len(e.links())) selected_path = paths[0] # shortest path log.msg('Attempting to create path %s' % selected_path, system=LOG_SYSTEM) for link in selected_path.links(): self.setupSubConnection(link, conn, service_parameters) # now reserve connections needed to create path conn.addSubscription(sub) d = task.deferLater(reactor, 0, conn.reserve) d.addErrback(log.err) return defer.succeed(None)
def addNetwork(self, network): if network.name in [ n.name for n in self.networks ]: raise error.TopologyError('Network name must be unique (name: %s)' % network.name) self.networks.append(network)