blob: a327ef9ab30ac1509fda66d19315463ab809e19a [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 Radoslavova5f167b2013-03-21 11:39:27 -07005import java.util.Collections;
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -08006import java.util.HashMap;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -07007import java.util.HashSet;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -07008import java.util.LinkedList;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -08009import java.util.List;
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080010import java.util.Map;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070011import java.util.Queue;
12import java.util.Set;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080013
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -070014import net.floodlightcontroller.core.IFloodlightProviderService;
15import net.floodlightcontroller.core.module.FloodlightModuleContext;
16import net.floodlightcontroller.core.module.FloodlightModuleException;
17import net.floodlightcontroller.core.module.IFloodlightModule;
18import net.floodlightcontroller.core.module.IFloodlightService;
19
20import net.onrc.onos.datagrid.IDatagridService;
Pankaj Berde38646d62013-06-21 11:34:04 -070021import net.onrc.onos.graph.GraphDBOperation;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070022import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070023import net.onrc.onos.ofcontroller.core.ISwitchStorage.SwitchState;
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -070024import net.onrc.onos.ofcontroller.floodlightlistener.INetworkGraphService;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070025import net.onrc.onos.ofcontroller.util.DataPath;
26import net.onrc.onos.ofcontroller.util.Dpid;
27import net.onrc.onos.ofcontroller.util.FlowEntry;
28import net.onrc.onos.ofcontroller.util.Port;
29import net.onrc.onos.ofcontroller.util.SwitchPort;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080030
31import org.openflow.util.HexString;
Pankaj Berde15193092013-03-21 17:30:14 -070032import org.slf4j.Logger;
33import org.slf4j.LoggerFactory;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080034
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070035import com.tinkerpop.blueprints.Direction;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080036import com.tinkerpop.blueprints.Vertex;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080037
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070038
39/**
40 * A class for storing Node and Link information for fast computation
41 * of shortest paths.
42 */
43class Node {
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070044 /**
45 * A class for storing Link information for fast computation of shortest
46 * paths.
47 */
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070048 class Link {
49 public Node me; // The node this link originates from
50 public Node neighbor; // The neighbor node on the other side
51 public short myPort; // Local port number for the link
52 public short neighborPort; // Neighbor port number for the link
53
54 /**
55 * Link constructor.
56 *
57 * @param me the node this link originates from.
58 * @param the neighbor node on the other side of the link.
59 * @param myPort local port number for the link.
60 * @param neighborPort neighrobr port number for the link.
61 */
62 public Link(Node me, Node neighbor, short myPort, short neighborPort) {
63 this.me = me;
64 this.neighbor = neighbor;
65 this.myPort = myPort;
66 this.neighborPort = neighborPort;
67 }
68 };
69
70 public long nodeId; // The node ID
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -070071 public HashMap<Short, Link> links; // The links originating from this node
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070072
73 /**
74 * Node constructor.
75 *
76 * @param nodeId the node ID.
77 */
78 public Node(long nodeId) {
79 this.nodeId = nodeId;
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -070080 links = new HashMap<Short, Link>();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070081 }
82
83 /**
84 * Add a neighbor.
85 *
86 * A new link to the neighbor will be created.
87 *
88 * @param neighbor the neighbor to add.
89 * @param myPort the local port number for the link to the neighbor.
90 * @param neighborPort the neighbor port number for the link.
91 */
92 public void addNeighbor(Node neighbor, short myPort, short neighborPort) {
93 Link link = new Link(this, neighbor, myPort, neighborPort);
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -070094 links.put(myPort, link);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070095 }
96};
97
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070098/**
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070099 * A class for implementing Topology Network Service.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700100 */
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -0700101public class TopologyManager implements IFloodlightModule,
102 ITopologyNetService {
Pavlin Radoslavove1b37bc2013-10-16 03:57:06 -0700103 private static Logger log = LoggerFactory.getLogger(TopologyManager.class);
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -0700104 protected IFloodlightProviderService floodlightProvider;
105
Toshio Koide18e47202013-06-13 14:07:13 -0700106 protected GraphDBOperation op;
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800107
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700108
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700109 /**
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700110 * Default constructor.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700111 */
Pavlin Radoslavove1b37bc2013-10-16 03:57:06 -0700112 public TopologyManager() {
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800113 }
114
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700115 /**
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700116 * Constructor for given database configuration file.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700117 *
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700118 * @param config the database configuration file to use for
119 * the initialization.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700120 */
Pavlin Radoslavove1b37bc2013-10-16 03:57:06 -0700121 public TopologyManager(String config) {
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700122 this.init(config);
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800123 }
124
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700125 /**
Pavlin Radoslavov0367d352013-10-19 11:04:43 -0700126 * Constructor for a given database operation handler.
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -0700127 *
Pavlin Radoslavov0367d352013-10-19 11:04:43 -0700128 * @param handler the database operation handler to use for the
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -0700129 * initialization.
130 */
Pavlin Radoslavov0367d352013-10-19 11:04:43 -0700131 public TopologyManager(GraphDBOperation handler) {
132 this.op = handler;
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -0700133 }
134
135 /**
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700136 * Init the module.
137 *
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700138 * @param config the database configuration file to use for
139 * the initialization.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700140 */
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700141 public void init(String config) {
142 try {
143 op = new GraphDBOperation(config);
144 } catch (Exception e) {
145 log.error(e.getMessage());
146 }
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800147 }
148
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700149 /**
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -0700150 * Shutdown the Topology Manager operation.
151 */
152 public void finalize() {
153 close();
154 }
155
156 /**
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700157 * Close the service. It will close the corresponding database connection.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700158 */
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700159 public void close() {
160 op.close();
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800161 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800162
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700163 /**
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -0700164 * Get the collection of offered module services.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700165 *
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -0700166 * @return the collection of offered module services.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700167 */
Pavlin Radoslavov5d8d77e2013-10-18 18:49:25 -0700168 @Override
169 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
170 Collection<Class<? extends IFloodlightService>> l =
171 new ArrayList<Class<? extends IFloodlightService>>();
172 l.add(ITopologyNetService.class);
173 return l;
174 }
175
176 /**
177 * Get the collection of implemented services.
178 *
179 * @return the collection of implemented services.
180 */
181 @Override
182 public Map<Class<? extends IFloodlightService>, IFloodlightService>
183 getServiceImpls() {
184 Map<Class<? extends IFloodlightService>,
185 IFloodlightService> m =
186 new HashMap<Class<? extends IFloodlightService>,
187 IFloodlightService>();
188 m.put(ITopologyNetService.class, this);
189 return m;
190 }
191
192 /**
193 * Get the collection of modules this module depends on.
194 *
195 * @return the collection of modules this module depends on.
196 */
197 @Override
198 public Collection<Class<? extends IFloodlightService>>
199 getModuleDependencies() {
200 Collection<Class<? extends IFloodlightService>> l =
201 new ArrayList<Class<? extends IFloodlightService>>();
202 l.add(IFloodlightProviderService.class);
203 l.add(INetworkGraphService.class);
204 l.add(IDatagridService.class);
205 return l;
206 }
207
208 /**
209 * Initialize the module.
210 *
211 * @param context the module context to use for the initialization.
212 */
213 @Override
214 public void init(FloodlightModuleContext context)
215 throws FloodlightModuleException {
216 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
217
218 String conf = "";
219 this.init(conf);
220 }
221
222 /**
223 * Startup module operation.
224 *
225 * @param context the module context to use for the startup.
226 */
227 @Override
228 public void startUp(FloodlightModuleContext context) {
229
Pavlin Radoslavovcec899a2013-06-27 15:47:50 -0700230 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800231
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700232 /**
233 * Fetch the Switch and Ports info from the Titan Graph
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000234 * and return it for fast access during the shortest path
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700235 * computation.
236 *
237 * After fetching the state, method @ref getTopoShortestPath()
238 * can be used for fast shortest path computation.
239 *
240 * Note: There is certain cost to fetch the state, hence it should
241 * be used only when there is a large number of shortest path
242 * computations that need to be done on the same topology.
243 * Typically, a single call to @ref prepareShortestPathTopo()
244 * should be followed by a large number of calls to
245 * method @ref getTopoShortestPath().
246 * After the last @ref getTopoShortestPath() call,
247 * method @ref dropShortestPathTopo() should be used to release
248 * the internal state that is not needed anymore:
249 *
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000250 * Map<Long, ?> shortestPathTopo;
251 * shortestPathTopo = prepareShortestPathTopo();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700252 * for (int i = 0; i < 10000; i++) {
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000253 * dataPath = getTopoShortestPath(shortestPathTopo, ...);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700254 * ...
255 * }
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000256 * dropShortestPathTopo(shortestPathTopo);
257 *
258 * @return the Shortest Path info handler stored in a map.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700259 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000260 public Map<Long, ?> prepareShortestPathTopo() {
261 Map<Long, Node> shortestPathTopo = new HashMap<Long, Node>();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700262
263 //
264 // Fetch the relevant info from the Switch and Port vertices
265 // from the Titan Graph.
266 //
Toshio Koide18e47202013-06-13 14:07:13 -0700267 Iterable<ISwitchObject> nodes = op.getActiveSwitches();
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700268 for (ISwitchObject switchObj : nodes) {
269 Vertex nodeVertex = switchObj.asVertex();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700270 //
271 // The Switch info
272 //
273 String nodeDpid = nodeVertex.getProperty("dpid").toString();
274 long nodeId = HexString.toLong(nodeDpid);
275 Node me = shortestPathTopo.get(nodeId);
276 if (me == null) {
277 me = new Node(nodeId);
278 shortestPathTopo.put(nodeId, me);
279 }
280
281 //
282 // The local Port info
283 //
284 for (Vertex myPortVertex : nodeVertex.getVertices(Direction.OUT, "on")) {
Pavlin Radoslavov65d50b52013-09-05 14:24:59 -0700285 // Ignore inactive ports
286 if (! myPortVertex.getProperty("state").toString().equals("ACTIVE"))
287 continue;
288
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700289 short myPort = 0;
290 Object obj = myPortVertex.getProperty("number");
291 if (obj instanceof Short) {
292 myPort = (Short)obj;
293 } else if (obj instanceof Integer) {
294 Integer int_nodeId = (Integer)obj;
295 myPort = int_nodeId.shortValue();
296 }
297
298 //
299 // The neighbor Port info
300 //
301 for (Vertex neighborPortVertex : myPortVertex.getVertices(Direction.OUT, "link")) {
Pavlin Radoslavov65d50b52013-09-05 14:24:59 -0700302 // Ignore inactive ports
303 if (! neighborPortVertex.getProperty("state").toString().equals("ACTIVE"))
304 continue;
305
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700306 short neighborPort = 0;
307 obj = neighborPortVertex.getProperty("number");
308 if (obj instanceof Short) {
309 neighborPort = (Short)obj;
310 } else if (obj instanceof Integer) {
311 Integer int_nodeId = (Integer)obj;
312 neighborPort = int_nodeId.shortValue();
313 }
314 //
315 // The neighbor Switch info
316 //
317 for (Vertex neighborVertex : neighborPortVertex.getVertices(Direction.IN, "on")) {
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700318 // Ignore inactive switches
319 String state = neighborVertex.getProperty("state").toString();
320 if (! state.equals(SwitchState.ACTIVE.toString()))
321 continue;
322
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700323 String neighborDpid = neighborVertex.getProperty("dpid").toString();
324 long neighborId = HexString.toLong(neighborDpid);
325 Node neighbor = shortestPathTopo.get(neighborId);
326 if (neighbor == null) {
327 neighbor = new Node(neighborId);
328 shortestPathTopo.put(neighborId, neighbor);
329 }
330 me.addNeighbor(neighbor, myPort, neighborPort);
331 }
332 }
333 }
334 }
Toshio Koide18e47202013-06-13 14:07:13 -0700335 op.commit();
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000336
337 return shortestPathTopo;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700338 }
339
340 /**
341 * Release the state that was populated by
342 * method @ref prepareShortestPathTopo().
343 *
344 * See the documentation for method @ref prepareShortestPathTopo()
345 * for additional information and usage.
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000346 *
Pavlin Radoslavoved13a242013-06-20 17:37:20 -0700347 * @param shortestPathTopo the Shortest Path info handler to release.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700348 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000349 public void dropShortestPathTopo(Map<Long, ?> shortestPathTopo) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700350 shortestPathTopo = null;
351 }
352
353 /**
354 * Get the shortest path from a source to a destination by
355 * using the pre-populated local topology state prepared
356 * by method @ref prepareShortestPathTopo().
357 *
358 * See the documentation for method @ref prepareShortestPathTopo()
359 * for additional information and usage.
360 *
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000361 * @param shortestPathTopoHandler the Shortest Path info handler
362 * to use.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700363 * @param src the source in the shortest path computation.
364 * @param dest the destination in the shortest path computation.
365 * @return the data path with the computed shortest path if
366 * found, otherwise null.
367 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000368 public DataPath getTopoShortestPath(Map<Long, ?> shortestPathTopoHandler,
369 SwitchPort src, SwitchPort dest) {
370 @SuppressWarnings("unchecked")
Yuta HIGUCHIfbc4d772013-10-14 09:58:15 -0700371 Map<Long, Node> shortestPathTopo = (Map<Long, Node>)shortestPathTopoHandler;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700372 DataPath result_data_path = new DataPath();
373
374 // Initialize the source and destination in the data path to return
375 result_data_path.setSrcPort(src);
376 result_data_path.setDstPort(dest);
377
378 String dpid_src = src.dpid().toString();
379 String dpid_dest = dest.dpid().toString();
380
381 // Get the source vertex
382 Node v_src = shortestPathTopo.get(src.dpid().value());
383 if (v_src == null) {
384 return null; // Source vertex not found
385 }
386
387 // Get the destination vertex
388 Node v_dest = shortestPathTopo.get(dest.dpid().value());
389 if (v_dest == null) {
390 return null; // Destination vertex not found
391 }
392
393 //
394 // Test whether we are computing a path from/to the same DPID.
395 // If "yes", then just add a single flow entry in the return result.
396 //
397 if (dpid_src.equals(dpid_dest)) {
398 FlowEntry flowEntry = new FlowEntry();
399 flowEntry.setDpid(src.dpid());
400 flowEntry.setInPort(src.port());
401 flowEntry.setOutPort(dest.port());
402 result_data_path.flowEntries().add(flowEntry);
403 return result_data_path;
404 }
405
406 //
407 // Implement the Shortest Path computation by using Breath First Search
408 //
409 Set<Node> visitedSet = new HashSet<Node>();
410 Queue<Node> processingList = new LinkedList<Node>();
411 Map<Node, Node.Link> previousVertexMap = new HashMap<Node, Node.Link>();
412 processingList.add(v_src);
413 visitedSet.add(v_src);
414 Boolean path_found = false;
415 while (! processingList.isEmpty()) {
416 Node nextVertex = processingList.poll();
417 if (v_dest == nextVertex) {
418 path_found = true;
419 break;
420 }
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -0700421 for (Node.Link link : nextVertex.links.values()) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700422 Node child = link.neighbor;
423 if (! visitedSet.contains(child)) {
424 previousVertexMap.put(child, link);
425 visitedSet.add(child);
426 processingList.add(child);
427 }
428 }
429 }
430 if (! path_found)
431 return null; // No path found
432
433 // Collect the path as a list of links
434 List<Node.Link> resultPath = new LinkedList<Node.Link>();
435 Node previousVertex = v_dest;
436 while (! v_src.equals(previousVertex)) {
437 Node.Link currentLink = previousVertexMap.get(previousVertex);
438 resultPath.add(currentLink);
439 previousVertex = currentLink.me;
440 }
441 Collections.reverse(resultPath);
442
443 //
444 // Loop through the result and prepare the return result
445 // as a list of Flow Entries.
446 //
447 Port inPort = new Port(src.port().value());
448 Port outPort;
449 for (Node.Link link: resultPath) {
450 // Setup the outgoing port, and add the Flow Entry
Pavlin Radoslavova1ff1192013-03-29 04:11:32 -0700451 outPort = new Port(link.myPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700452
453 FlowEntry flowEntry = new FlowEntry();
454 flowEntry.setDpid(new Dpid(link.me.nodeId));
455 flowEntry.setInPort(inPort);
456 flowEntry.setOutPort(outPort);
457 result_data_path.flowEntries().add(flowEntry);
458
459 // Setup the next incoming port
460 inPort = new Port(link.neighborPort);
461 }
462 if (resultPath.size() > 0) {
463 // Add the last Flow Entry
464 FlowEntry flowEntry = new FlowEntry();
465 flowEntry.setDpid(new Dpid(dest.dpid().value()));
466 flowEntry.setInPort(inPort);
467 flowEntry.setOutPort(dest.port());
468 result_data_path.flowEntries().add(flowEntry);
469 }
470
471 if (result_data_path.flowEntries().size() > 0)
472 return result_data_path;
473
474 return null;
475 }
476
477 /**
478 * Get the shortest path from a source to a destination.
479 *
480 * @param src the source in the shortest path computation.
481 * @param dest the destination in the shortest path computation.
482 * @return the data path with the computed shortest path if
483 * found, otherwise null.
484 */
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800485 @Override
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800486 public DataPath getShortestPath(SwitchPort src, SwitchPort dest) {
487 DataPath result_data_path = new DataPath();
488
489 // Initialize the source and destination in the data path to return
490 result_data_path.setSrcPort(src);
491 result_data_path.setDstPort(dest);
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800492
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800493 String dpid_src = src.dpid().toString();
494 String dpid_dest = dest.dpid().toString();
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800495
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700496 // Get the source and destination switches
497 ISwitchObject srcSwitch =
Toshio Koide18e47202013-06-13 14:07:13 -0700498 op.searchActiveSwitch(dpid_src);
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700499 ISwitchObject destSwitch =
Toshio Koide18e47202013-06-13 14:07:13 -0700500 op.searchActiveSwitch(dpid_dest);
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700501 if (srcSwitch == null || destSwitch == null) {
502 return null;
503 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800504
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800505 //
506 // Test whether we are computing a path from/to the same DPID.
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800507 // If "yes", then just add a single flow entry in the return result.
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800508 //
509 if (dpid_src.equals(dpid_dest)) {
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800510 FlowEntry flowEntry = new FlowEntry();
511 flowEntry.setDpid(src.dpid());
512 flowEntry.setInPort(src.port());
513 flowEntry.setOutPort(dest.port());
514 result_data_path.flowEntries().add(flowEntry);
Toshio Koide18e47202013-06-13 14:07:13 -0700515 op.commit();
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800516 return result_data_path;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800517 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800518
Pankaj Berde15193092013-03-21 17:30:14 -0700519 Vertex v_src = srcSwitch.asVertex();
520 Vertex v_dest = destSwitch.asVertex();
521
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700522 //
523 // Implement the Shortest Path computation by using Breath First Search
524 //
525 Set<Vertex> visitedSet = new HashSet<Vertex>();
526 Queue<Vertex> processingList = new LinkedList<Vertex>();
527 Map<Vertex, Vertex> previousVertexMap = new HashMap<Vertex, Vertex>();
528
529 processingList.add(v_src);
530 visitedSet.add(v_src);
531 Boolean path_found = false;
532 while (! processingList.isEmpty()) {
533 Vertex nextVertex = processingList.poll();
534 if (v_dest.equals(nextVertex)) {
535 path_found = true;
536 break;
537 }
538 for (Vertex parentPort : nextVertex.getVertices(Direction.OUT, "on")) {
Pavlin Radoslavov65d50b52013-09-05 14:24:59 -0700539 // Ignore inactive ports
540 if (! parentPort.getProperty("state").toString().equals("ACTIVE"))
541 continue;
542
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700543 for (Vertex childPort : parentPort.getVertices(Direction.OUT, "link")) {
Pavlin Radoslavov65d50b52013-09-05 14:24:59 -0700544 // Ignore inactive ports
545 if (! childPort.getProperty("state").toString().equals("ACTIVE"))
546 continue;
547
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700548 for (Vertex child : childPort.getVertices(Direction.IN, "on")) {
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700549 // Ignore inactive switches
550 String state = child.getProperty("state").toString();
551 if (! state.equals(SwitchState.ACTIVE.toString()))
552 continue;
553
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700554 if (! visitedSet.contains(child)) {
555 previousVertexMap.put(parentPort, nextVertex);
556 previousVertexMap.put(childPort, parentPort);
557 previousVertexMap.put(child, childPort);
558 visitedSet.add(child);
559 processingList.add(child);
560 }
561 }
562 }
563 }
564 }
565 if (! path_found)
566 return null; // No path found
567
568 List<Vertex> resultPath = new LinkedList<Vertex>();
569 Vertex previousVertex = v_dest;
570 resultPath.add(v_dest);
571 while (! v_src.equals(previousVertex)) {
572 Vertex currentVertex = previousVertexMap.get(previousVertex);
573 resultPath.add(currentVertex);
574 previousVertex = currentVertex;
575 }
576 Collections.reverse(resultPath);
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800577
Pankaj Berde15193092013-03-21 17:30:14 -0700578
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800579 //
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700580 // Loop through the result and prepare the return result
581 // as a list of Flow Entries.
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800582 //
583 long nodeId = 0;
584 short portId = 0;
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800585 Port inPort = new Port(src.port().value());
586 Port outPort = new Port();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700587 int idx = 0;
588 for (Vertex v: resultPath) {
589 String type = v.getProperty("type").toString();
590 // System.out.println("type: " + type);
591 if (type.equals("port")) {
Yuta HIGUCHI0e293922013-10-09 17:44:54 -0700592 //String number = v.getProperty("number").toString();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700593 // System.out.println("number: " + number);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800594
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700595 Object obj = v.getProperty("number");
596 // String class_str = obj.getClass().toString();
597 if (obj instanceof Short) {
598 portId = (Short)obj;
599 } else if (obj instanceof Integer) {
600 Integer int_nodeId = (Integer)obj;
601 portId = int_nodeId.shortValue();
602 // int int_nodeId = (Integer)obj;
603 // portId = (short)int_nodeId.;
604 }
605 } else if (type.equals("switch")) {
606 String dpid = v.getProperty("dpid").toString();
607 nodeId = HexString.toLong(dpid);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800608
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700609 // System.out.println("dpid: " + dpid);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800610 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700611 idx++;
612 if (idx == 1) {
613 continue;
614 }
615 int mod = idx % 3;
616 if (mod == 0) {
617 // Setup the incoming port
618 inPort = new Port(portId);
619 continue;
620 }
621 if (mod == 2) {
622 // Setup the outgoing port, and add the Flow Entry
623 outPort = new Port(portId);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800624
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800625 FlowEntry flowEntry = new FlowEntry();
626 flowEntry.setDpid(new Dpid(nodeId));
627 flowEntry.setInPort(inPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700628 flowEntry.setOutPort(outPort);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800629 result_data_path.flowEntries().add(flowEntry);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700630 continue;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800631 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800632 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700633 if (idx > 0) {
634 // Add the last Flow Entry
635 FlowEntry flowEntry = new FlowEntry();
636 flowEntry.setDpid(new Dpid(nodeId));
637 flowEntry.setInPort(inPort);
638 flowEntry.setOutPort(dest.port());
639 result_data_path.flowEntries().add(flowEntry);
640 }
641
Toshio Koide18e47202013-06-13 14:07:13 -0700642 op.commit();
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800643 if (result_data_path.flowEntries().size() > 0)
644 return result_data_path;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800645
646 return null;
647 }
648
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700649 /**
650 * Test whether a route exists from a source to a destination.
651 *
652 * @param src the source node for the test.
653 * @param dest the destination node for the test.
654 * @return true if a route exists, otherwise false.
655 */
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800656 @Override
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800657 public Boolean routeExists(SwitchPort src, SwitchPort dest) {
658 DataPath dataPath = getShortestPath(src, dest);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700659 return (dataPath != null);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800660 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800661}