Search in sources :

Example 1 with UnroutableFlowException

use of org.openkilda.pce.exception.UnroutableFlowException in project open-kilda by telstra.

the class BestWeightAndShortestPathFinder method findNPathsBetweenSwitches.

/**
 * Find N (or less) best paths. To find N paths Yen's algorithm is used.
 *
 * @return an list of N (or less) best paths.
 */
private List<List<Edge>> findNPathsBetweenSwitches(AvailableNetwork network, SwitchId startSwitchId, SwitchId endSwitchId, int count, WeightFunction weightFunction, Function<Node, FindOneDirectionPathResult> getPath) throws UnroutableFlowException {
    Node start = network.getSwitch(startSwitchId);
    Node end = network.getSwitch(endSwitchId);
    if (start == null || end == null) {
        throw new UnroutableFlowException(format("Switch %s doesn't have links with enough bandwidth", start == null ? startSwitchId : endSwitchId));
    }
    // Determine the shortest path from the start to the end.
    List<List<Edge>> bestPaths = new ArrayList<>();
    List<Edge> firstPath = getPath.apply(start).getFoundPath();
    if (firstPath.isEmpty()) {
        return new ArrayList<>();
    }
    bestPaths.add(getPath.apply(start).getFoundPath());
    // Initialize the set to store the potential kth shortest path.
    // Use LinkedHashSet to have deterministic results.
    Set<List<Edge>> potentialKthShortestPaths = new LinkedHashSet<>();
    for (int k = 1; k < count; k++) {
        List<Edge> bestPath = bestPaths.get(k - 1);
        for (int i = 0; i < bestPath.size(); i++) {
            // Spur node is retrieved from the previous k-shortest path.
            Node spurNode = bestPath.get(i).getSrcSwitch();
            // The sequence of edges from the start to the spur node (without spur node).
            List<Edge> rootPath = new ArrayList<>(bestPath.subList(0, i));
            Set<Edge> removedEdges = new HashSet<>();
            // Remove the links that are part of the previous shortest paths which share the same root path.
            for (List<Edge> path : bestPaths) {
                if (path.size() > i && rootPath.equals(path.subList(0, i)) && spurNode.equals(path.get(i).getSrcSwitch())) {
                    removedEdges.add(path.get(i));
                    removeEdge(path.get(i));
                }
            }
            for (Edge edge : rootPath) {
                edge.getSrcSwitch().remove();
            }
            // Calculate the spur path from the spur node to the end.
            List<Edge> pathFromSpurNode = getPath.apply(spurNode).getFoundPath();
            if (!pathFromSpurNode.isEmpty()) {
                List<Edge> totalPath = new ArrayList<>(rootPath);
                // Entire path is made up of the root path and spur path.
                totalPath.addAll(pathFromSpurNode);
                // Add the potential k-shortest path to the heap.
                potentialKthShortestPaths.add(totalPath);
            }
            // Add back the edges and nodes that were removed from the graph.
            for (Edge edge : removedEdges) {
                restoreEdge(edge);
            }
            for (Edge edge : rootPath) {
                edge.getSrcSwitch().restore();
            }
        }
        if (potentialKthShortestPaths.isEmpty()) {
            break;
        }
        // Add the lowest weight path becomes the k-shortest path.
        List<Edge> newBestPath = getBestPotentialKthShortestPath(potentialKthShortestPaths, bestPaths, weightFunction);
        bestPaths.add(newBestPath);
    }
    return bestPaths;
}
Also used : LinkedHashSet(java.util.LinkedHashSet) Node(org.openkilda.pce.model.Node) UnroutableFlowException(org.openkilda.pce.exception.UnroutableFlowException) ArrayList(java.util.ArrayList) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) Collections.emptyList(java.util.Collections.emptyList) List(java.util.List) Edge(org.openkilda.pce.model.Edge) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet)

Example 2 with UnroutableFlowException

use of org.openkilda.pce.exception.UnroutableFlowException in project open-kilda by telstra.

the class AllocateProtectedResourcesAction method allocate.

