blob: c0a5e57982ff428f66e5de6d3cffc0381e5d0e03 [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 Radoslavova5f167b2013-03-21 11:39:27 -07003import java.util.Collections;
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -08004import java.util.HashMap;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -07005import java.util.HashSet;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -07006import java.util.LinkedList;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -08007import java.util.List;
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -08008import java.util.Map;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -07009import java.util.Queue;
10import java.util.Set;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080011
Pankaj Berde38646d62013-06-21 11:34:04 -070012import net.onrc.onos.graph.GraphDBOperation;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070013import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
14import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoRouteService;
15import net.onrc.onos.ofcontroller.core.ISwitchStorage.SwitchState;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070016import net.onrc.onos.ofcontroller.util.DataPath;
17import net.onrc.onos.ofcontroller.util.Dpid;
18import net.onrc.onos.ofcontroller.util.FlowEntry;
19import net.onrc.onos.ofcontroller.util.Port;
20import net.onrc.onos.ofcontroller.util.SwitchPort;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080021
22import org.openflow.util.HexString;
Pankaj Berde15193092013-03-21 17:30:14 -070023import org.slf4j.Logger;
24import org.slf4j.LoggerFactory;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080025
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070026import com.tinkerpop.blueprints.Direction;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080027import com.tinkerpop.blueprints.Vertex;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080028
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070029
30/**
31 * A class for storing Node and Link information for fast computation
32 * of shortest paths.
33 */
34class Node {
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070035 /**
36 * A class for storing Link information for fast computation of shortest
37 * paths.
38 */
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070039 class Link {
40 public Node me; // The node this link originates from
41 public Node neighbor; // The neighbor node on the other side
42 public short myPort; // Local port number for the link
43 public short neighborPort; // Neighbor port number for the link
44
45 /**
46 * Link constructor.
47 *
48 * @param me the node this link originates from.
49 * @param the neighbor node on the other side of the link.
50 * @param myPort local port number for the link.
51 * @param neighborPort neighrobr port number for the link.
52 */
53 public Link(Node me, Node neighbor, short myPort, short neighborPort) {
54 this.me = me;
55 this.neighbor = neighbor;
56 this.myPort = myPort;
57 this.neighborPort = neighborPort;
58 }
59 };
60
61 public long nodeId; // The node ID
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -070062 public HashMap<Short, Link> links; // The links originating from this node
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070063
64 /**
65 * Node constructor.
66 *
67 * @param nodeId the node ID.
68 */
69 public Node(long nodeId) {
70 this.nodeId = nodeId;
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -070071 links = new HashMap<Short, Link>();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070072 }
73
74 /**
75 * Add a neighbor.
76 *
77 * A new link to the neighbor will be created.
78 *
79 * @param neighbor the neighbor to add.
80 * @param myPort the local port number for the link to the neighbor.
81 * @param neighborPort the neighbor port number for the link.
82 */
83 public void addNeighbor(Node neighbor, short myPort, short neighborPort) {
84 Link link = new Link(this, neighbor, myPort, neighborPort);
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -070085 links.put(myPort, link);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070086 }
87};
88
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070089/**
90 * A class for implementing Topology Route Service.
91 */
Pavlin Radoslavove1b37bc2013-10-16 03:57:06 -070092public class TopologyManager implements ITopoRouteService {
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080093
94 /** The logger. */
Pavlin Radoslavove1b37bc2013-10-16 03:57:06 -070095 private static Logger log = LoggerFactory.getLogger(TopologyManager.class);
Pankaj Berde15193092013-03-21 17:30:14 -070096
Toshio Koide18e47202013-06-13 14:07:13 -070097 protected GraphDBOperation op;
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080098
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070099
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700100 /**
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700101 * Default constructor.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700102 */
Pavlin Radoslavove1b37bc2013-10-16 03:57:06 -0700103 public TopologyManager() {
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800104 }
105
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700106 /**
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700107 * Constructor for given database configuration file.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700108 *
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700109 * @param config the database configuration file to use for
110 * the initialization.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700111 */
Pavlin Radoslavove1b37bc2013-10-16 03:57:06 -0700112 public TopologyManager(String config) {
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700113 this.init(config);
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800114 }
115
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700116 /**
117 * Init the module.
118 *
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700119 * @param config the database configuration file to use for
120 * the initialization.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700121 */
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700122 public void init(String config) {
123 try {
124 op = new GraphDBOperation(config);
125 } catch (Exception e) {
126 log.error(e.getMessage());
127 }
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800128 }
129
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700130 /**
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700131 * Close the service. It will close the corresponding database connection.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700132 */
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700133 public void close() {
134 op.close();
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800135 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800136
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700137 /**
138 * Set the database operation handler.
139 *
140 * @param init_op the database operation handler to use for the
141 * initialization.
142 */
Pavlin Radoslavovcec899a2013-06-27 15:47:50 -0700143 public void setDbOperationHandler(GraphDBOperation init_op) {
144 op = init_op;
145 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800146
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700147 /**
148 * Fetch the Switch and Ports info from the Titan Graph
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000149 * and return it for fast access during the shortest path
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700150 * computation.
151 *
152 * After fetching the state, method @ref getTopoShortestPath()
153 * can be used for fast shortest path computation.
154 *
155 * Note: There is certain cost to fetch the state, hence it should
156 * be used only when there is a large number of shortest path
157 * computations that need to be done on the same topology.
158 * Typically, a single call to @ref prepareShortestPathTopo()
159 * should be followed by a large number of calls to
160 * method @ref getTopoShortestPath().
161 * After the last @ref getTopoShortestPath() call,
162 * method @ref dropShortestPathTopo() should be used to release
163 * the internal state that is not needed anymore:
164 *
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000165 * Map<Long, ?> shortestPathTopo;
166 * shortestPathTopo = prepareShortestPathTopo();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700167 * for (int i = 0; i < 10000; i++) {
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000168 * dataPath = getTopoShortestPath(shortestPathTopo, ...);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700169 * ...
170 * }
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000171 * dropShortestPathTopo(shortestPathTopo);
172 *
173 * @return the Shortest Path info handler stored in a map.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700174 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000175 public Map<Long, ?> prepareShortestPathTopo() {
176 Map<Long, Node> shortestPathTopo = new HashMap<Long, Node>();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700177
178 //
179 // Fetch the relevant info from the Switch and Port vertices
180 // from the Titan Graph.
181 //
Toshio Koide18e47202013-06-13 14:07:13 -0700182 Iterable<ISwitchObject> nodes = op.getActiveSwitches();
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700183 for (ISwitchObject switchObj : nodes) {
184 Vertex nodeVertex = switchObj.asVertex();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700185 //
186 // The Switch info
187 //
188 String nodeDpid = nodeVertex.getProperty("dpid").toString();
189 long nodeId = HexString.toLong(nodeDpid);
190 Node me = shortestPathTopo.get(nodeId);
191 if (me == null) {
192 me = new Node(nodeId);
193 shortestPathTopo.put(nodeId, me);
194 }
195
196 //
197 // The local Port info
198 //
199 for (Vertex myPortVertex : nodeVertex.getVertices(Direction.OUT, "on")) {
Pavlin Radoslavov65d50b52013-09-05 14:24:59 -0700200 // Ignore inactive ports
201 if (! myPortVertex.getProperty("state").toString().equals("ACTIVE"))
202 continue;
203
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700204 short myPort = 0;
205 Object obj = myPortVertex.getProperty("number");
206 if (obj instanceof Short) {
207 myPort = (Short)obj;
208 } else if (obj instanceof Integer) {
209 Integer int_nodeId = (Integer)obj;
210 myPort = int_nodeId.shortValue();
211 }
212
213 //
214 // The neighbor Port info
215 //
216 for (Vertex neighborPortVertex : myPortVertex.getVertices(Direction.OUT, "link")) {
Pavlin Radoslavov65d50b52013-09-05 14:24:59 -0700217 // Ignore inactive ports
218 if (! neighborPortVertex.getProperty("state").toString().equals("ACTIVE"))
219 continue;
220
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700221 short neighborPort = 0;
222 obj = neighborPortVertex.getProperty("number");
223 if (obj instanceof Short) {
224 neighborPort = (Short)obj;
225 } else if (obj instanceof Integer) {
226 Integer int_nodeId = (Integer)obj;
227 neighborPort = int_nodeId.shortValue();
228 }
229 //
230 // The neighbor Switch info
231 //
232 for (Vertex neighborVertex : neighborPortVertex.getVertices(Direction.IN, "on")) {
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700233 // Ignore inactive switches
234 String state = neighborVertex.getProperty("state").toString();
235 if (! state.equals(SwitchState.ACTIVE.toString()))
236 continue;
237
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700238 String neighborDpid = neighborVertex.getProperty("dpid").toString();
239 long neighborId = HexString.toLong(neighborDpid);
240 Node neighbor = shortestPathTopo.get(neighborId);
241 if (neighbor == null) {
242 neighbor = new Node(neighborId);
243 shortestPathTopo.put(neighborId, neighbor);
244 }
245 me.addNeighbor(neighbor, myPort, neighborPort);
246 }
247 }
248 }
249 }
Toshio Koide18e47202013-06-13 14:07:13 -0700250 op.commit();
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000251
252 return shortestPathTopo;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700253 }
254
255 /**
256 * Release the state that was populated by
257 * method @ref prepareShortestPathTopo().
258 *
259 * See the documentation for method @ref prepareShortestPathTopo()
260 * for additional information and usage.
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000261 *
Pavlin Radoslavoved13a242013-06-20 17:37:20 -0700262 * @param shortestPathTopo the Shortest Path info handler to release.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700263 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000264 public void dropShortestPathTopo(Map<Long, ?> shortestPathTopo) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700265 shortestPathTopo = null;
266 }
267
268 /**
269 * Get the shortest path from a source to a destination by
270 * using the pre-populated local topology state prepared
271 * by method @ref prepareShortestPathTopo().
272 *
273 * See the documentation for method @ref prepareShortestPathTopo()
274 * for additional information and usage.
275 *
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000276 * @param shortestPathTopoHandler the Shortest Path info handler
277 * to use.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700278 * @param src the source in the shortest path computation.
279 * @param dest the destination in the shortest path computation.
280 * @return the data path with the computed shortest path if
281 * found, otherwise null.
282 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000283 public DataPath getTopoShortestPath(Map<Long, ?> shortestPathTopoHandler,
284 SwitchPort src, SwitchPort dest) {
285 @SuppressWarnings("unchecked")
286 Map<Long, Node> shortestPathTopo = (Map)shortestPathTopoHandler;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700287 DataPath result_data_path = new DataPath();
288
289 // Initialize the source and destination in the data path to return
290 result_data_path.setSrcPort(src);
291 result_data_path.setDstPort(dest);
292
293 String dpid_src = src.dpid().toString();
294 String dpid_dest = dest.dpid().toString();
295
296 // Get the source vertex
297 Node v_src = shortestPathTopo.get(src.dpid().value());
298 if (v_src == null) {
299 return null; // Source vertex not found
300 }
301
302 // Get the destination vertex
303 Node v_dest = shortestPathTopo.get(dest.dpid().value());
304 if (v_dest == null) {
305 return null; // Destination vertex not found
306 }
307
308 //
309 // Test whether we are computing a path from/to the same DPID.
310 // If "yes", then just add a single flow entry in the return result.
311 //
312 if (dpid_src.equals(dpid_dest)) {
313 FlowEntry flowEntry = new FlowEntry();
314 flowEntry.setDpid(src.dpid());
315 flowEntry.setInPort(src.port());
316 flowEntry.setOutPort(dest.port());
317 result_data_path.flowEntries().add(flowEntry);
318 return result_data_path;
319 }
320
321 //
322 // Implement the Shortest Path computation by using Breath First Search
323 //
324 Set<Node> visitedSet = new HashSet<Node>();
325 Queue<Node> processingList = new LinkedList<Node>();
326 Map<Node, Node.Link> previousVertexMap = new HashMap<Node, Node.Link>();
327 processingList.add(v_src);
328 visitedSet.add(v_src);
329 Boolean path_found = false;
330 while (! processingList.isEmpty()) {
331 Node nextVertex = processingList.poll();
332 if (v_dest == nextVertex) {
333 path_found = true;
334 break;
335 }
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -0700336 for (Node.Link link : nextVertex.links.values()) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700337 Node child = link.neighbor;
338 if (! visitedSet.contains(child)) {
339 previousVertexMap.put(child, link);
340 visitedSet.add(child);
341 processingList.add(child);
342 }
343 }
344 }
345 if (! path_found)
346 return null; // No path found
347
348 // Collect the path as a list of links
349 List<Node.Link> resultPath = new LinkedList<Node.Link>();
350 Node previousVertex = v_dest;
351 while (! v_src.equals(previousVertex)) {
352 Node.Link currentLink = previousVertexMap.get(previousVertex);
353 resultPath.add(currentLink);
354 previousVertex = currentLink.me;
355 }
356 Collections.reverse(resultPath);
357
358 //
359 // Loop through the result and prepare the return result
360 // as a list of Flow Entries.
361 //
362 Port inPort = new Port(src.port().value());
363 Port outPort;
364 for (Node.Link link: resultPath) {
365 // Setup the outgoing port, and add the Flow Entry
Pavlin Radoslavova1ff1192013-03-29 04:11:32 -0700366 outPort = new Port(link.myPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700367
368 FlowEntry flowEntry = new FlowEntry();
369 flowEntry.setDpid(new Dpid(link.me.nodeId));
370 flowEntry.setInPort(inPort);
371 flowEntry.setOutPort(outPort);
372 result_data_path.flowEntries().add(flowEntry);
373
374 // Setup the next incoming port
375 inPort = new Port(link.neighborPort);
376 }
377 if (resultPath.size() > 0) {
378 // Add the last Flow Entry
379 FlowEntry flowEntry = new FlowEntry();
380 flowEntry.setDpid(new Dpid(dest.dpid().value()));
381 flowEntry.setInPort(inPort);
382 flowEntry.setOutPort(dest.port());
383 result_data_path.flowEntries().add(flowEntry);
384 }
385
386 if (result_data_path.flowEntries().size() > 0)
387 return result_data_path;
388
389 return null;
390 }
391
392 /**
393 * Get the shortest path from a source to a destination.
394 *
395 * @param src the source in the shortest path computation.
396 * @param dest the destination in the shortest path computation.
397 * @return the data path with the computed shortest path if
398 * found, otherwise null.
399 */
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800400 @Override
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800401 public DataPath getShortestPath(SwitchPort src, SwitchPort dest) {
402 DataPath result_data_path = new DataPath();
403
404 // Initialize the source and destination in the data path to return
405 result_data_path.setSrcPort(src);
406 result_data_path.setDstPort(dest);
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800407
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800408 String dpid_src = src.dpid().toString();
409 String dpid_dest = dest.dpid().toString();
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800410
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700411 // Get the source and destination switches
412 ISwitchObject srcSwitch =
Toshio Koide18e47202013-06-13 14:07:13 -0700413 op.searchActiveSwitch(dpid_src);
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700414 ISwitchObject destSwitch =
Toshio Koide18e47202013-06-13 14:07:13 -0700415 op.searchActiveSwitch(dpid_dest);
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700416 if (srcSwitch == null || destSwitch == null) {
417 return null;
418 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800419
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800420 //
421 // Test whether we are computing a path from/to the same DPID.
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800422 // If "yes", then just add a single flow entry in the return result.
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800423 //
424 if (dpid_src.equals(dpid_dest)) {
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800425 FlowEntry flowEntry = new FlowEntry();
426 flowEntry.setDpid(src.dpid());
427 flowEntry.setInPort(src.port());
428 flowEntry.setOutPort(dest.port());
429 result_data_path.flowEntries().add(flowEntry);
Toshio Koide18e47202013-06-13 14:07:13 -0700430 op.commit();
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800431 return result_data_path;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800432 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800433
Pankaj Berde15193092013-03-21 17:30:14 -0700434 Vertex v_src = srcSwitch.asVertex();
435 Vertex v_dest = destSwitch.asVertex();
436
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700437 //
438 // Implement the Shortest Path computation by using Breath First Search
439 //
440 Set<Vertex> visitedSet = new HashSet<Vertex>();
441 Queue<Vertex> processingList = new LinkedList<Vertex>();
442 Map<Vertex, Vertex> previousVertexMap = new HashMap<Vertex, Vertex>();
443
444 processingList.add(v_src);
445 visitedSet.add(v_src);
446 Boolean path_found = false;
447 while (! processingList.isEmpty()) {
448 Vertex nextVertex = processingList.poll();
449 if (v_dest.equals(nextVertex)) {
450 path_found = true;
451 break;
452 }
453 for (Vertex parentPort : nextVertex.getVertices(Direction.OUT, "on")) {
Pavlin Radoslavov65d50b52013-09-05 14:24:59 -0700454 // Ignore inactive ports
455 if (! parentPort.getProperty("state").toString().equals("ACTIVE"))
456 continue;
457
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700458 for (Vertex childPort : parentPort.getVertices(Direction.OUT, "link")) {
Pavlin Radoslavov65d50b52013-09-05 14:24:59 -0700459 // Ignore inactive ports
460 if (! childPort.getProperty("state").toString().equals("ACTIVE"))
461 continue;
462
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700463 for (Vertex child : childPort.getVertices(Direction.IN, "on")) {
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700464 // Ignore inactive switches
465 String state = child.getProperty("state").toString();
466 if (! state.equals(SwitchState.ACTIVE.toString()))
467 continue;
468
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700469 if (! visitedSet.contains(child)) {
470 previousVertexMap.put(parentPort, nextVertex);
471 previousVertexMap.put(childPort, parentPort);
472 previousVertexMap.put(child, childPort);
473 visitedSet.add(child);
474 processingList.add(child);
475 }
476 }
477 }
478 }
479 }
480 if (! path_found)
481 return null; // No path found
482
483 List<Vertex> resultPath = new LinkedList<Vertex>();
484 Vertex previousVertex = v_dest;
485 resultPath.add(v_dest);
486 while (! v_src.equals(previousVertex)) {
487 Vertex currentVertex = previousVertexMap.get(previousVertex);
488 resultPath.add(currentVertex);
489 previousVertex = currentVertex;
490 }
491 Collections.reverse(resultPath);
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800492
Pankaj Berde15193092013-03-21 17:30:14 -0700493
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800494 //
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700495 // Loop through the result and prepare the return result
496 // as a list of Flow Entries.
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800497 //
498 long nodeId = 0;
499 short portId = 0;
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800500 Port inPort = new Port(src.port().value());
501 Port outPort = new Port();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700502 int idx = 0;
503 for (Vertex v: resultPath) {
504 String type = v.getProperty("type").toString();
505 // System.out.println("type: " + type);
506 if (type.equals("port")) {
507 String number = v.getProperty("number").toString();
508 // System.out.println("number: " + number);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800509
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700510 Object obj = v.getProperty("number");
511 // String class_str = obj.getClass().toString();
512 if (obj instanceof Short) {
513 portId = (Short)obj;
514 } else if (obj instanceof Integer) {
515 Integer int_nodeId = (Integer)obj;
516 portId = int_nodeId.shortValue();
517 // int int_nodeId = (Integer)obj;
518 // portId = (short)int_nodeId.;
519 }
520 } else if (type.equals("switch")) {
521 String dpid = v.getProperty("dpid").toString();
522 nodeId = HexString.toLong(dpid);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800523
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700524 // System.out.println("dpid: " + dpid);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800525 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700526 idx++;
527 if (idx == 1) {
528 continue;
529 }
530 int mod = idx % 3;
531 if (mod == 0) {
532 // Setup the incoming port
533 inPort = new Port(portId);
534 continue;
535 }
536 if (mod == 2) {
537 // Setup the outgoing port, and add the Flow Entry
538 outPort = new Port(portId);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800539
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800540 FlowEntry flowEntry = new FlowEntry();
541 flowEntry.setDpid(new Dpid(nodeId));
542 flowEntry.setInPort(inPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700543 flowEntry.setOutPort(outPort);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800544 result_data_path.flowEntries().add(flowEntry);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700545 continue;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800546 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800547 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700548 if (idx > 0) {
549 // Add the last Flow Entry
550 FlowEntry flowEntry = new FlowEntry();
551 flowEntry.setDpid(new Dpid(nodeId));
552 flowEntry.setInPort(inPort);
553 flowEntry.setOutPort(dest.port());
554 result_data_path.flowEntries().add(flowEntry);
555 }
556
Toshio Koide18e47202013-06-13 14:07:13 -0700557 op.commit();
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800558 if (result_data_path.flowEntries().size() > 0)
559 return result_data_path;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800560
561 return null;
562 }
563
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700564 /**
565 * Test whether a route exists from a source to a destination.
566 *
567 * @param src the source node for the test.
568 * @param dest the destination node for the test.
569 * @return true if a route exists, otherwise false.
570 */
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800571 @Override
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800572 public Boolean routeExists(SwitchPort src, SwitchPort dest) {
573 DataPath dataPath = getShortestPath(src, dest);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700574 return (dataPath != null);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800575 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800576}