Search in sources :

Example 1 with Node

use of org.openkilda.pce.model.Node in project open-kilda by telstra.

the class AvailableNetworkFactoryTest method assertAvailableNetworkIsCorrect.

private static void assertAvailableNetworkIsCorrect(IslImmutableView isl, AvailableNetwork availableNetwork) {
    Node src = availableNetwork.getSwitch(isl.getSrcSwitchId());
    assertNotNull(src);
    assertEquals(1, src.getOutgoingLinks().size());
    Edge edge = src.getOutgoingLinks().iterator().next();
    assertEquals(isl.getSrcSwitchId(), edge.getSrcSwitch().getSwitchId());
    assertEquals(isl.getSrcPort(), edge.getSrcPort());
    assertEquals(isl.getDestSwitchId(), edge.getDestSwitch().getSwitchId());
    assertEquals(isl.getDestPort(), edge.getDestPort());
    assertEquals(isl.getCost(), edge.getCost());
    assertEquals(isl.getLatency(), edge.getLatency());
    assertEquals(isl.getAvailableBandwidth(), edge.getAvailableBandwidth());
    Node dst = availableNetwork.getSwitch(isl.getDestSwitchId());
    assertNotNull(dst);
    assertEquals(1, dst.getIncomingLinks().size());
}
Also used : Node(org.openkilda.pce.model.Node) Edge(org.openkilda.pce.model.Edge)

Example 2 with Node

use of org.openkilda.pce.model.Node in project open-kilda by telstra.

the class AvailableNetworkTest method shouldCreateSymmetricOutgoingAndIncomming.

@Test
public void shouldCreateSymmetricOutgoingAndIncomming() {
    AvailableNetwork network = new AvailableNetwork();
    addLink(network, SRC_SWITCH, DST_SWITCH, 7, 60, 10, 3);
    Node srcSwitch = network.getSwitch(SRC_SWITCH);
    Node dstSwitch = network.getSwitch(DST_SWITCH);
    Set<Edge> outgoingLinks = srcSwitch.getOutgoingLinks();
    assertThat(outgoingLinks, Matchers.hasSize(1));
    Edge outgoingIsl = outgoingLinks.iterator().next();
    assertEquals(dstSwitch, outgoingIsl.getDestSwitch());
    Set<Edge> incomingLinks = dstSwitch.getIncomingLinks();
    assertThat(incomingLinks, Matchers.hasSize(1));
    Edge incomingIsl = incomingLinks.iterator().next();
    assertEquals(srcSwitch, incomingIsl.getSrcSwitch());
}
Also used : Node(org.openkilda.pce.model.Node) Edge(org.openkilda.pce.model.Edge) Test(org.junit.Test)

Example 3 with Node

use of org.openkilda.pce.model.Node in project open-kilda by telstra.

the class BestWeightAndShortestPathFinder method getPath.

/**
 * Call this method to find a path from start to end (srcDpid to dstDpid), particularly if you have no idea if the
 * path exists or what the best path is.
 *
 * @return A pair of ordered lists that represents the path from start to end, or an empty list
 */
private List<Edge> getPath(Node start, Node end, WeightFunction weightFunction) {
    PathWeight bestWeight = new PathWeight(Long.MAX_VALUE);
    SearchNode bestPath = null;
    // working list
    Deque<SearchNode> toVisit = new LinkedList<>();
    Map<Node, SearchNode> visited = new HashMap<>();
    toVisit.add(new SearchNode(weightFunction, start, allowedDepth, new PathWeight(), emptyList()));
    while (!toVisit.isEmpty()) {
        SearchNode current = toVisit.pop();
        log.trace("Going to visit node {} with weight {}.", current.dstSw, current.getParentWeight().toLong());
        // Determine if this node is the destination node.
        if (current.dstSw.equals(end)) {
            // We found the destination
            if (current.parentWeight.compareTo(bestWeight) < 0) {
                // We found a best path. If we don't get here, then the entire graph will be
                // searched until we run out of nodes or the depth is reached.
                bestWeight = current.parentWeight;
                bestPath = current;
            }
            // We found dest, no need to keep processing
            log.trace("Found destination using {} with path {}", current.dstSw, current.parentPath);
            continue;
        }
        // Otherwise, if we've been here before, see if this path is better
        SearchNode prior = visited.get(current.dstSw);
        if (prior != null && current.parentWeight.compareTo(prior.parentWeight) >= 0) {
            continue;
        }
        // Stop processing entirely if we've gone too far, or over bestWeight
        if (current.allowedDepth <= 0 || current.parentWeight.compareTo(bestWeight) > 0) {
            log.trace("Skip node {} processing", current.dstSw);
            continue;
        }
        // Either this is the first time, or this one has less weight .. either way, this node should
        // be the one in the visited list
        visited.put(current.dstSw, current);
        log.trace("Save new path to node {} and process it's outgoing links", current.dstSw);
        // At this stage .. haven't found END, haven't gone too deep, and we are not over weight.
        // So, add the outbound isls.
        current.dstSw.getOutgoingLinks().stream().sorted(Comparator.comparing(edge -> edge.getDestSwitch().getSwitchId())).forEach(edge -> toVisit.add(current.addNode(edge)));
    }
    return (bestPath != null) ? bestPath.parentPath : new LinkedList<>();
}
Also used : HashMap(java.util.HashMap) Node(org.openkilda.pce.model.Node) PathWeight(org.openkilda.pce.model.PathWeight) LinkedList(java.util.LinkedList)