@Override
protected void allocate(FlowUpdateFsm stateMachine) throws RecoverableException, UnroutableFlowException, ResourceAllocationException {
    String flowId = stateMachine.getFlowId();
    Set<String> flowIds = Sets.newHashSet(flowId);
    if (stateMachine.getBulkUpdateFlowIds() != null) {
        flowIds.addAll(stateMachine.getBulkUpdateFlowIds());
    }
    log.debug("Finding protected path ids for flows {}", flowIds);
    List<PathId> pathIdsToReuse = new ArrayList<>(flowPathRepository.findActualPathIdsByFlowIds(flowIds));
    pathIdsToReuse.addAll(stateMachine.getRejectedPaths());
    Flow tmpFlow = getFlow(flowId);
    FlowPathPair oldPaths = new FlowPathPair(tmpFlow.getProtectedForwardPath(), tmpFlow.getProtectedReversePath());
    FlowPath primaryForward = getFlowPath(tmpFlow, stateMachine.getNewPrimaryForwardPath());
    FlowPath primaryReverse = getFlowPath(tmpFlow, stateMachine.getNewPrimaryReversePath());
    Predicate<GetPathsResult> testNonOverlappingPath = path -> (primaryForward == null || !flowPathBuilder.arePathsOverlapped(path.getForward(), primaryForward)) && (primaryReverse == null || !flowPathBuilder.arePathsOverlapped(path.getReverse(), primaryReverse));
    PathId newForwardPathId = resourcesManager.generatePathId(flowId);
    PathId newReversePathId = resourcesManager.generatePathId(flowId);
    log.debug("Finding a new protected path for flow {}", flowId);
    GetPathsResult allocatedPaths = allocatePathPair(tmpFlow, newForwardPathId, newReversePathId, false, pathIdsToReuse, oldPaths, true, stateMachine.getSharedBandwidthGroupId(), testNonOverlappingPath);
    if (allocatedPaths == null) {
        throw new ResourceAllocationException("Unable to allocate a path");
    }
    if (!testNonOverlappingPath.test(allocatedPaths)) {
        stateMachine.saveActionToHistory("Couldn't find non overlapping protected path");
    } else {
        log.debug("New protected paths have been allocated: {}", allocatedPaths);
        stateMachine.setNewProtectedForwardPath(newForwardPathId);
        stateMachine.setNewProtectedReversePath(newReversePathId);
        stateMachine.setBackUpProtectedPathComputationWayUsed(allocatedPaths.isBackUpPathComputationWayUsed());
        log.debug("Allocating resources for a new protected path of flow {}", flowId);
        FlowResources flowResources = allocateFlowResources(tmpFlow, newForwardPathId, newReversePathId);
        stateMachine.setNewProtectedResources(flowResources);
        FlowPathPair createdPaths = createFlowPathPair(flowId, flowResources, allocatedPaths, false, stateMachine.getSharedBandwidthGroupId());
        log.debug("New protected path has been created: {}", createdPaths);
        saveAllocationActionWithDumpsToHistory(stateMachine, tmpFlow, "protected", createdPaths);
    }
}
Also used : BaseResourceAllocationAction(org.openkilda.wfm.topology.flowhs.fsm.common.actions.BaseResourceAllocationAction) FlowPath(org.openkilda.model.FlowPath) ResourceAllocationException(org.openkilda.wfm.share.flow.resources.ResourceAllocationException) RecoverableException(org.openkilda.pce.exception.RecoverableException) ArrayList(java.util.ArrayList) UnroutableFlowException(org.openkilda.pce.exception.UnroutableFlowException) Flow(org.openkilda.model.Flow) FlowPathPair(org.openkilda.wfm.topology.flow.model.FlowPathPair) PersistenceManager(org.openkilda.persistence.PersistenceManager) PathId(org.openkilda.model.PathId) FlowOperationsDashboardLogger(org.openkilda.wfm.share.logger.FlowOperationsDashboardLogger) ErrorType(org.openkilda.messaging.error.ErrorType) Predicate(java.util.function.Predicate) FlowUpdateFsm(org.openkilda.wfm.topology.flowhs.fsm.update.FlowUpdateFsm) Set(java.util.Set) State(org.openkilda.wfm.topology.flowhs.fsm.update.FlowUpdateFsm.State) FlowResources(org.openkilda.wfm.share.flow.resources.FlowResources) Sets(com.google.common.collect.Sets) Event(org.openkilda.wfm.topology.flowhs.fsm.update.FlowUpdateFsm.Event) Slf4j(lombok.extern.slf4j.Slf4j) List(java.util.List) FlowUpdateContext(org.openkilda.wfm.topology.flowhs.fsm.update.FlowUpdateContext) PathComputer(org.openkilda.pce.PathComputer) FlowResourcesManager(org.openkilda.wfm.share.flow.resources.FlowResourcesManager) GetPathsResult(org.openkilda.pce.GetPathsResult) FlowResources(org.openkilda.wfm.share.flow.resources.FlowResources) ArrayList(java.util.ArrayList) Flow(org.openkilda.model.Flow) FlowPathPair(org.openkilda.wfm.topology.flow.model.FlowPathPair) GetPathsResult(org.openkilda.pce.GetPathsResult) PathId(org.openkilda.model.PathId) FlowPath(org.openkilda.model.FlowPath) ResourceAllocationException(org.openkilda.wfm.share.flow.resources.ResourceAllocationException)

