blob: a074d197113ff62aee41ed3c7e375ebb48cffb53 [file] [log] [blame]
Pavlin Radoslavove1b37bc2013-10-16 03:57:06 -07001package net.onrc.onos.ofcontroller.topology;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -08002
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -07003import java.util.ArrayList;
4import java.util.Collection;
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -08005import java.util.HashMap;
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -08006import java.util.Map;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -08007
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -07008import net.floodlightcontroller.core.IFloodlightProviderService;
9import net.floodlightcontroller.core.module.FloodlightModuleContext;
10import net.floodlightcontroller.core.module.FloodlightModuleException;
11import net.floodlightcontroller.core.module.IFloodlightModule;
12import net.floodlightcontroller.core.module.IFloodlightService;
Naoki Shiotab32edf52013-12-12 14:09:36 -080013import net.floodlightcontroller.restserver.IRestApiService;
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -070014import net.onrc.onos.datagrid.IDatagridService;
yoshitomob292c622013-11-23 14:35:58 -080015import net.onrc.onos.graph.DBOperation;
16import net.onrc.onos.graph.GraphDBManager;
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -070017import net.onrc.onos.ofcontroller.floodlightlistener.INetworkGraphService;
Naoki Shiotab32edf52013-12-12 14:09:36 -080018import net.onrc.onos.ofcontroller.topology.web.OnosTopologyWebRoutable;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070019import net.onrc.onos.ofcontroller.util.DataPath;
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -070020import net.onrc.onos.ofcontroller.util.FlowEntry;
21import net.onrc.onos.ofcontroller.util.FlowPath;
22import net.onrc.onos.ofcontroller.util.Port;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070023import net.onrc.onos.ofcontroller.util.SwitchPort;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080024
Pankaj Berde15193092013-03-21 17:30:14 -070025import org.slf4j.Logger;
26import org.slf4j.LoggerFactory;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080027
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070028/**
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -070029 * A class for obtaining Topology Snapshot
30 * and PathComputation.
31 *
32 * TODO: PathComputation part should be refactored out to separate class.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070033 */
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -070034public class TopologyManager implements IFloodlightModule,
35 ITopologyNetService {
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070036 private final static Logger log = LoggerFactory.getLogger(TopologyManager.class);
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -070037 protected IFloodlightProviderService floodlightProvider;
38
yoshif7424e42013-11-25 22:07:40 -080039 protected static final String DBConfigFile = "dbconf";
40 protected static final String GraphDBStore = "graph_db_store";
41
yoshitomob292c622013-11-23 14:35:58 -080042 protected DBOperation dbHandler;
Naoki Shiotab32edf52013-12-12 14:09:36 -080043 protected IRestApiService restApi;
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080044
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070045
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070046 /**
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070047 * Default constructor.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070048 */
Pavlin Radoslavove1b37bc2013-10-16 03:57:06 -070049 public TopologyManager() {
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080050 }
51
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070052 /**
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070053 * Constructor for given database configuration file.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070054 *
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070055 * @param config the database configuration file to use for
56 * the initialization.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070057 */
yoshif7424e42013-11-25 22:07:40 -080058 public TopologyManager(FloodlightModuleContext context) {
59 Map<String, String> configMap = context.getConfigParams(this);
60 String conf = configMap.get(DBConfigFile);
61 String dbStore = configMap.get(GraphDBStore);
62 this.init(dbStore,conf);
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080063 }
64
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070065 /**
Pavlin Radoslavov0367d352013-10-19 11:04:43 -070066 * Constructor for a given database operation handler.
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -070067 *
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070068 * @param dbHandler the database operation handler to use for the
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -070069 * initialization.
70 */
yoshitomob292c622013-11-23 14:35:58 -080071 public TopologyManager(DBOperation dbHandler) {
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070072 this.dbHandler = dbHandler;
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -070073 }
74
75 /**
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070076 * Init the module.
yoshitomob292c622013-11-23 14:35:58 -080077 * @param
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070078 * @param config the database configuration file to use for
79 * the initialization.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070080 */
yoshitomob292c622013-11-23 14:35:58 -080081 public void init(final String dbStore, String config) {
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070082 try {
yoshid38cd312013-12-02 19:54:44 -080083 dbHandler = GraphDBManager.getDBOperation("ramcloud", "/tmp/ramcloudconf");
84 //dbHandler = GraphDBManager.getDBOperation(dbStore, config);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070085 } catch (Exception e) {
86 log.error(e.getMessage());
87 }
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080088 }
89
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070090 /**
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -070091 * Shutdown the Topology Manager operation.
92 */
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -080093 @Override
94 protected void finalize() {
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -070095 close();
96 }
97
98 /**
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070099 * Close the service. It will close the corresponding database connection.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700100 */
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700101 public void close() {
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700102 dbHandler.close();
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800103 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800104
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700105 /**
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -0700106 * Get the collection of offered module services.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700107 *
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -0700108 * @return the collection of offered module services.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700109 */
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -0700110 @Override
111 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -0800112 Collection<Class<? extends IFloodlightService>> l =
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -0700113 new ArrayList<Class<? extends IFloodlightService>>();
114 l.add(ITopologyNetService.class);
115 return l;
116 }
117
118 /**
119 * Get the collection of implemented services.
120 *
121 * @return the collection of implemented services.
122 */
123 @Override
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -0800124 public Map<Class<? extends IFloodlightService>, IFloodlightService>
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -0700125 getServiceImpls() {
126 Map<Class<? extends IFloodlightService>,
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -0800127 IFloodlightService> m =
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -0700128 new HashMap<Class<? extends IFloodlightService>,
129 IFloodlightService>();
130 m.put(ITopologyNetService.class, this);
131 return m;
132 }
133
134 /**
135 * Get the collection of modules this module depends on.
136 *
137 * @return the collection of modules this module depends on.
138 */
139 @Override
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -0800140 public Collection<Class<? extends IFloodlightService>>
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -0700141 getModuleDependencies() {
142 Collection<Class<? extends IFloodlightService>> l =
143 new ArrayList<Class<? extends IFloodlightService>>();
144 l.add(IFloodlightProviderService.class);
145 l.add(INetworkGraphService.class);
146 l.add(IDatagridService.class);
147 return l;
148 }
149
150 /**
151 * Initialize the module.
152 *
153 * @param context the module context to use for the initialization.
154 */
155 @Override
156 public void init(FloodlightModuleContext context)
157 throws FloodlightModuleException {
158 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Naoki Shiotab32edf52013-12-12 14:09:36 -0800159 restApi = context.getServiceImpl(IRestApiService.class);
yoshif7424e42013-11-25 22:07:40 -0800160 Map<String, String> configMap = context.getConfigParams(this);
161 String conf = configMap.get(DBConfigFile);
162 String dbStore = configMap.get(GraphDBStore);
163 this.init(dbStore, conf);
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -0700164 }
165
166 /**
167 * Startup module operation.
168 *
169 * @param context the module context to use for the startup.
170 */
171 @Override
172 public void startUp(FloodlightModuleContext context) {
Naoki Shiotab32edf52013-12-12 14:09:36 -0800173 restApi.addRestletRoutable(new OnosTopologyWebRoutable());
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -0700174
Pavlin Radoslavovcec899a2013-06-27 15:47:50 -0700175 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800176
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700177 /**
178 * Fetch the Switch and Ports info from the Titan Graph
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000179 * and return it for fast access during the shortest path
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700180 * computation.
181 *
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700182 * After fetching the state, method @ref getTopologyShortestPath()
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700183 * can be used for fast shortest path computation.
184 *
185 * Note: There is certain cost to fetch the state, hence it should
186 * be used only when there is a large number of shortest path
187 * computations that need to be done on the same topology.
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700188 * Typically, a single call to @ref newDatabaseTopology()
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700189 * should be followed by a large number of calls to
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700190 * method @ref getTopologyShortestPath().
191 * After the last @ref getTopologyShortestPath() call,
192 * method @ref dropTopology() should be used to release
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700193 * the internal state that is not needed anymore:
194 *
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700195 * Topology topology = topologyManager.newDatabaseTopology();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700196 * for (int i = 0; i < 10000; i++) {
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700197 * dataPath = topologyManager.getTopologyShortestPath(topology, ...);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700198 * ...
199 * }
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700200 * topologyManager.dropTopology(shortestPathTopo);
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000201 *
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700202 * @return the allocated topology handler.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700203 */
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -0800204 @Override
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700205 public Topology newDatabaseTopology() {
206 Topology topology = new Topology();
207 topology.readFromDatabase(dbHandler);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700208
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700209 return topology;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700210 }
211
212 /**
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700213 * Release the topology that was populated by
214 * method @ref newDatabaseTopology().
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700215 *
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700216 * See the documentation for method @ref newDatabaseTopology()
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700217 * for additional information and usage.
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000218 *
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700219 * @param topology the topology to release.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700220 */
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -0800221 @Override
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700222 public void dropTopology(Topology topology) {
223 topology = null;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700224 }
225
226 /**
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700227 * Compute the network path for a Flow.
228 *
229 * @param topology the topology handler to use.
230 * @param flowPath the Flow to compute the network path for.
231 * @return the data path with the computed path if found, otherwise null.
232 */
233 public static DataPath computeNetworkPath(Topology topology,
234 FlowPath flowPath) {
235 //
236 // Compute the network path based on the desired Flow Path type
237 //
238 switch (flowPath.flowPathType()) {
239 case FP_TYPE_SHORTEST_PATH: {
240 SwitchPort src = flowPath.dataPath().srcPort();
241 SwitchPort dest = flowPath.dataPath().dstPort();
242 return ShortestPath.getTopologyShortestPath(topology, src, dest);
243 }
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800244
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700245 case FP_TYPE_EXPLICIT_PATH:
246 return flowPath.dataPath();
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800247
248 case FP_TYPE_UNKNOWN:
249 return null;
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700250 }
251
252 return null;
253 }
254
255 /**
256 * Test whether two Flow Entries represent same points in a data path.
257 *
258 * NOTE: Two Flow Entries represent same points in a data path if
259 * the Switch DPID, incoming port and outgoing port are same.
260 *
261 * NOTE: This method is specialized for shortest-path unicast paths,
262 * and probably should be moved somewhere else.
263 *
264 * @param oldFlowEntry the first Flow Entry to compare.
265 * @param newFlowEntry the second Flow Entry to compare.
266 * @return true if the two Flow Entries represent same points in a
267 * data path, otherwise false.
268 */
269 public static boolean isSameFlowEntryDataPath(FlowEntry oldFlowEntry,
270 FlowEntry newFlowEntry) {
271 // Test the DPID
272 if (oldFlowEntry.dpid().value() != newFlowEntry.dpid().value())
273 return false;
274
275 // Test the inPort
276 do {
277 Port oldPort = oldFlowEntry.inPort();
278 Port newPort = newFlowEntry.inPort();
279 if ((oldPort != null) && (newPort != null) &&
280 (oldPort.value() == newPort.value())) {
281 break;
282 }
283 if ((oldPort == null) && (newPort == null))
284 break;
285 return false; // inPort is different
286 } while (false);
287
288 // Test the outPort
289 do {
290 Port oldPort = oldFlowEntry.outPort();
291 Port newPort = newFlowEntry.outPort();
292 if ((oldPort != null) && (newPort != null) &&
293 (oldPort.value() == newPort.value())) {
294 break;
295 }
296 if ((oldPort == null) && (newPort == null))
297 break;
298 return false; // outPort is different
299 } while (false);
300
301 return true;
302 }
303
304 /**
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700305 * Get the shortest path from a source to a destination by
306 * using the pre-populated local topology state prepared
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700307 * by method @ref newDatabaseTopology().
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700308 *
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700309 * See the documentation for method @ref newDatabaseTopology()
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700310 * for additional information and usage.
311 *
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700312 * @param topology the topology handler to use.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700313 * @param src the source in the shortest path computation.
314 * @param dest the destination in the shortest path computation.
315 * @return the data path with the computed shortest path if
316 * found, otherwise null.
317 */
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -0800318 @Override
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700319 public DataPath getTopologyShortestPath(Topology topology,
320 SwitchPort src, SwitchPort dest) {
321 return ShortestPath.getTopologyShortestPath(topology, src, dest);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700322 }
323
324 /**
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700325 * Get the shortest path from a source to a destination by using
326 * the underlying database.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700327 *
328 * @param src the source in the shortest path computation.
329 * @param dest the destination in the shortest path computation.
330 * @return the data path with the computed shortest path if
331 * found, otherwise null.
332 */
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800333 @Override
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700334 public DataPath getDatabaseShortestPath(SwitchPort src, SwitchPort dest) {
335 return ShortestPath.getDatabaseShortestPath(dbHandler, src, dest);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800336 }
337
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700338 /**
339 * Test whether a route exists from a source to a destination.
340 *
341 * @param src the source node for the test.
342 * @param dest the destination node for the test.
343 * @return true if a route exists, otherwise false.
344 */
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800345 @Override
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800346 public Boolean routeExists(SwitchPort src, SwitchPort dest) {
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700347 DataPath dataPath = getDatabaseShortestPath(src, dest);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700348 return (dataPath != null);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800349 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800350}