Example 4 with Node

use of org.openkilda.pce.model.Node in project open-kilda by telstra.

the class BestWeightAndShortestPathFinder method isPathValid.

/**
 * This helper function is used with getReversePath(hint) to confirm the hint path exists.
 */
private boolean isPathValid(List<Edge> path) {
    boolean validPath = true;
    for (Edge i : path) {
        Node srcSwitch = i.getSrcSwitch();
        Set<Edge> pathsToDst = srcSwitch.getOutgoingLinks().stream().filter(link -> link.getDestSwitch().equals(i.getDestSwitch())).collect(toSet());
        if (pathsToDst.isEmpty()) {
            log.debug("No ISLS from {} to {}", i.getSrcSwitch(), i.getDestSwitch());
        }
        boolean foundThisOne = false;
        for (Edge orig : pathsToDst) {
            if (i.getSrcSwitch().getSwitchId().equals(orig.getSrcSwitch().getSwitchId()) && i.getSrcPort() == orig.getSrcPort() && i.getDestSwitch().getSwitchId().equals(orig.getDestSwitch().getSwitchId()) && i.getDestPort() == orig.getDestPort()) {
                foundThisOne = true;
                // stop looking, we found the Edge
                break;
            }
        }
        if (!foundThisOne) {
            validPath = false;
            // found an Edge that doesn't exist, stop looking for others
            break;
        }
    }
    return validPath;
}
Also used : HashMap(java.util.HashMap) Deque(java.util.Deque) StringUtils(org.apache.commons.lang3.StringUtils) Function(java.util.function.Function) Supplier(java.util.function.Supplier) Value(lombok.Value) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) UnroutableFlowException(org.openkilda.pce.exception.UnroutableFlowException) Edge(org.openkilda.pce.model.Edge) Lists(com.google.common.collect.Lists) Pair(org.apache.commons.lang3.tuple.Pair) Node(org.openkilda.pce.model.Node) Map(java.util.Map) LinkedList(java.util.LinkedList) Collectors.toSet(java.util.stream.Collectors.toSet) AvailableNetwork(org.openkilda.pce.impl.AvailableNetwork) LinkedHashSet(java.util.LinkedHashSet) PathWeight(org.openkilda.pce.model.PathWeight) Collections.emptyList(java.util.Collections.emptyList) Set(java.util.Set) Collectors(java.util.stream.Collectors) String.format(java.lang.String.format) WeightFunction(org.openkilda.pce.model.WeightFunction) Objects(java.util.Objects) FindOneDirectionPathResult(org.openkilda.pce.model.FindOneDirectionPathResult) Slf4j(lombok.extern.slf4j.Slf4j) List(java.util.List) SwitchId(org.openkilda.model.SwitchId) FindPathResult(org.openkilda.pce.model.FindPathResult) Comparator(java.util.Comparator) Node(org.openkilda.pce.model.Node) Edge(org.openkilda.pce.model.Edge)

Example 5 with Node

use of org.openkilda.pce.model.Node 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)

Aggregations

Node (org.openkilda.pce.model.Node)20 Edge (org.openkilda.pce.model.Edge)15 Test (org.junit.Test)8 SwitchId (org.openkilda.model.SwitchId)4 HashMap (java.util.HashMap)3 HashSet (java.util.HashSet)3 LinkedList (java.util.LinkedList)3 List (java.util.List)3 UnroutableFlowException (org.openkilda.pce.exception.UnroutableFlowException)3 ArrayList (java.util.ArrayList)2 Collections.emptyList (java.util.Collections.emptyList)2 LinkedHashSet (java.util.LinkedHashSet)2 Map (java.util.Map)2 Set (java.util.Set)2 Slf4j (lombok.extern.slf4j.Slf4j)2 Flow (org.openkilda.model.Flow)2 PathSegment (org.openkilda.model.PathSegment)2 FindOneDirectionPathResult (org.openkilda.pce.model.FindOneDirectionPathResult)2 PathWeight (org.openkilda.pce.model.PathWeight)2 VisibleForTesting (com.google.common.annotations.VisibleForTesting)1