Example 3 with UnroutableFlowException

use of org.openkilda.pce.exception.UnroutableFlowException in project open-kilda by telstra.

the class InMemoryPathComputer method getNPaths.

@Override
public List<Path> getNPaths(SwitchId srcSwitchId, SwitchId dstSwitchId, int count, FlowEncapsulationType flowEncapsulationType, PathComputationStrategy pathComputationStrategy, Duration maxLatency, Duration maxLatencyTier2) throws RecoverableException, UnroutableFlowException {
    final long maxLatencyNs = maxLatency != null ? maxLatency.toNanos() : 0;
    final long maxLatencyTier2Ns = maxLatencyTier2 != null ? maxLatencyTier2.toNanos() : 0;
    Flow flow = Flow.builder().flowId(// just any id, as not used.
    "").srcSwitch(Switch.builder().switchId(srcSwitchId).build()).destSwitch(Switch.builder().switchId(dstSwitchId).build()).ignoreBandwidth(false).encapsulationType(flowEncapsulationType).bandwidth(// to get ISLs with non zero available bandwidth
    1).maxLatency(maxLatencyNs).maxLatencyTier2(maxLatencyTier2Ns).build();
    AvailableNetwork availableNetwork = availableNetworkFactory.getAvailableNetwork(flow, Collections.emptyList());
    if (MAX_LATENCY.equals(pathComputationStrategy) && (flow.getMaxLatency() == null || flow.getMaxLatency() == 0)) {
        pathComputationStrategy = LATENCY;
    }
    List<List<Edge>> paths;
    switch(pathComputationStrategy) {
        case COST:
        case LATENCY:
        case COST_AND_AVAILABLE_BANDWIDTH:
            paths = pathFinder.findNPathsBetweenSwitches(availableNetwork, srcSwitchId, dstSwitchId, count, getWeightFunctionByStrategy(pathComputationStrategy));
            break;
        case MAX_LATENCY:
            paths = pathFinder.findNPathsBetweenSwitches(availableNetwork, srcSwitchId, dstSwitchId, count, getWeightFunctionByStrategy(pathComputationStrategy), maxLatencyNs, maxLatencyTier2Ns);
            break;
        default:
            throw new UnsupportedOperationException(String.format("Unsupported strategy type %s", pathComputationStrategy));
    }
    Comparator<Path> comparator;
    if (pathComputationStrategy == LATENCY || pathComputationStrategy == MAX_LATENCY) {
        comparator = Comparator.comparing(Path::getLatency).thenComparing(Comparator.comparing(Path::getMinAvailableBandwidth).reversed());
    } else {
        comparator = Comparator.comparing(Path::getMinAvailableBandwidth).reversed().thenComparing(Path::getLatency);
    }
    return paths.stream().map(edges -> convertToPath(srcSwitchId, dstSwitchId, edges)).sorted(comparator).limit(count).collect(Collectors.toList());
}
Also used : FlowPath(org.openkilda.model.FlowPath) Path(org.openkilda.pce.Path) MAX_LATENCY(org.openkilda.model.PathComputationStrategy.MAX_LATENCY) PathSegment(org.openkilda.model.PathSegment) FlowPath(org.openkilda.model.FlowPath) RecoverableException(org.openkilda.pce.exception.RecoverableException) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) UnroutableFlowException(org.openkilda.pce.exception.UnroutableFlowException) Edge(org.openkilda.pce.model.Edge) Flow(org.openkilda.model.Flow) AvailableNetworkFactory(org.openkilda.pce.AvailableNetworkFactory) Duration(java.time.Duration) PathComputerConfig(org.openkilda.pce.PathComputerConfig) LinkedList(java.util.LinkedList) PathId(org.openkilda.model.PathId) Path(org.openkilda.pce.Path) PathFinder(org.openkilda.pce.finder.PathFinder) FlowEncapsulationType(org.openkilda.model.FlowEncapsulationType) PathWeight(org.openkilda.pce.model.PathWeight) Switch(org.openkilda.model.Switch) PathComputationStrategy(org.openkilda.model.PathComputationStrategy) Collections.emptyList(java.util.Collections.emptyList) Collection(java.util.Collection) Set(java.util.Set) LATENCY(org.openkilda.model.PathComputationStrategy.LATENCY) Collectors(java.util.stream.Collectors) String.format(java.lang.String.format) WeightFunction(org.openkilda.pce.model.WeightFunction) Objects(java.util.Objects) Slf4j(lombok.extern.slf4j.Slf4j) List(java.util.List) SwitchId(org.openkilda.model.SwitchId) FindPathResult(org.openkilda.pce.model.FindPathResult) PathComputer(org.openkilda.pce.PathComputer) Optional(java.util.Optional) GetPathsResult(org.openkilda.pce.GetPathsResult) VisibleForTesting(com.google.common.annotations.VisibleForTesting) Comparator(java.util.Comparator) Collections(java.util.Collections) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) Collections.emptyList(java.util.Collections.emptyList) List(java.util.List) Flow(org.openkilda.model.Flow)

