blob: 21381d9a11bbf9bd7af28f7ff03e49d279c98025 [file] [log] [blame]
HIGUCHI Yuta4e64f312013-06-12 14:40:39 -07001package net.onrc.onos.ofcontroller.routing;
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 Radoslavovddd01ba2013-07-03 15:40:44 -070092public class TopoRouteService implements ITopoRouteService {
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080093
94 /** The logger. */
Pavlin Radoslavov19343432013-03-06 10:43:18 -080095 private static Logger log =
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080096 LoggerFactory.getLogger(TopoRouteService.class);
Pankaj Berde15193092013-03-21 17:30:14 -070097
Toshio Koide18e47202013-06-13 14:07:13 -070098 protected GraphDBOperation op;
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080099
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700100
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700101 /**
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700102 * Default constructor.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700103 */
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700104 public TopoRouteService() {
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800105 }
106
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700107 /**
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700108 * Constructor for given database configuration file.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700109 *
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700110 * @param config the database configuration file to use for
111 * the initialization.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700112 */
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700113 public TopoRouteService(String config) {
114 this.init(config);
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800115 }
116
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700117 /**
118 * Init the module.
119 *
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700120 * @param config the database configuration file to use for
121 * the initialization.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700122 */
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700123 public void init(String config) {
124 try {
125 op = new GraphDBOperation(config);
126 } catch (Exception e) {
127 log.error(e.getMessage());
128 }
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800129 }
130
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700131 /**
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700132 * Close the service. It will close the corresponding database connection.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700133 */
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700134 public void close() {
135 op.close();
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800136 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800137
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700138 /**
139 * Set the database operation handler.
140 *
141 * @param init_op the database operation handler to use for the
142 * initialization.
143 */
Pavlin Radoslavovcec899a2013-06-27 15:47:50 -0700144 public void setDbOperationHandler(GraphDBOperation init_op) {
145 op = init_op;
146 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800147
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700148 /**
149 * Fetch the Switch and Ports info from the Titan Graph
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000150 * and return it for fast access during the shortest path
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700151 * computation.
152 *
153 * After fetching the state, method @ref getTopoShortestPath()
154 * can be used for fast shortest path computation.
155 *
156 * Note: There is certain cost to fetch the state, hence it should
157 * be used only when there is a large number of shortest path
158 * computations that need to be done on the same topology.
159 * Typically, a single call to @ref prepareShortestPathTopo()
160 * should be followed by a large number of calls to
161 * method @ref getTopoShortestPath().
162 * After the last @ref getTopoShortestPath() call,
163 * method @ref dropShortestPathTopo() should be used to release
164 * the internal state that is not needed anymore:
165 *
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000166 * Map<Long, ?> shortestPathTopo;
167 * shortestPathTopo = prepareShortestPathTopo();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700168 * for (int i = 0; i < 10000; i++) {
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000169 * dataPath = getTopoShortestPath(shortestPathTopo, ...);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700170 * ...
171 * }
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000172 * dropShortestPathTopo(shortestPathTopo);
173 *
174 * @return the Shortest Path info handler stored in a map.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700175 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000176 public Map<Long, ?> prepareShortestPathTopo() {
177 Map<Long, Node> shortestPathTopo = new HashMap<Long, Node>();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700178
179 //
180 // Fetch the relevant info from the Switch and Port vertices
181 // from the Titan Graph.
182 //
Toshio Koide18e47202013-06-13 14:07:13 -0700183 Iterable<ISwitchObject> nodes = op.getActiveSwitches();
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700184 for (ISwitchObject switchObj : nodes) {
185 Vertex nodeVertex = switchObj.asVertex();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700186 //
187 // The Switch info
188 //
189 String nodeDpid = nodeVertex.getProperty("dpid").toString();
190 long nodeId = HexString.toLong(nodeDpid);
191 Node me = shortestPathTopo.get(nodeId);
192 if (me == null) {
193 me = new Node(nodeId);
194 shortestPathTopo.put(nodeId, me);
195 }
196
197 //
198 // The local Port info
199 //
200 for (Vertex myPortVertex : nodeVertex.getVertices(Direction.OUT, "on")) {
Pavlin Radoslavov65d50b52013-09-05 14:24:59 -0700201 // Ignore inactive ports
202 if (! myPortVertex.getProperty("state").toString().equals("ACTIVE"))
203 continue;
204
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700205 short myPort = 0;
206 Object obj = myPortVertex.getProperty("number");
207 if (obj instanceof Short) {
208 myPort = (Short)obj;
209 } else if (obj instanceof Integer) {
210 Integer int_nodeId = (Integer)obj;
211 myPort = int_nodeId.shortValue();
212 }
213
214 //
215 // The neighbor Port info
216 //
217 for (Vertex neighborPortVertex : myPortVertex.getVertices(Direction.OUT, "link")) {
Pavlin Radoslavov65d50b52013-09-05 14:24:59 -0700218 // Ignore inactive ports
219 if (! neighborPortVertex.getProperty("state").toString().equals("ACTIVE"))
220 continue;
221
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700222 short neighborPort = 0;
223 obj = neighborPortVertex.getProperty("number");
224 if (obj instanceof Short) {
225 neighborPort = (Short)obj;
226 } else if (obj instanceof Integer) {
227 Integer int_nodeId = (Integer)obj;
228 neighborPort = int_nodeId.shortValue();
229 }
230 //
231 // The neighbor Switch info
232 //
233 for (Vertex neighborVertex : neighborPortVertex.getVertices(Direction.IN, "on")) {
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700234 // Ignore inactive switches
235 String state = neighborVertex.getProperty("state").toString();
236 if (! state.equals(SwitchState.ACTIVE.toString()))
237 continue;
238
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700239 String neighborDpid = neighborVertex.getProperty("dpid").toString();
240 long neighborId = HexString.toLong(neighborDpid);
241 Node neighbor = shortestPathTopo.get(neighborId);
242 if (neighbor == null) {
243 neighbor = new Node(neighborId);
244 shortestPathTopo.put(neighborId, neighbor);
245 }
246 me.addNeighbor(neighbor, myPort, neighborPort);
247 }
248 }
249 }
250 }
Toshio Koide18e47202013-06-13 14:07:13 -0700251 op.commit();
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000252
253 return shortestPathTopo;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700254 }
255
256 /**
257 * Release the state that was populated by
258 * method @ref prepareShortestPathTopo().
259 *
260 * See the documentation for method @ref prepareShortestPathTopo()
261 * for additional information and usage.
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000262 *
Pavlin Radoslavoved13a242013-06-20 17:37:20 -0700263 * @param shortestPathTopo the Shortest Path info handler to release.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700264 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000265 public void dropShortestPathTopo(Map<Long, ?> shortestPathTopo) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700266 shortestPathTopo = null;
267 }
268
269 /**
270 * Get the shortest path from a source to a destination by
271 * using the pre-populated local topology state prepared
272 * by method @ref prepareShortestPathTopo().
273 *
274 * See the documentation for method @ref prepareShortestPathTopo()
275 * for additional information and usage.
276 *
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000277 * @param shortestPathTopoHandler the Shortest Path info handler
278 * to use.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700279 * @param src the source in the shortest path computation.
280 * @param dest the destination in the shortest path computation.
281 * @return the data path with the computed shortest path if
282 * found, otherwise null.
283 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000284 public DataPath getTopoShortestPath(Map<Long, ?> shortestPathTopoHandler,
285 SwitchPort src, SwitchPort dest) {
286 @SuppressWarnings("unchecked")
287 Map<Long, Node> shortestPathTopo = (Map)shortestPathTopoHandler;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700288 DataPath result_data_path = new DataPath();
289
290 // Initialize the source and destination in the data path to return
291 result_data_path.setSrcPort(src);
292 result_data_path.setDstPort(dest);
293
294 String dpid_src = src.dpid().toString();
295 String dpid_dest = dest.dpid().toString();
296
297 // Get the source vertex
298 Node v_src = shortestPathTopo.get(src.dpid().value());
299 if (v_src == null) {
300 return null; // Source vertex not found
301 }
302
303 // Get the destination vertex
304 Node v_dest = shortestPathTopo.get(dest.dpid().value());
305 if (v_dest == null) {
306 return null; // Destination vertex not found
307 }
308
309 //
310 // Test whether we are computing a path from/to the same DPID.
311 // If "yes", then just add a single flow entry in the return result.
312 //
313 if (dpid_src.equals(dpid_dest)) {
314 FlowEntry flowEntry = new FlowEntry();
315 flowEntry.setDpid(src.dpid());
316 flowEntry.setInPort(src.port());
317 flowEntry.setOutPort(dest.port());
318 result_data_path.flowEntries().add(flowEntry);
319 return result_data_path;
320 }
321
322 //
323 // Implement the Shortest Path computation by using Breath First Search
324 //
325 Set<Node> visitedSet = new HashSet<Node>();
326 Queue<Node> processingList = new LinkedList<Node>();
327 Map<Node, Node.Link> previousVertexMap = new HashMap<Node, Node.Link>();
328 processingList.add(v_src);
329 visitedSet.add(v_src);
330 Boolean path_found = false;
331 while (! processingList.isEmpty()) {
332 Node nextVertex = processingList.poll();
333 if (v_dest == nextVertex) {
334 path_found = true;
335 break;
336 }
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -0700337 for (Node.Link link : nextVertex.links.values()) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700338 Node child = link.neighbor;
339 if (! visitedSet.contains(child)) {
340 previousVertexMap.put(child, link);
341 visitedSet.add(child);
342 processingList.add(child);
343 }
344 }
345 }
346 if (! path_found)
347 return null; // No path found
348
349 // Collect the path as a list of links
350 List<Node.Link> resultPath = new LinkedList<Node.Link>();
351 Node previousVertex = v_dest;
352 while (! v_src.equals(previousVertex)) {
353 Node.Link currentLink = previousVertexMap.get(previousVertex);
354 resultPath.add(currentLink);
355 previousVertex = currentLink.me;
356 }
357 Collections.reverse(resultPath);
358
359 //
360 // Loop through the result and prepare the return result
361 // as a list of Flow Entries.
362 //
363 Port inPort = new Port(src.port().value());
364 Port outPort;
365 for (Node.Link link: resultPath) {
366 // Setup the outgoing port, and add the Flow Entry
Pavlin Radoslavova1ff1192013-03-29 04:11:32 -0700367 outPort = new Port(link.myPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700368
369 FlowEntry flowEntry = new FlowEntry();
370 flowEntry.setDpid(new Dpid(link.me.nodeId));
371 flowEntry.setInPort(inPort);
372 flowEntry.setOutPort(outPort);
373 result_data_path.flowEntries().add(flowEntry);
374
375 // Setup the next incoming port
376 inPort = new Port(link.neighborPort);
377 }
378 if (resultPath.size() > 0) {
379 // Add the last Flow Entry
380 FlowEntry flowEntry = new FlowEntry();
381 flowEntry.setDpid(new Dpid(dest.dpid().value()));
382 flowEntry.setInPort(inPort);
383 flowEntry.setOutPort(dest.port());
384 result_data_path.flowEntries().add(flowEntry);
385 }
386
387 if (result_data_path.flowEntries().size() > 0)
388 return result_data_path;
389
390 return null;
391 }
392
393 /**
394 * Get the shortest path from a source to a destination.
395 *
396 * @param src the source in the shortest path computation.
397 * @param dest the destination in the shortest path computation.
398 * @return the data path with the computed shortest path if
399 * found, otherwise null.
400 */
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800401 @Override
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800402 public DataPath getShortestPath(SwitchPort src, SwitchPort dest) {
403 DataPath result_data_path = new DataPath();
404
405 // Initialize the source and destination in the data path to return
406 result_data_path.setSrcPort(src);
407 result_data_path.setDstPort(dest);
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800408
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800409 String dpid_src = src.dpid().toString();
410 String dpid_dest = dest.dpid().toString();
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800411
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700412 // Get the source and destination switches
413 ISwitchObject srcSwitch =
Toshio Koide18e47202013-06-13 14:07:13 -0700414 op.searchActiveSwitch(dpid_src);
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700415 ISwitchObject destSwitch =
Toshio Koide18e47202013-06-13 14:07:13 -0700416 op.searchActiveSwitch(dpid_dest);
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700417 if (srcSwitch == null || destSwitch == null) {
418 return null;
419 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800420
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800421 //
422 // Test whether we are computing a path from/to the same DPID.
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800423 // If "yes", then just add a single flow entry in the return result.
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800424 //
425 if (dpid_src.equals(dpid_dest)) {
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800426 FlowEntry flowEntry = new FlowEntry();
427 flowEntry.setDpid(src.dpid());
428 flowEntry.setInPort(src.port());
429 flowEntry.setOutPort(dest.port());
430 result_data_path.flowEntries().add(flowEntry);
Toshio Koide18e47202013-06-13 14:07:13 -0700431 op.commit();
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800432 return result_data_path;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800433 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800434
Pankaj Berde15193092013-03-21 17:30:14 -0700435 Vertex v_src = srcSwitch.asVertex();
436 Vertex v_dest = destSwitch.asVertex();
437
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700438 //
439 // Implement the Shortest Path computation by using Breath First Search
440 //
441 Set<Vertex> visitedSet = new HashSet<Vertex>();
442 Queue<Vertex> processingList = new LinkedList<Vertex>();
443 Map<Vertex, Vertex> previousVertexMap = new HashMap<Vertex, Vertex>();
444
445 processingList.add(v_src);
446 visitedSet.add(v_src);
447 Boolean path_found = false;
448 while (! processingList.isEmpty()) {
449 Vertex nextVertex = processingList.poll();
450 if (v_dest.equals(nextVertex)) {
451 path_found = true;
452 break;
453 }
454 for (Vertex parentPort : nextVertex.getVertices(Direction.OUT, "on")) {
Pavlin Radoslavov65d50b52013-09-05 14:24:59 -0700455 // Ignore inactive ports
456 if (! parentPort.getProperty("state").toString().equals("ACTIVE"))
457 continue;
458
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700459 for (Vertex childPort : parentPort.getVertices(Direction.OUT, "link")) {
Pavlin Radoslavov65d50b52013-09-05 14:24:59 -0700460 // Ignore inactive ports
461 if (! childPort.getProperty("state").toString().equals("ACTIVE"))
462 continue;
463
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700464 for (Vertex child : childPort.getVertices(Direction.IN, "on")) {
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700465 // Ignore inactive switches
466 String state = child.getProperty("state").toString();
467 if (! state.equals(SwitchState.ACTIVE.toString()))
468 continue;
469
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700470 if (! visitedSet.contains(child)) {
471 previousVertexMap.put(parentPort, nextVertex);
472 previousVertexMap.put(childPort, parentPort);
473 previousVertexMap.put(child, childPort);
474 visitedSet.add(child);
475 processingList.add(child);
476 }
477 }
478 }
479 }
480 }
481 if (! path_found)
482 return null; // No path found
483
484 List<Vertex> resultPath = new LinkedList<Vertex>();
485 Vertex previousVertex = v_dest;
486 resultPath.add(v_dest);
487 while (! v_src.equals(previousVertex)) {
488 Vertex currentVertex = previousVertexMap.get(previousVertex);
489 resultPath.add(currentVertex);
490 previousVertex = currentVertex;
491 }
492 Collections.reverse(resultPath);
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800493
Pankaj Berde15193092013-03-21 17:30:14 -0700494
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800495 //
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700496 // Loop through the result and prepare the return result
497 // as a list of Flow Entries.
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800498 //
499 long nodeId = 0;
500 short portId = 0;
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800501 Port inPort = new Port(src.port().value());
502 Port outPort = new Port();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700503 int idx = 0;
504 for (Vertex v: resultPath) {
505 String type = v.getProperty("type").toString();
506 // System.out.println("type: " + type);
507 if (type.equals("port")) {
508 String number = v.getProperty("number").toString();
509 // System.out.println("number: " + number);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800510
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700511 Object obj = v.getProperty("number");
512 // String class_str = obj.getClass().toString();
513 if (obj instanceof Short) {
514 portId = (Short)obj;
515 } else if (obj instanceof Integer) {
516 Integer int_nodeId = (Integer)obj;
517 portId = int_nodeId.shortValue();
518 // int int_nodeId = (Integer)obj;
519 // portId = (short)int_nodeId.;
520 }
521 } else if (type.equals("switch")) {
522 String dpid = v.getProperty("dpid").toString();
523 nodeId = HexString.toLong(dpid);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800524
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700525 // System.out.println("dpid: " + dpid);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800526 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700527 idx++;
528 if (idx == 1) {
529 continue;
530 }
531 int mod = idx % 3;
532 if (mod == 0) {
533 // Setup the incoming port
534 inPort = new Port(portId);
535 continue;
536 }
537 if (mod == 2) {
538 // Setup the outgoing port, and add the Flow Entry
539 outPort = new Port(portId);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800540
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800541 FlowEntry flowEntry = new FlowEntry();
542 flowEntry.setDpid(new Dpid(nodeId));
543 flowEntry.setInPort(inPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700544 flowEntry.setOutPort(outPort);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800545 result_data_path.flowEntries().add(flowEntry);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700546 continue;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800547 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800548 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700549 if (idx > 0) {
550 // Add the last Flow Entry
551 FlowEntry flowEntry = new FlowEntry();
552 flowEntry.setDpid(new Dpid(nodeId));
553 flowEntry.setInPort(inPort);
554 flowEntry.setOutPort(dest.port());
555 result_data_path.flowEntries().add(flowEntry);
556 }
557
Toshio Koide18e47202013-06-13 14:07:13 -0700558 op.commit();
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800559 if (result_data_path.flowEntries().size() > 0)
560 return result_data_path;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800561
562 return null;
563 }
564
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700565 /**
566 * Test whether a route exists from a source to a destination.
567 *
568 * @param src the source node for the test.
569 * @param dest the destination node for the test.
570 * @return true if a route exists, otherwise false.
571 */
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800572 @Override
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800573 public Boolean routeExists(SwitchPort src, SwitchPort dest) {
574 DataPath dataPath = getShortestPath(src, dest);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700575 return (dataPath != null);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800576 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800577}