Example #1
0
    def checkReservation(self, resource, start_time, end_time):
        self._checkArgs(resource, start_time, end_time)

        # check start time is before end time
        if start_time is not None and end_time is not None and start_time > end_time:
            raise error.PayloadError(
                'Invalid request: Reverse duration (end time before start time)'
            )

        if start_time is not None:
            # check that start time is not in the past
            now = datetime.datetime.utcnow()
            if start_time < now:
                delta = now - start_time
                stamp = str(start_time).rsplit('.')[0]
                variables = [('startTime', start_time.isoformat())]
                raise error.PayloadError(
                    'Invalid request: Start time in the past (Startime: %s, Delta: %s)'
                    % (stamp, str(delta)),
                    variables=variables)

            # check the start time makes sense
            if start_time > datetime.datetime(2025, 1, 1):
                raise error.PayloadError(
                    'Invalid request: Start time after year 2025')

        for (c_resource, c_start_time, c_end_time) in self.reservations:
            if resource == c_resource:
                if self._resourceOverlap(c_start_time, c_end_time, start_time,
                                         end_time):
                    raise error.STPUnavailableError(
                        'Resource %s not available in specified time span' %
                        resource)
Example #2
0
 def getPort(self, port_id):
     for port in itertools.chain(self.inbound_ports, self.outbound_ports, self.bidirectional_ports):
         if port.id_ == port_id:
             return port
     # better error message
     ports = [ p.id_ for p in list(itertools.chain(self.inbound_ports, self.outbound_ports, self.bidirectional_ports)) ]
     raise error.STPUnavailableError('No port named %s for network %s (ports: %s)' %(port_id, self.id_, str(ports)))
Example #3
0
    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 the network this NSA is managing ({})'
                .format(source_stp.network, self.network))
        if dest_stp.network != self.network:
            raise error.ConnectionCreateError(
                'Destination network {} does not match network this NSA is managing ({})'
                .format(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)
Example #4
0
    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)