blob: d44758049a4ee9cf7bae9fadb2acd837d9913bbc [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;
Pankaj Berde38646d62013-06-21 11:34:04 -070015import net.onrc.onos.graph.GraphDBOperation;
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -070016import net.onrc.onos.ofcontroller.floodlightlistener.INetworkGraphService;
Naoki Shiotab32edf52013-12-12 14:09:36 -080017import net.onrc.onos.ofcontroller.topology.web.OnosTopologyWebRoutable;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070018import net.onrc.onos.ofcontroller.util.DataPath;
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -070019import net.onrc.onos.ofcontroller.util.FlowEntry;
20import net.onrc.onos.ofcontroller.util.FlowPath;
21import net.onrc.onos.ofcontroller.util.Port;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070022import net.onrc.onos.ofcontroller.util.SwitchPort;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080023
Pankaj Berde15193092013-03-21 17:30:14 -070024import org.slf4j.Logger;
25import org.slf4j.LoggerFactory;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080026
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070027/**
Yuta HIGUCHIe1038fb2013-10-30 15:35:18 -070028 * A class for obtaining Topology Snapshot
29 * and PathComputation.
30 *
31 * TODO: PathComputation part should be refactored out to separate class.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070032 */
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -070033public class TopologyManager implements IFloodlightModule,
34 ITopologyNetService {
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070035 private final static Logger log = LoggerFactory.getLogger(TopologyManager.class);
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -070036 protected IFloodlightProviderService floodlightProvider;
37
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070038 protected GraphDBOperation dbHandler;
Naoki Shiotab32edf52013-12-12 14:09:36 -080039 protected IRestApiService restApi;
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080040
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070041
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070042 /**
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070043 * Default constructor.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070044 */
Pavlin Radoslavove1b37bc2013-10-16 03:57:06 -070045 public TopologyManager() {
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080046 }
47
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070048 /**
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070049 * Constructor for given database configuration file.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070050 *
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070051 * @param config the database configuration file to use for
52 * the initialization.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070053 */
Pavlin Radoslavove1b37bc2013-10-16 03:57:06 -070054 public TopologyManager(String config) {
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070055 this.init(config);
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080056 }
57
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070058 /**
Pavlin Radoslavov0367d352013-10-19 11:04:43 -070059 * Constructor for a given database operation handler.
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -070060 *
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070061 * @param dbHandler the database operation handler to use for the
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -070062 * initialization.
63 */
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070064 public TopologyManager(GraphDBOperation dbHandler) {
65 this.dbHandler = dbHandler;
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -070066 }
67
68 /**
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070069 * Init the module.
70 *
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070071 * @param config the database configuration file to use for
72 * the initialization.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070073 */
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070074 public void init(String config) {
75 try {
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070076 dbHandler = new GraphDBOperation(config);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070077 } catch (Exception e) {
78 log.error(e.getMessage());
79 }
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080080 }
81
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070082 /**
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -070083 * Shutdown the Topology Manager operation.
84 */
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -080085 @Override
86 protected void finalize() {
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -070087 close();
88 }
89
90 /**
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070091 * Close the service. It will close the corresponding database connection.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070092 */
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070093 public void close() {
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070094 dbHandler.close();
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080095 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080096
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070097 /**
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -070098 * Get the collection of offered module services.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070099 *
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -0700100 * @return the collection of offered module services.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700101 */
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -0700102 @Override
103 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -0800104 Collection<Class<? extends IFloodlightService>> l =
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -0700105 new ArrayList<Class<? extends IFloodlightService>>();
106 l.add(ITopologyNetService.class);
107 return l;
108 }
109
110 /**
111 * Get the collection of implemented services.
112 *
113 * @return the collection of implemented services.
114 */
115 @Override
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -0800116 public Map<Class<? extends IFloodlightService>, IFloodlightService>
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -0700117 getServiceImpls() {
118 Map<Class<? extends IFloodlightService>,
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -0800119 IFloodlightService> m =
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -0700120 new HashMap<Class<? extends IFloodlightService>,
121 IFloodlightService>();
122 m.put(ITopologyNetService.class, this);
123 return m;
124 }
125
126 /**
127 * Get the collection of modules this module depends on.
128 *
129 * @return the collection of modules this module depends on.
130 */
131 @Override
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -0800132 public Collection<Class<? extends IFloodlightService>>
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -0700133 getModuleDependencies() {
134 Collection<Class<? extends IFloodlightService>> l =
135 new ArrayList<Class<? extends IFloodlightService>>();
136 l.add(IFloodlightProviderService.class);
137 l.add(INetworkGraphService.class);
138 l.add(IDatagridService.class);
139 return l;
140 }
141
142 /**
143 * Initialize the module.
144 *
145 * @param context the module context to use for the initialization.
146 */
147 @Override
148 public void init(FloodlightModuleContext context)
149 throws FloodlightModuleException {
150 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Naoki Shiotab32edf52013-12-12 14:09:36 -0800151 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -0700152
153 String conf = "";
154 this.init(conf);
155 }
156
157 /**
158 * Startup module operation.
159 *
160 * @param context the module context to use for the startup.
161 */
162 @Override
163 public void startUp(FloodlightModuleContext context) {
Naoki Shiotab32edf52013-12-12 14:09:36 -0800164 restApi.addRestletRoutable(new OnosTopologyWebRoutable());
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -0700165
Pavlin Radoslavovcec899a2013-06-27 15:47:50 -0700166 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800167
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700168 /**
169 * Fetch the Switch and Ports info from the Titan Graph
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000170 * and return it for fast access during the shortest path
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700171 * computation.
172 *
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700173 * After fetching the state, method @ref getTopologyShortestPath()
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700174 * can be used for fast shortest path computation.
175 *
176 * Note: There is certain cost to fetch the state, hence it should
177 * be used only when there is a large number of shortest path
178 * computations that need to be done on the same topology.
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700179 * Typically, a single call to @ref newDatabaseTopology()
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700180 * should be followed by a large number of calls to
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700181 * method @ref getTopologyShortestPath().
182 * After the last @ref getTopologyShortestPath() call,
183 * method @ref dropTopology() should be used to release
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700184 * the internal state that is not needed anymore:
185 *
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700186 * Topology topology = topologyManager.newDatabaseTopology();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700187 * for (int i = 0; i < 10000; i++) {
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700188 * dataPath = topologyManager.getTopologyShortestPath(topology, ...);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700189 * ...
190 * }
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700191 * topologyManager.dropTopology(shortestPathTopo);
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000192 *
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700193 * @return the allocated topology handler.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700194 */
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -0800195 @Override
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700196 public Topology newDatabaseTopology() {
197 Topology topology = new Topology();
198 topology.readFromDatabase(dbHandler);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700199
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700200 return topology;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700201 }
202
203 /**
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700204 * Release the topology that was populated by
205 * method @ref newDatabaseTopology().
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700206 *
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700207 * See the documentation for method @ref newDatabaseTopology()
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700208 * for additional information and usage.
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000209 *
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700210 * @param topology the topology to release.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700211 */
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -0800212 @Override
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700213 public void dropTopology(Topology topology) {
Naoki Shiotadf051d42014-01-20 16:12:41 -0800214 // nothing to do
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700215 }
216
217 /**
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700218 * Compute the network path for a Flow.
219 *
220 * @param topology the topology handler to use.
221 * @param flowPath the Flow to compute the network path for.
222 * @return the data path with the computed path if found, otherwise null.
223 */
224 public static DataPath computeNetworkPath(Topology topology,
225 FlowPath flowPath) {
226 //
227 // Compute the network path based on the desired Flow Path type
228 //
229 switch (flowPath.flowPathType()) {
230 case FP_TYPE_SHORTEST_PATH: {
231 SwitchPort src = flowPath.dataPath().srcPort();
232 SwitchPort dest = flowPath.dataPath().dstPort();
233 return ShortestPath.getTopologyShortestPath(topology, src, dest);
234 }
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800235
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700236 case FP_TYPE_EXPLICIT_PATH:
237 return flowPath.dataPath();
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800238
239 case FP_TYPE_UNKNOWN:
240 return null;
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700241 }
Pavlin Radoslavov4839f6d2013-12-11 12:49:45 -0800242
243 return null;
Pavlin Radoslavov3ecd41e2013-10-29 14:29:30 -0700244 }
245
246 /**
247 * Test whether two Flow Entries represent same points in a data path.
248 *
249 * NOTE: Two Flow Entries represent same points in a data path if
250 * the Switch DPID, incoming port and outgoing port are same.
251 *
252 * NOTE: This method is specialized for shortest-path unicast paths,
253 * and probably should be moved somewhere else.
254 *
255 * @param oldFlowEntry the first Flow Entry to compare.
256 * @param newFlowEntry the second Flow Entry to compare.
257 * @return true if the two Flow Entries represent same points in a
258 * data path, otherwise false.
259 */
260 public static boolean isSameFlowEntryDataPath(FlowEntry oldFlowEntry,
261 FlowEntry newFlowEntry) {
262 // Test the DPID
263 if (oldFlowEntry.dpid().value() != newFlowEntry.dpid().value())
264 return false;
265
266 // Test the inPort
267 do {
268 Port oldPort = oldFlowEntry.inPort();
269 Port newPort = newFlowEntry.inPort();
270 if ((oldPort != null) && (newPort != null) &&
271 (oldPort.value() == newPort.value())) {
272 break;
273 }
274 if ((oldPort == null) && (newPort == null))
275 break;
276 return false; // inPort is different
277 } while (false);
278
279 // Test the outPort
280 do {
281 Port oldPort = oldFlowEntry.outPort();
282 Port newPort = newFlowEntry.outPort();
283 if ((oldPort != null) && (newPort != null) &&
284 (oldPort.value() == newPort.value())) {
285 break;
286 }
287 if ((oldPort == null) && (newPort == null))
288 break;
289 return false; // outPort is different
290 } while (false);
291
292 return true;
293 }
294
295 /**
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700296 * Get the shortest path from a source to a destination by
297 * using the pre-populated local topology state prepared
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700298 * by method @ref newDatabaseTopology().
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700299 *
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700300 * See the documentation for method @ref newDatabaseTopology()
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700301 * for additional information and usage.
302 *
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700303 * @param topology the topology handler to use.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700304 * @param src the source in the shortest path computation.
305 * @param dest the destination in the shortest path computation.
306 * @return the data path with the computed shortest path if
307 * found, otherwise null.
308 */
Yuta HIGUCHI67a7a3e2014-01-03 14:51:34 -0800309 @Override
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700310 public DataPath getTopologyShortestPath(Topology topology,
311 SwitchPort src, SwitchPort dest) {
312 return ShortestPath.getTopologyShortestPath(topology, src, dest);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700313 }
314
315 /**
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700316 * Get the shortest path from a source to a destination by using
317 * the underlying database.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700318 *
319 * @param src the source in the shortest path computation.
320 * @param dest the destination in the shortest path computation.
321 * @return the data path with the computed shortest path if
322 * found, otherwise null.
323 */
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800324 @Override
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700325 public DataPath getDatabaseShortestPath(SwitchPort src, SwitchPort dest) {
326 return ShortestPath.getDatabaseShortestPath(dbHandler, src, dest);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800327 }
328
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700329 /**
330 * Test whether a route exists from a source to a destination.
331 *
332 * @param src the source node for the test.
333 * @param dest the destination node for the test.
334 * @return true if a route exists, otherwise false.
335 */
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800336 @Override
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800337 public Boolean routeExists(SwitchPort src, SwitchPort dest) {
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700338 DataPath dataPath = getDatabaseShortestPath(src, dest);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700339 return (dataPath != null);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800340 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800341}