org.opendaylight.sfc.provider.topology.SfcProviderGraph Maven / Gradle / Ivy
/*
* Copyright (c) 2014, 2017 Intel Corporation. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.sfc.provider.topology;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.TreeSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class represents a topology graph, node/vertex is a SF (Service
* Function) or SFF (Service Function Forwarder), edge is a unidirect and direct
* connection between two nodes/vertexes, it is mainly used to implement
* Dijkstra shortest path algorithm, method getShortestPath can find the
* shortest path between 'from' node and 'to' node in a graph.
*
*
*
* @author Shuqiang Zhao ([email protected])
* @author Yi Yang ([email protected])
*
* @since 2015-03-13
*/
public class SfcProviderGraph {
private static final Logger LOG = LoggerFactory.getLogger(SfcProviderGraph.class);
private static final TreeSet EMPTY_SET = new TreeSet<>();
private static final int WHITE = 2;
private static final int GRAY = 1;
private static final int BLACK = 0;
private final HashMap> sfcProviderTopoEdges;
private final HashMap sfcProviderTopoNodes;
public SfcProviderGraph() {
sfcProviderTopoEdges = new HashMap<>();
sfcProviderTopoNodes = new HashMap<>();
}
public SfcProviderTopologyNode addNode(String nodeName) {
SfcProviderTopologyNode node;
node = sfcProviderTopoNodes.get(nodeName);
if (node == null) {
node = new SfcProviderTopologyNode(nodeName);
sfcProviderTopoNodes.put(nodeName, node);
sfcProviderTopoEdges.put(node, new TreeSet<>());
}
return node;
}
public SfcProviderTopologyNode getNode(String nodeName) {
return sfcProviderTopoNodes.get(nodeName);
}
public boolean hasNode(String nodeName) {
return sfcProviderTopoNodes.containsKey(nodeName);
}
public boolean hasEdge(String fromNodeName, String toNodeName) {
SfcProviderTopologyNode fromNode;
SfcProviderTopologyNode toNode;
if (!hasNode(fromNodeName) || !hasNode(toNodeName)) {
return false;
}
fromNode = sfcProviderTopoNodes.get(fromNodeName);
toNode = sfcProviderTopoNodes.get(toNodeName);
return sfcProviderTopoEdges.get(fromNode).contains(toNode);
}
public boolean addEdge(String fromNodeName, String toNodeName) {
SfcProviderTopologyNode fromNode;
SfcProviderTopologyNode toNode;
if (!hasEdge(fromNodeName, toNodeName)) {
fromNode = getNode(fromNodeName);
if (fromNode == null) {
fromNode = addNode(fromNodeName);
}
toNode = getNode(toNodeName);
if (toNode == null) {
toNode = addNode(toNodeName);
}
sfcProviderTopoEdges.get(fromNode).add(toNode);
sfcProviderTopoEdges.get(toNode).add(fromNode);
}
return true;
}
public Iterable getNeighborNodes(String nodeName) {
if (!hasNode(nodeName)) {
return EMPTY_SET;
}
return sfcProviderTopoEdges.get(getNode(nodeName));
}
public Iterable getAllNodes() {
return sfcProviderTopoNodes.values();
}
private void breadthFirstSearch(String fromNodeName) {
/* Reset all nodes' color, dist, parent */
for (SfcProviderTopologyNode sfcNode : getAllNodes()) {
sfcNode.setColor(WHITE);
sfcNode.setDist(0);
sfcNode.setParent(null);
}
/* Mark fromNode as GRAY */
SfcProviderTopologyNode sfcProviderTopologyNode = getNode(fromNodeName);
sfcProviderTopologyNode.setColor(GRAY);
sfcProviderTopologyNode.setDist(0);
sfcProviderTopologyNode.setParent(null);
Queue queue = new LinkedList<>();
offer(queue, sfcProviderTopologyNode);
while (!queue.isEmpty()) {
SfcProviderTopologyNode sfcProviderNode = queue.poll();
for (SfcProviderTopologyNode sfcNode : getNeighborNodes(sfcProviderNode.getName())) {
if (sfcNode.getColor() == WHITE) {
sfcNode.setColor(GRAY);
sfcNode.setDist(sfcProviderNode.getDist() + 1);
offer(queue, sfcNode);
sfcNode.setParent(sfcProviderNode);
}
}
sfcProviderNode.setColor(BLACK);
}
}
private void offer(Queue queue, SfcProviderTopologyNode node) {
if (!queue.offer(node)) {
// Shouldn't happen since the queue is (currently) unbounded but checking avoids findbugs violation.
LOG.warn("Could not offer to queue");
}
}
public List getShortestPath(String fromNodeName, String toNodeName) {
SfcProviderTopologyNode fromNode = getNode(fromNodeName);
SfcProviderTopologyNode toNode = getNode(toNodeName);
if (fromNode == null || toNode == null) {
LOG.error(" Node {} or {} doesn't exist in topology graph!", fromNodeName, toNodeName);
return Collections.emptyList();
}
List sfcProviderTopologyNodePath = new ArrayList<>();
if (fromNodeName.equals(toNodeName)) {
sfcProviderTopologyNodePath.add(0, fromNode);
return sfcProviderTopologyNodePath;
}
breadthFirstSearch(fromNodeName);
SfcProviderTopologyNode sfcProviderTopologyNode = getNode(toNodeName);
while (sfcProviderTopologyNode != null) {
sfcProviderTopologyNodePath.add(0, sfcProviderTopologyNode);
sfcProviderTopologyNode = sfcProviderTopologyNode.getParent();
}
/* No path if the first node isn't fromNode, so clear it. */
if (!sfcProviderTopologyNodePath.isEmpty() && !sfcProviderTopologyNodePath.get(0).equals(fromNode)) {
sfcProviderTopologyNodePath.clear();
}
return sfcProviderTopologyNodePath;
}
}