blob: 5328eaec0b62355fbbe155696313c08a6976c5b5 [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
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080014import net.floodlightcontroller.core.module.FloodlightModuleContext;
15import net.floodlightcontroller.core.module.FloodlightModuleException;
16import net.floodlightcontroller.core.module.IFloodlightModule;
17import net.floodlightcontroller.core.module.IFloodlightService;
Pankaj Berde38646d62013-06-21 11:34:04 -070018import net.onrc.onos.graph.GraphDBOperation;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070019import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
20import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoRouteService;
21import net.onrc.onos.ofcontroller.core.ISwitchStorage.SwitchState;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070022import net.onrc.onos.ofcontroller.util.DataPath;
23import net.onrc.onos.ofcontroller.util.Dpid;
24import net.onrc.onos.ofcontroller.util.FlowEntry;
25import net.onrc.onos.ofcontroller.util.Port;
26import net.onrc.onos.ofcontroller.util.SwitchPort;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080027
28import org.openflow.util.HexString;
Pankaj Berde15193092013-03-21 17:30:14 -070029import org.slf4j.Logger;
30import org.slf4j.LoggerFactory;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080031
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070032import com.tinkerpop.blueprints.Direction;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080033import com.tinkerpop.blueprints.Vertex;
Pavlin Radoslavovbfae5e02013-03-19 23:06:36 -070034import com.tinkerpop.pipes.PipeFunction;
35import com.tinkerpop.pipes.branch.LoopPipe.LoopBundle;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080036
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070037
38/**
39 * A class for storing Node and Link information for fast computation
40 * of shortest paths.
41 */
42class Node {
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070043 /**
44 * A class for storing Link information for fast computation of shortest
45 * paths.
46 */
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070047 class Link {
48 public Node me; // The node this link originates from
49 public Node neighbor; // The neighbor node on the other side
50 public short myPort; // Local port number for the link
51 public short neighborPort; // Neighbor port number for the link
52
53 /**
54 * Link constructor.
55 *
56 * @param me the node this link originates from.
57 * @param the neighbor node on the other side of the link.
58 * @param myPort local port number for the link.
59 * @param neighborPort neighrobr port number for the link.
60 */
61 public Link(Node me, Node neighbor, short myPort, short neighborPort) {
62 this.me = me;
63 this.neighbor = neighbor;
64 this.myPort = myPort;
65 this.neighborPort = neighborPort;
66 }
67 };
68
69 public long nodeId; // The node ID
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -070070 public HashMap<Short, Link> links; // The links originating from this node
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070071
72 /**
73 * Node constructor.
74 *
75 * @param nodeId the node ID.
76 */
77 public Node(long nodeId) {
78 this.nodeId = nodeId;
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -070079 links = new HashMap<Short, Link>();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070080 }
81
82 /**
83 * Add a neighbor.
84 *
85 * A new link to the neighbor will be created.
86 *
87 * @param neighbor the neighbor to add.
88 * @param myPort the local port number for the link to the neighbor.
89 * @param neighborPort the neighbor port number for the link.
90 */
91 public void addNeighbor(Node neighbor, short myPort, short neighborPort) {
92 Link link = new Link(this, neighbor, myPort, neighborPort);
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -070093 links.put(myPort, link);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070094 }
95};
96
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070097/**
98 * A class for implementing Topology Route Service.
99 */
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800100public class TopoRouteService implements IFloodlightModule, ITopoRouteService {
101
102 /** The logger. */
Pavlin Radoslavov19343432013-03-06 10:43:18 -0800103 private static Logger log =
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800104 LoggerFactory.getLogger(TopoRouteService.class);
Pankaj Berde15193092013-03-21 17:30:14 -0700105
Toshio Koide18e47202013-06-13 14:07:13 -0700106 protected GraphDBOperation op;
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800107
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700108 /**
109 * Get the collection of module services.
110 *
111 * @return the collection of services provided by this module.
112 */
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800113 @Override
114 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
115 Collection<Class<? extends IFloodlightService>> l =
116 new ArrayList<Class<? extends IFloodlightService>>();
117 l.add(ITopoRouteService.class);
118 return l;
119 }
120
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700121 /**
122 * Get a map with the services provided by this module.
123 *
124 * @return a map with the services provided by this module.
125 */
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800126 @Override
127 public Map<Class<? extends IFloodlightService>, IFloodlightService>
128 getServiceImpls() {
129 Map<Class<? extends IFloodlightService>,
130 IFloodlightService> m =
131 new HashMap<Class<? extends IFloodlightService>,
132 IFloodlightService>();
133 m.put(ITopoRouteService.class, this);
134 return m;
135 }
136
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700137 /**
138 * Get the collection with the services this module depends on.
139 *
140 * @return the collection with the services this module depends on.
141 */
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800142 @Override
143 public Collection<Class<? extends IFloodlightService>>
144 getModuleDependencies() {
145 Collection<Class<? extends IFloodlightService>> l =
146 new ArrayList<Class<? extends IFloodlightService>>();
147 // TODO: Add the appropriate dependencies
148 // l.add(IRestApiService.class);
149 return l;
150 }
151
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700152 /**
153 * Init the module.
154 *
155 * @param context the module context to use for the initialization.
156 * @see FloodlightModuleContext.
157 */
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800158 @Override
159 public void init(FloodlightModuleContext context)
160 throws FloodlightModuleException {
161 // TODO: Add the appropriate initialization
Toshio Koidebfe9b922013-06-18 10:56:05 -0700162 op = new GraphDBOperation("");
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800163 }
164
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700165 /**
166 * Startup initialization.
167 */
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800168 @Override
169 public void startUp(FloodlightModuleContext context) {
170 // TODO: Add the approprate setup
171 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800172
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700173 /**
174 * Set the database operation handler.
175 *
176 * @param init_op the database operation handler to use for the
177 * initialization.
178 */
Pavlin Radoslavovcec899a2013-06-27 15:47:50 -0700179 public void setDbOperationHandler(GraphDBOperation init_op) {
180 op = init_op;
181 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800182
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700183 /**
184 * Fetch the Switch and Ports info from the Titan Graph
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000185 * and return it for fast access during the shortest path
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700186 * computation.
187 *
188 * After fetching the state, method @ref getTopoShortestPath()
189 * can be used for fast shortest path computation.
190 *
191 * Note: There is certain cost to fetch the state, hence it should
192 * be used only when there is a large number of shortest path
193 * computations that need to be done on the same topology.
194 * Typically, a single call to @ref prepareShortestPathTopo()
195 * should be followed by a large number of calls to
196 * method @ref getTopoShortestPath().
197 * After the last @ref getTopoShortestPath() call,
198 * method @ref dropShortestPathTopo() should be used to release
199 * the internal state that is not needed anymore:
200 *
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000201 * Map<Long, ?> shortestPathTopo;
202 * shortestPathTopo = prepareShortestPathTopo();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700203 * for (int i = 0; i < 10000; i++) {
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000204 * dataPath = getTopoShortestPath(shortestPathTopo, ...);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700205 * ...
206 * }
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000207 * dropShortestPathTopo(shortestPathTopo);
208 *
209 * @return the Shortest Path info handler stored in a map.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700210 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000211 public Map<Long, ?> prepareShortestPathTopo() {
212 Map<Long, Node> shortestPathTopo = new HashMap<Long, Node>();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700213
214 //
215 // Fetch the relevant info from the Switch and Port vertices
216 // from the Titan Graph.
217 //
Toshio Koide18e47202013-06-13 14:07:13 -0700218 Iterable<ISwitchObject> nodes = op.getActiveSwitches();
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700219 for (ISwitchObject switchObj : nodes) {
220 Vertex nodeVertex = switchObj.asVertex();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700221 //
222 // The Switch info
223 //
224 String nodeDpid = nodeVertex.getProperty("dpid").toString();
225 long nodeId = HexString.toLong(nodeDpid);
226 Node me = shortestPathTopo.get(nodeId);
227 if (me == null) {
228 me = new Node(nodeId);
229 shortestPathTopo.put(nodeId, me);
230 }
231
232 //
233 // The local Port info
234 //
235 for (Vertex myPortVertex : nodeVertex.getVertices(Direction.OUT, "on")) {
236 short myPort = 0;
237 Object obj = myPortVertex.getProperty("number");
238 if (obj instanceof Short) {
239 myPort = (Short)obj;
240 } else if (obj instanceof Integer) {
241 Integer int_nodeId = (Integer)obj;
242 myPort = int_nodeId.shortValue();
243 }
244
245 //
246 // The neighbor Port info
247 //
248 for (Vertex neighborPortVertex : myPortVertex.getVertices(Direction.OUT, "link")) {
249 short neighborPort = 0;
250 obj = neighborPortVertex.getProperty("number");
251 if (obj instanceof Short) {
252 neighborPort = (Short)obj;
253 } else if (obj instanceof Integer) {
254 Integer int_nodeId = (Integer)obj;
255 neighborPort = int_nodeId.shortValue();
256 }
257 //
258 // The neighbor Switch info
259 //
260 for (Vertex neighborVertex : neighborPortVertex.getVertices(Direction.IN, "on")) {
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700261 // Ignore inactive switches
262 String state = neighborVertex.getProperty("state").toString();
263 if (! state.equals(SwitchState.ACTIVE.toString()))
264 continue;
265
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700266 String neighborDpid = neighborVertex.getProperty("dpid").toString();
267 long neighborId = HexString.toLong(neighborDpid);
268 Node neighbor = shortestPathTopo.get(neighborId);
269 if (neighbor == null) {
270 neighbor = new Node(neighborId);
271 shortestPathTopo.put(neighborId, neighbor);
272 }
273 me.addNeighbor(neighbor, myPort, neighborPort);
274 }
275 }
276 }
277 }
Toshio Koide18e47202013-06-13 14:07:13 -0700278 op.commit();
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000279
280 return shortestPathTopo;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700281 }
282
283 /**
284 * Release the state that was populated by
285 * method @ref prepareShortestPathTopo().
286 *
287 * See the documentation for method @ref prepareShortestPathTopo()
288 * for additional information and usage.
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000289 *
Pavlin Radoslavoved13a242013-06-20 17:37:20 -0700290 * @param shortestPathTopo the Shortest Path info handler to release.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700291 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000292 public void dropShortestPathTopo(Map<Long, ?> shortestPathTopo) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700293 shortestPathTopo = null;
294 }
295
296 /**
297 * Get the shortest path from a source to a destination by
298 * using the pre-populated local topology state prepared
299 * by method @ref prepareShortestPathTopo().
300 *
301 * See the documentation for method @ref prepareShortestPathTopo()
302 * for additional information and usage.
303 *
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000304 * @param shortestPathTopoHandler the Shortest Path info handler
305 * to use.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700306 * @param src the source in the shortest path computation.
307 * @param dest the destination in the shortest path computation.
308 * @return the data path with the computed shortest path if
309 * found, otherwise null.
310 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000311 public DataPath getTopoShortestPath(Map<Long, ?> shortestPathTopoHandler,
312 SwitchPort src, SwitchPort dest) {
313 @SuppressWarnings("unchecked")
314 Map<Long, Node> shortestPathTopo = (Map)shortestPathTopoHandler;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700315 DataPath result_data_path = new DataPath();
316
317 // Initialize the source and destination in the data path to return
318 result_data_path.setSrcPort(src);
319 result_data_path.setDstPort(dest);
320
321 String dpid_src = src.dpid().toString();
322 String dpid_dest = dest.dpid().toString();
323
324 // Get the source vertex
325 Node v_src = shortestPathTopo.get(src.dpid().value());
326 if (v_src == null) {
327 return null; // Source vertex not found
328 }
329
330 // Get the destination vertex
331 Node v_dest = shortestPathTopo.get(dest.dpid().value());
332 if (v_dest == null) {
333 return null; // Destination vertex not found
334 }
335
336 //
337 // Test whether we are computing a path from/to the same DPID.
338 // If "yes", then just add a single flow entry in the return result.
339 //
340 if (dpid_src.equals(dpid_dest)) {
341 FlowEntry flowEntry = new FlowEntry();
342 flowEntry.setDpid(src.dpid());
343 flowEntry.setInPort(src.port());
344 flowEntry.setOutPort(dest.port());
345 result_data_path.flowEntries().add(flowEntry);
346 return result_data_path;
347 }
348
349 //
350 // Implement the Shortest Path computation by using Breath First Search
351 //
352 Set<Node> visitedSet = new HashSet<Node>();
353 Queue<Node> processingList = new LinkedList<Node>();
354 Map<Node, Node.Link> previousVertexMap = new HashMap<Node, Node.Link>();
355 processingList.add(v_src);
356 visitedSet.add(v_src);
357 Boolean path_found = false;
358 while (! processingList.isEmpty()) {
359 Node nextVertex = processingList.poll();
360 if (v_dest == nextVertex) {
361 path_found = true;
362 break;
363 }
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -0700364 for (Node.Link link : nextVertex.links.values()) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700365 Node child = link.neighbor;
366 if (! visitedSet.contains(child)) {
367 previousVertexMap.put(child, link);
368 visitedSet.add(child);
369 processingList.add(child);
370 }
371 }
372 }
373 if (! path_found)
374 return null; // No path found
375
376 // Collect the path as a list of links
377 List<Node.Link> resultPath = new LinkedList<Node.Link>();
378 Node previousVertex = v_dest;
379 while (! v_src.equals(previousVertex)) {
380 Node.Link currentLink = previousVertexMap.get(previousVertex);
381 resultPath.add(currentLink);
382 previousVertex = currentLink.me;
383 }
384 Collections.reverse(resultPath);
385
386 //
387 // Loop through the result and prepare the return result
388 // as a list of Flow Entries.
389 //
390 Port inPort = new Port(src.port().value());
391 Port outPort;
392 for (Node.Link link: resultPath) {
393 // Setup the outgoing port, and add the Flow Entry
Pavlin Radoslavova1ff1192013-03-29 04:11:32 -0700394 outPort = new Port(link.myPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700395
396 FlowEntry flowEntry = new FlowEntry();
397 flowEntry.setDpid(new Dpid(link.me.nodeId));
398 flowEntry.setInPort(inPort);
399 flowEntry.setOutPort(outPort);
400 result_data_path.flowEntries().add(flowEntry);
401
402 // Setup the next incoming port
403 inPort = new Port(link.neighborPort);
404 }
405 if (resultPath.size() > 0) {
406 // Add the last Flow Entry
407 FlowEntry flowEntry = new FlowEntry();
408 flowEntry.setDpid(new Dpid(dest.dpid().value()));
409 flowEntry.setInPort(inPort);
410 flowEntry.setOutPort(dest.port());
411 result_data_path.flowEntries().add(flowEntry);
412 }
413
414 if (result_data_path.flowEntries().size() > 0)
415 return result_data_path;
416
417 return null;
418 }
419
420 /**
421 * Get the shortest path from a source to a destination.
422 *
423 * @param src the source in the shortest path computation.
424 * @param dest the destination in the shortest path computation.
425 * @return the data path with the computed shortest path if
426 * found, otherwise null.
427 */
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800428 @Override
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800429 public DataPath getShortestPath(SwitchPort src, SwitchPort dest) {
430 DataPath result_data_path = new DataPath();
431
432 // Initialize the source and destination in the data path to return
433 result_data_path.setSrcPort(src);
434 result_data_path.setDstPort(dest);
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800435
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800436 String dpid_src = src.dpid().toString();
437 String dpid_dest = dest.dpid().toString();
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800438
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700439 // Get the source and destination switches
440 ISwitchObject srcSwitch =
Toshio Koide18e47202013-06-13 14:07:13 -0700441 op.searchActiveSwitch(dpid_src);
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700442 ISwitchObject destSwitch =
Toshio Koide18e47202013-06-13 14:07:13 -0700443 op.searchActiveSwitch(dpid_dest);
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700444 if (srcSwitch == null || destSwitch == null) {
445 return null;
446 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800447
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800448 //
449 // Test whether we are computing a path from/to the same DPID.
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800450 // If "yes", then just add a single flow entry in the return result.
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800451 //
452 if (dpid_src.equals(dpid_dest)) {
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800453 FlowEntry flowEntry = new FlowEntry();
454 flowEntry.setDpid(src.dpid());
455 flowEntry.setInPort(src.port());
456 flowEntry.setOutPort(dest.port());
457 result_data_path.flowEntries().add(flowEntry);
Toshio Koide18e47202013-06-13 14:07:13 -0700458 op.commit();
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800459 return result_data_path;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800460 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800461
Pankaj Berde15193092013-03-21 17:30:14 -0700462 Vertex v_src = srcSwitch.asVertex();
463 Vertex v_dest = destSwitch.asVertex();
464
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700465 //
466 // Implement the Shortest Path computation by using Breath First Search
467 //
468 Set<Vertex> visitedSet = new HashSet<Vertex>();
469 Queue<Vertex> processingList = new LinkedList<Vertex>();
470 Map<Vertex, Vertex> previousVertexMap = new HashMap<Vertex, Vertex>();
471
472 processingList.add(v_src);
473 visitedSet.add(v_src);
474 Boolean path_found = false;
475 while (! processingList.isEmpty()) {
476 Vertex nextVertex = processingList.poll();
477 if (v_dest.equals(nextVertex)) {
478 path_found = true;
479 break;
480 }
481 for (Vertex parentPort : nextVertex.getVertices(Direction.OUT, "on")) {
482 for (Vertex childPort : parentPort.getVertices(Direction.OUT, "link")) {
483 for (Vertex child : childPort.getVertices(Direction.IN, "on")) {
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700484 // Ignore inactive switches
485 String state = child.getProperty("state").toString();
486 if (! state.equals(SwitchState.ACTIVE.toString()))
487 continue;
488
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700489 if (! visitedSet.contains(child)) {
490 previousVertexMap.put(parentPort, nextVertex);
491 previousVertexMap.put(childPort, parentPort);
492 previousVertexMap.put(child, childPort);
493 visitedSet.add(child);
494 processingList.add(child);
495 }
496 }
497 }
498 }
499 }
500 if (! path_found)
501 return null; // No path found
502
503 List<Vertex> resultPath = new LinkedList<Vertex>();
504 Vertex previousVertex = v_dest;
505 resultPath.add(v_dest);
506 while (! v_src.equals(previousVertex)) {
507 Vertex currentVertex = previousVertexMap.get(previousVertex);
508 resultPath.add(currentVertex);
509 previousVertex = currentVertex;
510 }
511 Collections.reverse(resultPath);
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800512
Pankaj Berde15193092013-03-21 17:30:14 -0700513
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800514 //
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700515 // Loop through the result and prepare the return result
516 // as a list of Flow Entries.
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800517 //
518 long nodeId = 0;
519 short portId = 0;
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800520 Port inPort = new Port(src.port().value());
521 Port outPort = new Port();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700522 int idx = 0;
523 for (Vertex v: resultPath) {
524 String type = v.getProperty("type").toString();
525 // System.out.println("type: " + type);
526 if (type.equals("port")) {
527 String number = v.getProperty("number").toString();
528 // System.out.println("number: " + number);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800529
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700530 Object obj = v.getProperty("number");
531 // String class_str = obj.getClass().toString();
532 if (obj instanceof Short) {
533 portId = (Short)obj;
534 } else if (obj instanceof Integer) {
535 Integer int_nodeId = (Integer)obj;
536 portId = int_nodeId.shortValue();
537 // int int_nodeId = (Integer)obj;
538 // portId = (short)int_nodeId.;
539 }
540 } else if (type.equals("switch")) {
541 String dpid = v.getProperty("dpid").toString();
542 nodeId = HexString.toLong(dpid);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800543
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700544 // System.out.println("dpid: " + dpid);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800545 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700546 idx++;
547 if (idx == 1) {
548 continue;
549 }
550 int mod = idx % 3;
551 if (mod == 0) {
552 // Setup the incoming port
553 inPort = new Port(portId);
554 continue;
555 }
556 if (mod == 2) {
557 // Setup the outgoing port, and add the Flow Entry
558 outPort = new Port(portId);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800559
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800560 FlowEntry flowEntry = new FlowEntry();
561 flowEntry.setDpid(new Dpid(nodeId));
562 flowEntry.setInPort(inPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700563 flowEntry.setOutPort(outPort);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800564 result_data_path.flowEntries().add(flowEntry);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700565 continue;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800566 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800567 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700568 if (idx > 0) {
569 // Add the last Flow Entry
570 FlowEntry flowEntry = new FlowEntry();
571 flowEntry.setDpid(new Dpid(nodeId));
572 flowEntry.setInPort(inPort);
573 flowEntry.setOutPort(dest.port());
574 result_data_path.flowEntries().add(flowEntry);
575 }
576
Toshio Koide18e47202013-06-13 14:07:13 -0700577 op.commit();
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800578 if (result_data_path.flowEntries().size() > 0)
579 return result_data_path;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800580
581 return null;
582 }
583
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700584 /**
585 * Test whether a route exists from a source to a destination.
586 *
587 * @param src the source node for the test.
588 * @param dest the destination node for the test.
589 * @return true if a route exists, otherwise false.
590 */
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800591 @Override
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800592 public Boolean routeExists(SwitchPort src, SwitchPort dest) {
593 DataPath dataPath = getShortestPath(src, dest);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700594 return (dataPath != null);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800595 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800596}