Example 4 with UnroutableFlowException

use of org.openkilda.pce.exception.UnroutableFlowException in project open-kilda by telstra.

the class BestWeightAndShortestPathFinderTest method shouldFindSymmetricPath.

@Test
public void shouldFindSymmetricPath() throws UnroutableFlowException {
    AvailableNetwork network = buildLinearNetworkWithPairLinks();
    BestWeightAndShortestPathFinder pathFinder = new BestWeightAndShortestPathFinder(2);
    Pair<List<Edge>, List<Edge>> pathPair = pathFinder.findPathWithMinWeight(network, SWITCH_ID_1, SWITCH_ID_3, WEIGHT_FUNCTION).getFoundPath();
    List<Edge> forward = pathPair.getLeft();
    List<Edge> reverse = Lists.reverse(pathPair.getRight());
    List<Boolean> validation = IntStream.range(0, forward.size()).mapToObj(i -> Objects.equals(forward.get(i).getSrcPort(), reverse.get(i).getDestPort())).collect(Collectors.toList());
    assertFalse(validation.contains(false));
}
Also used : IntStream(java.util.stream.IntStream) PathWeight(org.openkilda.pce.model.PathWeight) Arrays(java.util.Arrays) CoreMatchers.equalTo(org.hamcrest.CoreMatchers.equalTo) Assert.assertTrue(org.junit.Assert.assertTrue) Matchers(org.hamcrest.Matchers) Test(org.junit.Test) Collectors(java.util.stream.Collectors) WeightFunction(org.openkilda.pce.model.WeightFunction) ArrayList(java.util.ArrayList) Assert.assertThat(org.junit.Assert.assertThat) Objects(java.util.Objects) UnroutableFlowException(org.openkilda.pce.exception.UnroutableFlowException) Edge(org.openkilda.pce.model.Edge) List(java.util.List) Lists(com.google.common.collect.Lists) SwitchId(org.openkilda.model.SwitchId) Pair(org.apache.commons.lang3.tuple.Pair) FindPathResult(org.openkilda.pce.model.FindPathResult) Assert.assertFalse(org.junit.Assert.assertFalse) Assert.assertEquals(org.junit.Assert.assertEquals) AvailableNetwork(org.openkilda.pce.impl.AvailableNetwork) ArrayList(java.util.ArrayList) List(java.util.List) AvailableNetwork(org.openkilda.pce.impl.AvailableNetwork) Edge(org.openkilda.pce.model.Edge) Test(org.junit.Test)

Example 5 with UnroutableFlowException

use of org.openkilda.pce.exception.UnroutableFlowException in project open-kilda by telstra.

the class ResourcesAllocationAction method allocateProtectedPath.

