blob: 59e76cadc39d8e42b713329f963b8b0995ee8f19 [file] [log] [blame]
HIGUCHI Yuta4e64f312013-06-12 14:40:39 -07001package net.onrc.onos.ofcontroller.routing;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -08002
3import java.util.ArrayList;
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -08004import 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
Pankaj Berde38646d62013-06-21 11:34:04 -070014import net.onrc.onos.graph.GraphDBOperation;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070015import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
16import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoRouteService;
17import net.onrc.onos.ofcontroller.core.ISwitchStorage.SwitchState;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070018import net.onrc.onos.ofcontroller.util.DataPath;
19import net.onrc.onos.ofcontroller.util.Dpid;
20import net.onrc.onos.ofcontroller.util.FlowEntry;
21import net.onrc.onos.ofcontroller.util.Port;
22import net.onrc.onos.ofcontroller.util.SwitchPort;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080023
24import org.openflow.util.HexString;
Pankaj Berde15193092013-03-21 17:30:14 -070025import org.slf4j.Logger;
26import org.slf4j.LoggerFactory;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080027
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070028import com.tinkerpop.blueprints.Direction;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080029import com.tinkerpop.blueprints.Vertex;
Pavlin Radoslavovbfae5e02013-03-19 23:06:36 -070030import com.tinkerpop.pipes.PipeFunction;
31import com.tinkerpop.pipes.branch.LoopPipe.LoopBundle;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080032
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070033
34/**
35 * A class for storing Node and Link information for fast computation
36 * of shortest paths.
37 */
38class Node {
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070039 /**
40 * A class for storing Link information for fast computation of shortest
41 * paths.
42 */
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070043 class Link {
44 public Node me; // The node this link originates from
45 public Node neighbor; // The neighbor node on the other side
46 public short myPort; // Local port number for the link
47 public short neighborPort; // Neighbor port number for the link
48
49 /**
50 * Link constructor.
51 *
52 * @param me the node this link originates from.
53 * @param the neighbor node on the other side of the link.
54 * @param myPort local port number for the link.
55 * @param neighborPort neighrobr port number for the link.
56 */
57 public Link(Node me, Node neighbor, short myPort, short neighborPort) {
58 this.me = me;
59 this.neighbor = neighbor;
60 this.myPort = myPort;
61 this.neighborPort = neighborPort;
62 }
63 };
64
65 public long nodeId; // The node ID
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -070066 public HashMap<Short, Link> links; // The links originating from this node
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070067
68 /**
69 * Node constructor.
70 *
71 * @param nodeId the node ID.
72 */
73 public Node(long nodeId) {
74 this.nodeId = nodeId;
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -070075 links = new HashMap<Short, Link>();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070076 }
77
78 /**
79 * Add a neighbor.
80 *
81 * A new link to the neighbor will be created.
82 *
83 * @param neighbor the neighbor to add.
84 * @param myPort the local port number for the link to the neighbor.
85 * @param neighborPort the neighbor port number for the link.
86 */
87 public void addNeighbor(Node neighbor, short myPort, short neighborPort) {
88 Link link = new Link(this, neighbor, myPort, neighborPort);
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -070089 links.put(myPort, link);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070090 }
91};
92
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070093/**
94 * A class for implementing Topology Route Service.
95 */
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070096public class TopoRouteService implements ITopoRouteService {
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080097
98 /** The logger. */
Pavlin Radoslavov19343432013-03-06 10:43:18 -080099 private static Logger log =
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800100 LoggerFactory.getLogger(TopoRouteService.class);
Pankaj Berde15193092013-03-21 17:30:14 -0700101
Toshio Koide18e47202013-06-13 14:07:13 -0700102 protected GraphDBOperation op;
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800103
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700104
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700105 /**
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700106 * Default constructor.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700107 */
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700108 public TopoRouteService() {
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800109 }
110
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700111 /**
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700112 * Constructor for given database configuration file.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700113 *
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700114 * @param config the database configuration file to use for
115 * the initialization.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700116 */
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700117 public TopoRouteService(String config) {
118 this.init(config);
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800119 }
120
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700121 /**
122 * Init the module.
123 *
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700124 * @param config the database configuration file to use for
125 * the initialization.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700126 */
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700127 public void init(String config) {
128 try {
129 op = new GraphDBOperation(config);
130 } catch (Exception e) {
131 log.error(e.getMessage());
132 }
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800133 }
134
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700135 /**
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700136 * Close the service. It will close the corresponding database connection.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700137 */
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700138 public void close() {
139 op.close();
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800140 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800141
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700142 /**
143 * Set the database operation handler.
144 *
145 * @param init_op the database operation handler to use for the
146 * initialization.
147 */
Pavlin Radoslavovcec899a2013-06-27 15:47:50 -0700148 public void setDbOperationHandler(GraphDBOperation init_op) {
149 op = init_op;
150 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800151
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700152 /**
153 * Fetch the Switch and Ports info from the Titan Graph
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000154 * and return it for fast access during the shortest path
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700155 * computation.
156 *
157 * After fetching the state, method @ref getTopoShortestPath()
158 * can be used for fast shortest path computation.
159 *
160 * Note: There is certain cost to fetch the state, hence it should
161 * be used only when there is a large number of shortest path
162 * computations that need to be done on the same topology.
163 * Typically, a single call to @ref prepareShortestPathTopo()
164 * should be followed by a large number of calls to
165 * method @ref getTopoShortestPath().
166 * After the last @ref getTopoShortestPath() call,
167 * method @ref dropShortestPathTopo() should be used to release
168 * the internal state that is not needed anymore:
169 *
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000170 * Map<Long, ?> shortestPathTopo;
171 * shortestPathTopo = prepareShortestPathTopo();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700172 * for (int i = 0; i < 10000; i++) {
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000173 * dataPath = getTopoShortestPath(shortestPathTopo, ...);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700174 * ...
175 * }
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000176 * dropShortestPathTopo(shortestPathTopo);
177 *
178 * @return the Shortest Path info handler stored in a map.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700179 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000180 public Map<Long, ?> prepareShortestPathTopo() {
181 Map<Long, Node> shortestPathTopo = new HashMap<Long, Node>();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700182
183 //
184 // Fetch the relevant info from the Switch and Port vertices
185 // from the Titan Graph.
186 //
Toshio Koide18e47202013-06-13 14:07:13 -0700187 Iterable<ISwitchObject> nodes = op.getActiveSwitches();
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700188 for (ISwitchObject switchObj : nodes) {
189 Vertex nodeVertex = switchObj.asVertex();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700190 //
191 // The Switch info
192 //
193 String nodeDpid = nodeVertex.getProperty("dpid").toString();
194 long nodeId = HexString.toLong(nodeDpid);
195 Node me = shortestPathTopo.get(nodeId);
196 if (me == null) {
197 me = new Node(nodeId);
198 shortestPathTopo.put(nodeId, me);
199 }
200
201 //
202 // The local Port info
203 //
204 for (Vertex myPortVertex : nodeVertex.getVertices(Direction.OUT, "on")) {
205 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")) {
218 short neighborPort = 0;
219 obj = neighborPortVertex.getProperty("number");
220 if (obj instanceof Short) {
221 neighborPort = (Short)obj;
222 } else if (obj instanceof Integer) {
223 Integer int_nodeId = (Integer)obj;
224 neighborPort = int_nodeId.shortValue();
225 }
226 //
227 // The neighbor Switch info
228 //
229 for (Vertex neighborVertex : neighborPortVertex.getVertices(Direction.IN, "on")) {
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700230 // Ignore inactive switches
231 String state = neighborVertex.getProperty("state").toString();
232 if (! state.equals(SwitchState.ACTIVE.toString()))
233 continue;
234
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700235 String neighborDpid = neighborVertex.getProperty("dpid").toString();
236 long neighborId = HexString.toLong(neighborDpid);
237 Node neighbor = shortestPathTopo.get(neighborId);
238 if (neighbor == null) {
239 neighbor = new Node(neighborId);
240 shortestPathTopo.put(neighborId, neighbor);
241 }
242 me.addNeighbor(neighbor, myPort, neighborPort);
243 }
244 }
245 }
246 }
Toshio Koide18e47202013-06-13 14:07:13 -0700247 op.commit();
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000248
249 return shortestPathTopo;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700250 }
251
252 /**
253 * Release the state that was populated by
254 * method @ref prepareShortestPathTopo().
255 *
256 * See the documentation for method @ref prepareShortestPathTopo()
257 * for additional information and usage.
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000258 *
Pavlin Radoslavoved13a242013-06-20 17:37:20 -0700259 * @param shortestPathTopo the Shortest Path info handler to release.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700260 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000261 public void dropShortestPathTopo(Map<Long, ?> shortestPathTopo) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700262 shortestPathTopo = null;
263 }
264
265 /**
266 * Get the shortest path from a source to a destination by
267 * using the pre-populated local topology state prepared
268 * by method @ref prepareShortestPathTopo().
269 *
270 * See the documentation for method @ref prepareShortestPathTopo()
271 * for additional information and usage.
272 *
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000273 * @param shortestPathTopoHandler the Shortest Path info handler
274 * to use.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700275 * @param src the source in the shortest path computation.
276 * @param dest the destination in the shortest path computation.
277 * @return the data path with the computed shortest path if
278 * found, otherwise null.
279 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000280 public DataPath getTopoShortestPath(Map<Long, ?> shortestPathTopoHandler,
281 SwitchPort src, SwitchPort dest) {
282 @SuppressWarnings("unchecked")
283 Map<Long, Node> shortestPathTopo = (Map)shortestPathTopoHandler;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700284 DataPath result_data_path = new DataPath();
285
286 // Initialize the source and destination in the data path to return
287 result_data_path.setSrcPort(src);
288 result_data_path.setDstPort(dest);
289
290 String dpid_src = src.dpid().toString();
291 String dpid_dest = dest.dpid().toString();
292
293 // Get the source vertex
294 Node v_src = shortestPathTopo.get(src.dpid().value());
295 if (v_src == null) {
296 return null; // Source vertex not found
297 }
298
299 // Get the destination vertex
300 Node v_dest = shortestPathTopo.get(dest.dpid().value());
301 if (v_dest == null) {
302 return null; // Destination vertex not found
303 }
304
305 //
306 // Test whether we are computing a path from/to the same DPID.
307 // If "yes", then just add a single flow entry in the return result.
308 //
309 if (dpid_src.equals(dpid_dest)) {
310 FlowEntry flowEntry = new FlowEntry();
311 flowEntry.setDpid(src.dpid());
312 flowEntry.setInPort(src.port());
313 flowEntry.setOutPort(dest.port());
314 result_data_path.flowEntries().add(flowEntry);
315 return result_data_path;
316 }
317
318 //
319 // Implement the Shortest Path computation by using Breath First Search
320 //
321 Set<Node> visitedSet = new HashSet<Node>();
322 Queue<Node> processingList = new LinkedList<Node>();
323 Map<Node, Node.Link> previousVertexMap = new HashMap<Node, Node.Link>();
324 processingList.add(v_src);
325 visitedSet.add(v_src);
326 Boolean path_found = false;
327 while (! processingList.isEmpty()) {
328 Node nextVertex = processingList.poll();
329 if (v_dest == nextVertex) {
330 path_found = true;
331 break;
332 }
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -0700333 for (Node.Link link : nextVertex.links.values()) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700334 Node child = link.neighbor;
335 if (! visitedSet.contains(child)) {
336 previousVertexMap.put(child, link);
337 visitedSet.add(child);
338 processingList.add(child);
339 }
340 }
341 }
342 if (! path_found)
343 return null; // No path found
344
345 // Collect the path as a list of links
346 List<Node.Link> resultPath = new LinkedList<Node.Link>();
347 Node previousVertex = v_dest;
348 while (! v_src.equals(previousVertex)) {
349 Node.Link currentLink = previousVertexMap.get(previousVertex);
350 resultPath.add(currentLink);
351 previousVertex = currentLink.me;
352 }
353 Collections.reverse(resultPath);
354
355 //
356 // Loop through the result and prepare the return result
357 // as a list of Flow Entries.
358 //
359 Port inPort = new Port(src.port().value());
360 Port outPort;
361 for (Node.Link link: resultPath) {
362 // Setup the outgoing port, and add the Flow Entry
Pavlin Radoslavova1ff1192013-03-29 04:11:32 -0700363 outPort = new Port(link.myPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700364
365 FlowEntry flowEntry = new FlowEntry();
366 flowEntry.setDpid(new Dpid(link.me.nodeId));
367 flowEntry.setInPort(inPort);
368 flowEntry.setOutPort(outPort);
369 result_data_path.flowEntries().add(flowEntry);
370
371 // Setup the next incoming port
372 inPort = new Port(link.neighborPort);
373 }
374 if (resultPath.size() > 0) {
375 // Add the last Flow Entry
376 FlowEntry flowEntry = new FlowEntry();
377 flowEntry.setDpid(new Dpid(dest.dpid().value()));
378 flowEntry.setInPort(inPort);
379 flowEntry.setOutPort(dest.port());
380 result_data_path.flowEntries().add(flowEntry);
381 }
382
383 if (result_data_path.flowEntries().size() > 0)
384 return result_data_path;
385
386 return null;
387 }
388
389 /**
390 * Get the shortest path from a source to a destination.
391 *
392 * @param src the source in the shortest path computation.
393 * @param dest the destination in the shortest path computation.
394 * @return the data path with the computed shortest path if
395 * found, otherwise null.
396 */
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800397 @Override
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800398 public DataPath getShortestPath(SwitchPort src, SwitchPort dest) {
399 DataPath result_data_path = new DataPath();
400
401 // Initialize the source and destination in the data path to return
402 result_data_path.setSrcPort(src);
403 result_data_path.setDstPort(dest);
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800404
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800405 String dpid_src = src.dpid().toString();
406 String dpid_dest = dest.dpid().toString();
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800407
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700408 // Get the source and destination switches
409 ISwitchObject srcSwitch =
Toshio Koide18e47202013-06-13 14:07:13 -0700410 op.searchActiveSwitch(dpid_src);
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700411 ISwitchObject destSwitch =
Toshio Koide18e47202013-06-13 14:07:13 -0700412 op.searchActiveSwitch(dpid_dest);
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700413 if (srcSwitch == null || destSwitch == null) {
414 return null;
415 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800416
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800417 //
418 // Test whether we are computing a path from/to the same DPID.
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800419 // If "yes", then just add a single flow entry in the return result.
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800420 //
421 if (dpid_src.equals(dpid_dest)) {
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800422 FlowEntry flowEntry = new FlowEntry();
423 flowEntry.setDpid(src.dpid());
424 flowEntry.setInPort(src.port());
425 flowEntry.setOutPort(dest.port());
426 result_data_path.flowEntries().add(flowEntry);
Toshio Koide18e47202013-06-13 14:07:13 -0700427 op.commit();
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800428 return result_data_path;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800429 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800430
Pankaj Berde15193092013-03-21 17:30:14 -0700431 Vertex v_src = srcSwitch.asVertex();
432 Vertex v_dest = destSwitch.asVertex();
433
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700434 //
435 // Implement the Shortest Path computation by using Breath First Search
436 //
437 Set<Vertex> visitedSet = new HashSet<Vertex>();
438 Queue<Vertex> processingList = new LinkedList<Vertex>();
439 Map<Vertex, Vertex> previousVertexMap = new HashMap<Vertex, Vertex>();
440
441 processingList.add(v_src);
442 visitedSet.add(v_src);
443 Boolean path_found = false;
444 while (! processingList.isEmpty()) {
445 Vertex nextVertex = processingList.poll();
446 if (v_dest.equals(nextVertex)) {
447 path_found = true;
448 break;
449 }
450 for (Vertex parentPort : nextVertex.getVertices(Direction.OUT, "on")) {
451 for (Vertex childPort : parentPort.getVertices(Direction.OUT, "link")) {
452 for (Vertex child : childPort.getVertices(Direction.IN, "on")) {
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700453 // Ignore inactive switches
454 String state = child.getProperty("state").toString();
455 if (! state.equals(SwitchState.ACTIVE.toString()))
456 continue;
457
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700458 if (! visitedSet.contains(child)) {
459 previousVertexMap.put(parentPort, nextVertex);
460 previousVertexMap.put(childPort, parentPort);
461 previousVertexMap.put(child, childPort);
462 visitedSet.add(child);
463 processingList.add(child);
464 }
465 }
466 }
467 }
468 }
469 if (! path_found)
470 return null; // No path found
471
472 List<Vertex> resultPath = new LinkedList<Vertex>();
473 Vertex previousVertex = v_dest;
474 resultPath.add(v_dest);
475 while (! v_src.equals(previousVertex)) {
476 Vertex currentVertex = previousVertexMap.get(previousVertex);
477 resultPath.add(currentVertex);
478 previousVertex = currentVertex;
479 }
480 Collections.reverse(resultPath);
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800481
Pankaj Berde15193092013-03-21 17:30:14 -0700482
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800483 //
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700484 // Loop through the result and prepare the return result
485 // as a list of Flow Entries.
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800486 //
487 long nodeId = 0;
488 short portId = 0;
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800489 Port inPort = new Port(src.port().value());
490 Port outPort = new Port();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700491 int idx = 0;
492 for (Vertex v: resultPath) {
493 String type = v.getProperty("type").toString();
494 // System.out.println("type: " + type);
495 if (type.equals("port")) {
496 String number = v.getProperty("number").toString();
497 // System.out.println("number: " + number);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800498
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700499 Object obj = v.getProperty("number");
500 // String class_str = obj.getClass().toString();
501 if (obj instanceof Short) {
502 portId = (Short)obj;
503 } else if (obj instanceof Integer) {
504 Integer int_nodeId = (Integer)obj;
505 portId = int_nodeId.shortValue();
506 // int int_nodeId = (Integer)obj;
507 // portId = (short)int_nodeId.;
508 }
509 } else if (type.equals("switch")) {
510 String dpid = v.getProperty("dpid").toString();
511 nodeId = HexString.toLong(dpid);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800512
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700513 // System.out.println("dpid: " + dpid);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800514 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700515 idx++;
516 if (idx == 1) {
517 continue;
518 }
519 int mod = idx % 3;
520 if (mod == 0) {
521 // Setup the incoming port
522 inPort = new Port(portId);
523 continue;
524 }
525 if (mod == 2) {
526 // Setup the outgoing port, and add the Flow Entry
527 outPort = new Port(portId);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800528
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800529 FlowEntry flowEntry = new FlowEntry();
530 flowEntry.setDpid(new Dpid(nodeId));
531 flowEntry.setInPort(inPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700532 flowEntry.setOutPort(outPort);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800533 result_data_path.flowEntries().add(flowEntry);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700534 continue;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800535 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800536 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700537 if (idx > 0) {
538 // Add the last Flow Entry
539 FlowEntry flowEntry = new FlowEntry();
540 flowEntry.setDpid(new Dpid(nodeId));
541 flowEntry.setInPort(inPort);
542 flowEntry.setOutPort(dest.port());
543 result_data_path.flowEntries().add(flowEntry);
544 }
545
Toshio Koide18e47202013-06-13 14:07:13 -0700546 op.commit();
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800547 if (result_data_path.flowEntries().size() > 0)
548 return result_data_path;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800549
550 return null;
551 }
552
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700553 /**
554 * Test whether a route exists from a source to a destination.
555 *
556 * @param src the source node for the test.
557 * @param dest the destination node for the test.
558 * @return true if a route exists, otherwise false.
559 */
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800560 @Override
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800561 public Boolean routeExists(SwitchPort src, SwitchPort dest) {
562 DataPath dataPath = getShortestPath(src, dest);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700563 return (dataPath != null);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800564 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800565}