blob: be207c6e69face487b8f44baf832cbbf93fc3744 [file] [log] [blame]
package net.onrc.onos.ofcontroller.topology;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import net.floodlightcontroller.core.IFloodlightProviderService;
import net.floodlightcontroller.core.module.FloodlightModuleContext;
import net.floodlightcontroller.core.module.FloodlightModuleException;
import net.floodlightcontroller.core.module.IFloodlightModule;
import net.floodlightcontroller.core.module.IFloodlightService;
import net.floodlightcontroller.restserver.IRestApiService;
import net.onrc.onos.datagrid.IDatagridService;
import net.onrc.onos.graph.GraphDBOperation;
import net.onrc.onos.ofcontroller.floodlightlistener.INetworkGraphService;
import net.onrc.onos.ofcontroller.topology.web.OnosTopologyWebRoutable;
import net.onrc.onos.ofcontroller.util.DataPath;
import net.onrc.onos.ofcontroller.util.FlowEntry;
import net.onrc.onos.ofcontroller.util.FlowPath;
import net.onrc.onos.ofcontroller.util.Port;
import net.onrc.onos.ofcontroller.util.SwitchPort;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A class for obtaining Topology Snapshot
* and PathComputation.
*
* TODO: PathComputation part should be refactored out to separate class.
*/
public class TopologyManager implements IFloodlightModule,
ITopologyNetService {
private final static Logger log = LoggerFactory.getLogger(TopologyManager.class);
protected IFloodlightProviderService floodlightProvider;
protected GraphDBOperation dbHandler;
protected IRestApiService restApi;
/**
* Default constructor.
*/
public TopologyManager() {
}
/**
* Constructor for given database configuration file.
*
* @param config the database configuration file to use for
* the initialization.
*/
public TopologyManager(String config) {
this.init(config);
}
/**
* Constructor for a given database operation handler.
*
* @param dbHandler the database operation handler to use for the
* initialization.
*/
public TopologyManager(GraphDBOperation dbHandler) {
this.dbHandler = dbHandler;
}
/**
* Init the module.
*
* @param config the database configuration file to use for
* the initialization.
*/
public void init(String config) {
try {
dbHandler = new GraphDBOperation(config);
} catch (Exception e) {
log.error(e.getMessage());
}
}
/**
* Shutdown the Topology Manager operation.
*/
public void finalize() {
close();
}
/**
* Close the service. It will close the corresponding database connection.
*/
public void close() {
dbHandler.close();
}
/**
* Get the collection of offered module services.
*
* @return the collection of offered module services.
*/
@Override
public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Collection<Class<? extends IFloodlightService>> l =
new ArrayList<Class<? extends IFloodlightService>>();
l.add(ITopologyNetService.class);
return l;
}
/**
* Get the collection of implemented services.
*
* @return the collection of implemented services.
*/
@Override
public Map<Class<? extends IFloodlightService>, IFloodlightService>
getServiceImpls() {
Map<Class<? extends IFloodlightService>,
IFloodlightService> m =
new HashMap<Class<? extends IFloodlightService>,
IFloodlightService>();
m.put(ITopologyNetService.class, this);
return m;
}
/**
* Get the collection of modules this module depends on.
*
* @return the collection of modules this module depends on.
*/
@Override
public Collection<Class<? extends IFloodlightService>>
getModuleDependencies() {
Collection<Class<? extends IFloodlightService>> l =
new ArrayList<Class<? extends IFloodlightService>>();
l.add(IFloodlightProviderService.class);
l.add(INetworkGraphService.class);
l.add(IDatagridService.class);
return l;
}
/**
* Initialize the module.
*
* @param context the module context to use for the initialization.
*/
@Override
public void init(FloodlightModuleContext context)
throws FloodlightModuleException {
floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
restApi = context.getServiceImpl(IRestApiService.class);
String conf = "";
this.init(conf);
}
/**
* Startup module operation.
*
* @param context the module context to use for the startup.
*/
@Override
public void startUp(FloodlightModuleContext context) {
restApi.addRestletRoutable(new OnosTopologyWebRoutable());
}
/**
* Fetch the Switch and Ports info from the Titan Graph
* and return it for fast access during the shortest path
* computation.
*
* After fetching the state, method @ref getTopologyShortestPath()
* can be used for fast shortest path computation.
*
* Note: There is certain cost to fetch the state, hence it should
* be used only when there is a large number of shortest path
* computations that need to be done on the same topology.
* Typically, a single call to @ref newDatabaseTopology()
* should be followed by a large number of calls to
* method @ref getTopologyShortestPath().
* After the last @ref getTopologyShortestPath() call,
* method @ref dropTopology() should be used to release
* the internal state that is not needed anymore:
*
* Topology topology = topologyManager.newDatabaseTopology();
* for (int i = 0; i < 10000; i++) {
* dataPath = topologyManager.getTopologyShortestPath(topology, ...);
* ...
* }
* topologyManager.dropTopology(shortestPathTopo);
*
* @return the allocated topology handler.
*/
public Topology newDatabaseTopology() {
Topology topology = new Topology();
topology.readFromDatabase(dbHandler);
return topology;
}
/**
* Release the topology that was populated by
* method @ref newDatabaseTopology().
*
* See the documentation for method @ref newDatabaseTopology()
* for additional information and usage.
*
* @param topology the topology to release.
*/
public void dropTopology(Topology topology) {
topology = null;
}
/**
* Compute the network path for a Flow.
*
* @param topology the topology handler to use.
* @param flowPath the Flow to compute the network path for.
* @return the data path with the computed path if found, otherwise null.
*/
public static DataPath computeNetworkPath(Topology topology,
FlowPath flowPath) {
//
// Compute the network path based on the desired Flow Path type
//
switch (flowPath.flowPathType()) {
case FP_TYPE_SHORTEST_PATH: {
SwitchPort src = flowPath.dataPath().srcPort();
SwitchPort dest = flowPath.dataPath().dstPort();
return ShortestPath.getTopologyShortestPath(topology, src, dest);
}
case FP_TYPE_EXPLICIT_PATH:
return flowPath.dataPath();
case FP_TYPE_UNKNOWN:
return null;
}
return null;
}
/**
* Test whether two Flow Entries represent same points in a data path.
*
* NOTE: Two Flow Entries represent same points in a data path if
* the Switch DPID, incoming port and outgoing port are same.
*
* NOTE: This method is specialized for shortest-path unicast paths,
* and probably should be moved somewhere else.
*
* @param oldFlowEntry the first Flow Entry to compare.
* @param newFlowEntry the second Flow Entry to compare.
* @return true if the two Flow Entries represent same points in a
* data path, otherwise false.
*/
public static boolean isSameFlowEntryDataPath(FlowEntry oldFlowEntry,
FlowEntry newFlowEntry) {
// Test the DPID
if (oldFlowEntry.dpid().value() != newFlowEntry.dpid().value())
return false;
// Test the inPort
do {
Port oldPort = oldFlowEntry.inPort();
Port newPort = newFlowEntry.inPort();
if ((oldPort != null) && (newPort != null) &&
(oldPort.value() == newPort.value())) {
break;
}
if ((oldPort == null) && (newPort == null))
break;
return false; // inPort is different
} while (false);
// Test the outPort
do {
Port oldPort = oldFlowEntry.outPort();
Port newPort = newFlowEntry.outPort();
if ((oldPort != null) && (newPort != null) &&
(oldPort.value() == newPort.value())) {
break;
}
if ((oldPort == null) && (newPort == null))
break;
return false; // outPort is different
} while (false);
return true;
}
/**
* Get the shortest path from a source to a destination by
* using the pre-populated local topology state prepared
* by method @ref newDatabaseTopology().
*
* See the documentation for method @ref newDatabaseTopology()
* for additional information and usage.
*
* @param topology the topology handler to use.
* @param src the source in the shortest path computation.
* @param dest the destination in the shortest path computation.
* @return the data path with the computed shortest path if
* found, otherwise null.
*/
public DataPath getTopologyShortestPath(Topology topology,
SwitchPort src, SwitchPort dest) {
return ShortestPath.getTopologyShortestPath(topology, src, dest);
}
/**
* Get the shortest path from a source to a destination by using
* the underlying database.
*
* @param src the source in the shortest path computation.
* @param dest the destination in the shortest path computation.
* @return the data path with the computed shortest path if
* found, otherwise null.
*/
@Override
public DataPath getDatabaseShortestPath(SwitchPort src, SwitchPort dest) {
return ShortestPath.getDatabaseShortestPath(dbHandler, src, dest);
}
/**
* Test whether a route exists from a source to a destination.
*
* @param src the source node for the test.
* @param dest the destination node for the test.
* @return true if a route exists, otherwise false.
*/
@Override
public Boolean routeExists(SwitchPort src, SwitchPort dest) {
DataPath dataPath = getDatabaseShortestPath(src, dest);
return (dataPath != null);
}
}