-
/*
* Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
*
*/
package org.opendaylight.controller.routing.dijkstra_implementation.internal;
+import org.opendaylight.controller.clustering.services.IClusterContainerServices;
import org.opendaylight.controller.sal.core.Bandwidth;
import org.opendaylight.controller.sal.core.ConstructionException;
import org.opendaylight.controller.sal.core.Edge;
import org.opendaylight.controller.sal.core.Path;
import org.opendaylight.controller.sal.core.Property;
import org.opendaylight.controller.sal.core.UpdateType;
-import org.opendaylight.controller.sal.reader.IReadService;
import org.opendaylight.controller.sal.routing.IListenRoutingUpdates;
import org.opendaylight.controller.sal.routing.IRouting;
+import org.opendaylight.controller.sal.topology.TopoEdgeUpdate;
import org.opendaylight.controller.switchmanager.ISwitchManager;
import org.opendaylight.controller.topologymanager.ITopologyManager;
-import org.opendaylight.controller.topologymanager.ITopologyManagerAware;
+import org.opendaylight.controller.topologymanager.ITopologyManagerClusterWideAware;
import edu.uci.ics.jung.algorithms.shortestpath.DijkstraShortestPath;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.SparseMultigraph;
import edu.uci.ics.jung.graph.util.EdgeType;
-import java.lang.Exception;
-import java.lang.IllegalArgumentException;
+
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.ArrayList;
import java.util.Set;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.commons.collections15.Transformer;
-public class DijkstraImplementation implements IRouting, ITopologyManagerAware {
- private static Logger log = LoggerFactory
- .getLogger(DijkstraImplementation.class);
+@SuppressWarnings("rawtypes")
+public class DijkstraImplementation implements IRouting, ITopologyManagerClusterWideAware {
+ private static Logger log = LoggerFactory.getLogger(DijkstraImplementation.class);
private ConcurrentMap<Short, Graph<Node, Edge>> topologyBWAware;
private ConcurrentMap<Short, DijkstraShortestPath<Node, Edge>> sptBWAware;
- DijkstraShortestPath<Node, Edge> mtp; //Max Throughput Path
+ DijkstraShortestPath<Node, Edge> mtp; // Max Throughput Path
private Set<IListenRoutingUpdates> routingAware;
private ISwitchManager switchManager;
private ITopologyManager topologyManager;
- private IReadService readService;
private static final long DEFAULT_LINK_SPEED = Bandwidth.BW1Gbps;
+ private IClusterContainerServices clusterContainerService;
- public void setLIstenRoutingUpdates(IListenRoutingUpdates i) {
+ public void setListenRoutingUpdates(final IListenRoutingUpdates i) {
if (this.routingAware == null) {
this.routingAware = new HashSet<IListenRoutingUpdates>();
}
}
}
- public void unsetRoutingUpdates(IListenRoutingUpdates i) {
+ public void unsetListenRoutingUpdates(final IListenRoutingUpdates i) {
if (this.routingAware == null) {
return;
}
Transformer<Edge, ? extends Number> mtTransformer = null;
if (EdgeWeightMap == null) {
mtTransformer = new Transformer<Edge, Double>() {
+ @Override
public Double transform(Edge e) {
if (switchManager == null) {
log.error("switchManager is null");
log.error("srcNC:{} or dstNC:{} is null", srcNC, dstNC);
return (double) -1;
}
- Bandwidth bwSrc = (Bandwidth) switchManager
- .getNodeConnectorProp(srcNC,
- Bandwidth.BandwidthPropName);
- Bandwidth bwDst = (Bandwidth) switchManager
- .getNodeConnectorProp(dstNC,
- Bandwidth.BandwidthPropName);
-
- if ((bwSrc == null) || (bwDst == null)) {
- log.error("bwSrc:{} or bwDst:{} is null", bwSrc, bwDst);
- return (double) -1;
- }
-
- long srcLinkSpeed = bwSrc.getValue();
- if (srcLinkSpeed == 0) {
- log.trace("Edge {}: srcLinkSpeed is 0. Setting to {}!",
- e, DEFAULT_LINK_SPEED);
+ Bandwidth bwSrc = (Bandwidth) switchManager.getNodeConnectorProp(srcNC,
+ Bandwidth.BandwidthPropName);
+ Bandwidth bwDst = (Bandwidth) switchManager.getNodeConnectorProp(dstNC,
+ Bandwidth.BandwidthPropName);
+
+ long srcLinkSpeed = 0, dstLinkSpeed = 0;
+ if ((bwSrc == null) || ((srcLinkSpeed = bwSrc.getValue()) == 0)) {
+ log.debug("srcNC: {} - Setting srcLinkSpeed to Default!", srcNC);
srcLinkSpeed = DEFAULT_LINK_SPEED;
}
- long dstLinkSpeed = bwDst.getValue();
- if (dstLinkSpeed == 0) {
- log.trace("Edge {}: dstLinkSpeed is 0. Setting to {}!",
- e, DEFAULT_LINK_SPEED);
+ if ((bwDst == null) || ((dstLinkSpeed = bwDst.getValue()) == 0)) {
+ log.debug("dstNC: {} - Setting dstLinkSpeed to Default!", dstNC);
dstLinkSpeed = DEFAULT_LINK_SPEED;
}
- long avlSrcThruPut = srcLinkSpeed
- - readService.getTransmitRate(srcNC);
- long avlDstThruPut = dstLinkSpeed
- - readService.getTransmitRate(dstNC);
-
- //Use lower of the 2 available thruput as the available thruput
- long avlThruPut = avlSrcThruPut < avlDstThruPut ? avlSrcThruPut
- : avlDstThruPut;
+ // TODO: revisit the logic below with the real use case in
+ // mind
+ // For now we assume the throughput to be the speed of the
+ // link itself
+ // this kind of logic require information that should be
+ // polled by statistic manager and are not yet available,
+ // also this service at the moment is not used, so to be
+ // revisited later on
+ long avlSrcThruPut = srcLinkSpeed;
+ long avlDstThruPut = dstLinkSpeed;
+
+ // Use lower of the 2 available throughput as the available
+ // throughput
+ long avlThruPut = avlSrcThruPut < avlDstThruPut ? avlSrcThruPut : avlDstThruPut;
if (avlThruPut <= 0) {
- log.debug("Edge {}: Available Throughput {} <= 0!",
- e, avlThruPut);
+ log.debug("Edge {}: Available Throughput {} <= 0!", e, avlThruPut);
return (double) -1;
}
return (double) (Bandwidth.BW1Pbps / avlThruPut);
};
} else {
mtTransformer = new Transformer<Edge, Number>() {
+ @Override
public Number transform(Edge e) {
return EdgeWeightMap.get(e);
}
};
}
Short baseBW = Short.valueOf((short) 0);
- //Initialize mtp also using the default topo
+ // Initialize mtp also using the default topo
Graph<Node, Edge> g = this.topologyBWAware.get(baseBW);
if (g == null) {
log.error("Default Topology Graph is null");
}
@Override
- public Path getRoute(Node src, Node dst) {
- if (src == null || dst == null) {
+ public Path getRoute(final Node src, final Node dst) {
+ if ((src == null) || (dst == null)) {
return null;
}
return getRoute(src, dst, (short) 0);
try {
path = mtp.getMaxThroughputPath(src, dst);
} catch (IllegalArgumentException ie) {
- log.debug("A vertex is yet not known between {} {}", src.toString(),
- dst.toString());
+ log.debug("A vertex is yet not known between {} {}", src, dst);
return null;
}
Path res;
try {
res = new Path(path);
} catch (ConstructionException e) {
- log.debug("A vertex is yet not known between {} {}", src.toString(),
- dst.toString());
+ log.debug("A vertex is yet not known between {} {}", src, dst);
return null;
}
return res;
}
@Override
- public synchronized Path getRoute(Node src, Node dst, Short Bw) {
+ public synchronized Path getRoute(final Node src, final Node dst, final Short Bw) {
DijkstraShortestPath<Node, Edge> spt = this.sptBWAware.get(Bw);
- if (spt == null)
+ if (spt == null) {
return null;
+ }
List<Edge> path;
try {
path = spt.getPath(src, dst);
} catch (IllegalArgumentException ie) {
- log.debug("A vertex is yet not known between {} {}", src.toString(),
- dst.toString());
+ log.debug("A vertex is yet not known between {} {}", src, dst);
return null;
}
Path res;
try {
res = new Path(path);
} catch (ConstructionException e) {
- log.debug("A vertex is yet not known between {} {}", src.toString(),
- dst.toString());
+ log.debug("A vertex is yet not known between {} {}", src, dst);
return null;
}
return res;
@Override
public synchronized void clearMaxThroughput() {
if (mtp != null) {
- mtp.reset(); //reset maxthruput path
+ mtp.reset(); // reset max throughput path
}
}
- @SuppressWarnings( { "rawtypes", "unchecked" })
- private synchronized boolean updateTopo(Edge edge, Short bw, boolean added) {
+ @SuppressWarnings({ "unchecked" })
+ private synchronized boolean updateTopo(Edge edge, Short bw, UpdateType type) {
Graph<Node, Edge> topo = this.topologyBWAware.get(bw);
DijkstraShortestPath<Node, Edge> spt = this.sptBWAware.get(bw);
boolean edgePresentInGraph = false;
this.sptBWAware.put(bw, spt);
}
- if (added) {
+ switch (type) {
+ case ADDED:
// Make sure the vertex are there before adding the edge
topo.addVertex(src.getNode());
topo.addVertex(dst.getNode());
edgePresentInGraph = topo.containsEdge(edge);
if (edgePresentInGraph == false) {
try {
- topo.addEdge(new Edge(src, dst), src
- .getNode(), dst
- .getNode(), EdgeType.DIRECTED);
- } catch (ConstructionException e) {
- e.printStackTrace();
+ topo.addEdge(new Edge(src, dst), src.getNode(), dst.getNode(), EdgeType.DIRECTED);
+ } catch (final ConstructionException e) {
+ log.error("", e);
return edgePresentInGraph;
}
}
- } else {
- //Remove the edge
+ case CHANGED:
+ // Mainly raised only on properties update, so not really useful
+ // in this case
+ break;
+ case REMOVED:
+ // Remove the edge
try {
topo.removeEdge(new Edge(src, dst));
- } catch (ConstructionException e) {
- e.printStackTrace();
+ } catch (final ConstructionException e) {
+ log.error("", e);
return edgePresentInGraph;
}
// If the src and dst vertex don't have incoming or
// outgoing links we can get ride of them
- if (topo.containsVertex(src.getNode())
- && topo.inDegree(src.getNode()) == 0
- && topo.outDegree(src.getNode()) == 0) {
+ if (topo.containsVertex(src.getNode()) && (topo.inDegree(src.getNode()) == 0)
+ && (topo.outDegree(src.getNode()) == 0)) {
log.debug("Removing vertex {}", src);
topo.removeVertex(src.getNode());
}
- if (topo.containsVertex(dst.getNode())
- && topo.inDegree(dst.getNode()) == 0
- && topo.outDegree(dst.getNode()) == 0) {
+ if (topo.containsVertex(dst.getNode()) && (topo.inDegree(dst.getNode()) == 0)
+ && (topo.outDegree(dst.getNode()) == 0)) {
log.debug("Removing vertex {}", dst);
topo.removeVertex(dst.getNode());
}
+ break;
}
spt.reset();
if (bw.equals(baseBW)) {
return edgePresentInGraph;
}
- @Override
- public void edgeUpdate(Edge e, UpdateType type, Set<Property> props) {
+ private boolean edgeUpdate(Edge e, UpdateType type, Set<Property> props, boolean local) {
String srcType = null;
String dstType = null;
- if (e == null || type == null) {
+ log.trace("Got an edgeUpdate: {} props: {} update type: {} local: {}", new Object[] { e, props, type, local });
+
+ if ((e == null) || (type == null)) {
log.error("Edge or Update type are null!");
- return;
+ return false;
} else {
srcType = e.getTailNodeConnector().getType();
dstType = e.getHeadNodeConnector().getType();
if (srcType.equals(NodeConnector.NodeConnectorIDType.PRODUCTION)) {
log.debug("Skip updates for {}", e);
- return;
+ return false;
}
if (dstType.equals(NodeConnector.NodeConnectorIDType.PRODUCTION)) {
log.debug("Skip updates for {}", e);
- return;
+ return false;
}
}
Bandwidth bw = new Bandwidth(0);
boolean newEdge = false;
- if (props != null)
+ if (props != null) {
props.remove(bw);
-
- log.debug("edgeUpdate: {} bw: {}", e.toString(), bw.getValue());
+ }
Short baseBW = Short.valueOf((short) 0);
- boolean add = (type == UpdateType.ADDED) ? true : false;
// Update base topo
- newEdge = !updateTopo(e, baseBW, add);
+ newEdge = !updateTopo(e, baseBW, type);
if (newEdge == true) {
if (bw.getValue() != baseBW) {
// Update BW topo
- updateTopo(e, (short) bw.getValue(), add);
+ updateTopo(e, (short) bw.getValue(), type);
}
- if (this.routingAware != null) {
- for (IListenRoutingUpdates ra : this.routingAware) {
- try {
- ra.recalculateDone();
- } catch (Exception ex) {
- log.error("Exception on routingAware listener call", e);
- }
+ }
+ return newEdge;
+ }
+
+ @Override
+ public void edgeUpdate(List<TopoEdgeUpdate> topoedgeupdateList) {
+ log.trace("Start of a Bulk EdgeUpdate with " + topoedgeupdateList.size() + " elements");
+ boolean callListeners = false;
+ for (int i = 0; i < topoedgeupdateList.size(); i++) {
+ Edge e = topoedgeupdateList.get(i).getEdge();
+ Set<Property> p = topoedgeupdateList.get(i)
+ .getProperty();
+ UpdateType type = topoedgeupdateList.get(i)
+ .getUpdateType();
+ boolean isLocal = topoedgeupdateList.get(i)
+ .isLocal();
+ if ((edgeUpdate(e, type, p, isLocal)) && (!callListeners)) {
+ callListeners = true;
+ }
+ }
+
+ // The routing listeners should only be called on the coordinator, to
+ // avoid multiple controller cluster nodes to actually do the
+ // recalculation when only one need to react
+ boolean amICoordinator = true;
+ if (this.clusterContainerService != null) {
+ amICoordinator = this.clusterContainerService.amICoordinator();
+ }
+ if ((callListeners) && (this.routingAware != null) && amICoordinator) {
+ log.trace("Calling the routing listeners");
+ for (IListenRoutingUpdates ra : this.routingAware) {
+ try {
+ ra.recalculateDone();
+ } catch (Exception ex) {
+ log.error("Exception on routingAware listener call", ex);
}
}
}
+ log.trace("End of a Bulk EdgeUpdate");
}
/**
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public void init() {
- log.debug("Routing init() is called");
- this.topologyBWAware = (ConcurrentMap<Short, Graph<Node, Edge>>) new ConcurrentHashMap();
- this.sptBWAware = (ConcurrentMap<Short, DijkstraShortestPath<Node, Edge>>) new ConcurrentHashMap();
- // Now create the default topology, which doesn't consider the
- // BW, also create the corresponding Dijkstra calculation
- Graph<Node, Edge> g = new SparseMultigraph();
- Short sZero = Short.valueOf((short) 0);
- this.topologyBWAware.put(sZero, g);
- this.sptBWAware.put(sZero, new DijkstraShortestPath(g));
- // Topologies for other BW will be added on a needed base
+ log.debug("Routing init() is called");
+ this.topologyBWAware = new ConcurrentHashMap<Short, Graph<Node, Edge>>();
+ this.sptBWAware = new ConcurrentHashMap<Short, DijkstraShortestPath<Node, Edge>>();
+ // Now create the default topology, which doesn't consider the
+ // BW, also create the corresponding Dijkstra calculation
+ Graph<Node, Edge> g = new SparseMultigraph();
+ Short sZero = Short.valueOf((short) 0);
+ this.topologyBWAware.put(sZero, g);
+ this.sptBWAware.put(sZero, new DijkstraShortestPath(g));
+ // Topologies for other BW will be added on a needed base
}
+
/**
* Function called by the dependency manager when at least one dependency
* become unsatisfied or when the component is shutting down because for
*
*/
void destroy() {
- log.debug("Routing destroy() is called");
+ log.debug("Routing destroy() is called");
}
/**
- * Function called by dependency manager after "init ()" is called
- * and after the services provided by the class are registered in
- * the service registry
+ * Function called by dependency manager after "init ()" is called and after
+ * the services provided by the class are registered in the service registry
*
*/
- void start() {
- log.debug("Routing start() is called");
- // build the routing database from the topology if it exists.
- Map<Edge, Set<Property>> edges = topologyManager.getEdges();
- if (edges.isEmpty()) {
- return;
- }
- log.debug("Creating routing database from the topology");
- for (Iterator<Map.Entry<Edge,Set<Property>>> i = edges.entrySet().iterator(); i.hasNext();) {
- Map.Entry<Edge, Set<Property>> entry = i.next();
- Edge e = entry.getKey();
- Set<Property> props = entry.getValue();
- edgeUpdate(e, UpdateType.ADDED, props);
- }
- }
+ void start() {
+ log.debug("Routing start() is called");
+ // build the routing database from the topology if it exists.
+ Map<Edge, Set<Property>> edges = topologyManager.getEdges();
+ if (edges.isEmpty()) {
+ return;
+ }
+ List<TopoEdgeUpdate> topoedgeupdateList = new ArrayList<TopoEdgeUpdate>();
+ log.debug("Creating routing database from the topology");
+ for (Iterator<Map.Entry<Edge, Set<Property>>> i = edges.entrySet()
+ .iterator(); i.hasNext();) {
+ Map.Entry<Edge, Set<Property>> entry = i.next();
+ Edge e = entry.getKey();
+ Set<Property> props = entry.getValue();
+ TopoEdgeUpdate topoedgeupdate = new TopoEdgeUpdate(e, props,
+ UpdateType.ADDED);
+ topoedgeupdateList.add(topoedgeupdate);
+ }
+ edgeUpdate(topoedgeupdateList);
+ }
/**
* Function called by the dependency manager before the services exported by
* calls
*
*/
- public void stop() {
- log.debug("Routing stop() is called");
- }
-
- @Override
- public void edgeOverUtilized(Edge edge) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void edgeUtilBackToNormal(Edge edge) {
- // TODO Auto-generated method stub
-
+ public void stop() {
+ log.debug("Routing stop() is called");
}
public void setSwitchManager(ISwitchManager switchManager) {
}
}
- public void setReadService(IReadService readService) {
- this.readService = readService;
+ public void setTopologyManager(ITopologyManager tm) {
+ this.topologyManager = tm;
}
- public void unsetReadService(IReadService readService) {
- if (this.readService == readService) {
- this.readService = null;
+ public void unsetTopologyManager(ITopologyManager tm) {
+ if (this.topologyManager == tm) {
+ this.topologyManager = null;
}
}
-
- public void setTopologyManager(ITopologyManager tm) {
- this.topologyManager = tm;
+
+ void setClusterContainerService(IClusterContainerServices s) {
+ log.debug("Cluster Service set");
+ this.clusterContainerService = s;
}
-
- public void unsetTopologyManager(ITopologyManager tm) {
- if (this.topologyManager == tm) {
- this.topologyManager = null;
- }
+
+ void unsetClusterContainerService(IClusterContainerServices s) {
+ if (this.clusterContainerService == s) {
+ log.debug("Cluster Service removed!");
+ this.clusterContainerService = null;
+ }
+ }
+
+ @Override
+ public void edgeOverUtilized(Edge edge) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void edgeUtilBackToNormal(Edge edge) {
+ // TODO Auto-generated method stub
+
}
}