private void allocateProtectedPath(FlowCreateFsm stateMachine) throws UnroutableFlowException, RecoverableException, ResourceAllocationException, FlowNotFoundException {
    String flowId = stateMachine.getFlowId();
    Flow tmpFlow = getFlow(flowId);
    if (!tmpFlow.isAllocateProtectedPath()) {
        return;
    }
    tmpFlow.setDiverseGroupId(getFlowDiverseGroupFromContext(flowId).orElseThrow(() -> new FlowNotFoundException(flowId)));
    GetPathsResult protectedPath = pathComputer.getPath(tmpFlow);
    stateMachine.setBackUpProtectedPathComputationWayUsed(protectedPath.isBackUpPathComputationWayUsed());
    boolean overlappingProtectedPathFound = flowPathBuilder.arePathsOverlapped(protectedPath.getForward(), tmpFlow.getForwardPath()) || flowPathBuilder.arePathsOverlapped(protectedPath.getReverse(), tmpFlow.getReversePath());
    if (overlappingProtectedPathFound) {
        log.info("Couldn't find non overlapping protected path. Result flow state: {}", tmpFlow);
        throw new UnroutableFlowException("Couldn't find non overlapping protected path", tmpFlow.getFlowId());
    }
    log.debug("Creating the protected path {} for flow {}", protectedPath, tmpFlow);
    transactionManager.doInTransaction(() -> {
        Flow flow = getFlow(flowId);
        FlowResources flowResources = resourcesManager.allocateFlowResources(flow);
        final FlowSegmentCookieBuilder cookieBuilder = FlowSegmentCookie.builder().flowEffectiveId(flowResources.getUnmaskedCookie());
        FlowPath forward = flowPathBuilder.buildFlowPath(flow, flowResources.getForward(), protectedPath.getForward(), cookieBuilder.direction(FlowPathDirection.FORWARD).build(), false, stateMachine.getSharedBandwidthGroupId());
        forward.setStatus(FlowPathStatus.IN_PROGRESS);
        flowPathRepository.add(forward);
        flow.setProtectedForwardPath(forward);
        FlowPath reverse = flowPathBuilder.buildFlowPath(flow, flowResources.getReverse(), protectedPath.getReverse(), cookieBuilder.direction(FlowPathDirection.REVERSE).build(), false, stateMachine.getSharedBandwidthGroupId());
        reverse.setStatus(FlowPathStatus.IN_PROGRESS);
        flowPathRepository.add(reverse);
        flow.setProtectedReversePath(reverse);
        updateIslsForFlowPath(forward.getPathId());
        updateIslsForFlowPath(reverse.getPathId());
        stateMachine.setProtectedForwardPathId(forward.getPathId());
        stateMachine.setProtectedReversePathId(reverse.getPathId());
        log.debug("Allocated resources for the flow {}: {}", flow.getFlowId(), flowResources);
        stateMachine.getFlowResources().add(flowResources);
    });
}
Also used : FlowNotFoundException(org.openkilda.wfm.error.FlowNotFoundException) FlowResources(org.openkilda.wfm.share.flow.resources.FlowResources) UnroutableFlowException(org.openkilda.pce.exception.UnroutableFlowException) FlowSegmentCookieBuilder(org.openkilda.model.cookie.FlowSegmentCookie.FlowSegmentCookieBuilder) FlowPath(org.openkilda.model.FlowPath) Flow(org.openkilda.model.Flow) YSubFlow(org.openkilda.model.YSubFlow) RequestedFlow(org.openkilda.wfm.topology.flowhs.model.RequestedFlow) YFlow(org.openkilda.model.YFlow) GetPathsResult(org.openkilda.pce.GetPathsResult)

Aggregations

UnroutableFlowException (org.openkilda.pce.exception.UnroutableFlowException)22 Test (org.junit.Test)12 Flow (org.openkilda.model.Flow)10 RecoverableException (org.openkilda.pce.exception.RecoverableException)9 List (java.util.List)8 FlowPath (org.openkilda.model.FlowPath)8 GetPathsResult (org.openkilda.pce.GetPathsResult)8 YFlowRequest (org.openkilda.messaging.command.yflow.YFlowRequest)7 ResourceAllocationException (org.openkilda.wfm.share.flow.resources.ResourceAllocationException)7 AbstractYFlowTest (org.openkilda.wfm.topology.flowhs.service.AbstractYFlowTest)7 ErrorType (org.openkilda.messaging.error.ErrorType)6 PathId (org.openkilda.model.PathId)6 SwitchId (org.openkilda.model.SwitchId)6 ArrayList (java.util.ArrayList)5 Slf4j (lombok.extern.slf4j.Slf4j)5 Objects (java.util.Objects)4 Set (java.util.Set)4 Collection (java.util.Collection)3 Collectors (java.util.stream.Collectors)3 Assert.assertEquals (org.junit.Assert.assertEquals)3