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());
}
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());
}
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<>();
}
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;
}
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;
}
Aggregations