blob: fd7c36497637ccacb890c2e748a7febcc01c96f0 [file] [log] [blame]
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -08001package net.floodlightcontroller.routing;
2
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 Berde15193092013-03-21 17:30:14 -070014import net.floodlightcontroller.core.INetMapTopologyObjects.ISwitchObject;
15import net.floodlightcontroller.core.INetMapTopologyService.ITopoRouteService;
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080016import net.floodlightcontroller.core.module.FloodlightModuleContext;
17import net.floodlightcontroller.core.module.FloodlightModuleException;
18import net.floodlightcontroller.core.module.IFloodlightModule;
19import net.floodlightcontroller.core.module.IFloodlightService;
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -080020import net.floodlightcontroller.util.DataPath;
21import net.floodlightcontroller.util.Dpid;
22import net.floodlightcontroller.util.FlowEntry;
23import net.floodlightcontroller.util.Port;
24import net.floodlightcontroller.util.SwitchPort;
Pankaj Berde15193092013-03-21 17:30:14 -070025import net.onrc.onos.util.GraphDBConnection;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080026
27import org.openflow.util.HexString;
Pankaj Berde15193092013-03-21 17:30:14 -070028import org.slf4j.Logger;
29import org.slf4j.LoggerFactory;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080030
Pankaj Berde15193092013-03-21 17:30:14 -070031import com.thinkaurelius.titan.core.TitanFactory;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080032import com.thinkaurelius.titan.core.TitanGraph;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070033import com.thinkaurelius.titan.core.TitanTransaction;
34import com.tinkerpop.blueprints.Direction;
Pavlin Radoslavov19343432013-03-06 10:43:18 -080035import com.tinkerpop.blueprints.TransactionalGraph.Conclusion;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080036import com.tinkerpop.blueprints.Vertex;
Pavlin Radoslavovbfae5e02013-03-19 23:06:36 -070037import com.tinkerpop.pipes.PipeFunction;
38import com.tinkerpop.pipes.branch.LoopPipe.LoopBundle;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080039
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070040
41/**
42 * A class for storing Node and Link information for fast computation
43 * of shortest paths.
44 */
45class Node {
46 class Link {
47 public Node me; // The node this link originates from
48 public Node neighbor; // The neighbor node on the other side
49 public short myPort; // Local port number for the link
50 public short neighborPort; // Neighbor port number for the link
51
52 /**
53 * Link constructor.
54 *
55 * @param me the node this link originates from.
56 * @param the neighbor node on the other side of the link.
57 * @param myPort local port number for the link.
58 * @param neighborPort neighrobr port number for the link.
59 */
60 public Link(Node me, Node neighbor, short myPort, short neighborPort) {
61 this.me = me;
62 this.neighbor = neighbor;
63 this.myPort = myPort;
64 this.neighborPort = neighborPort;
65 }
66 };
67
68 public long nodeId; // The node ID
69 public LinkedList<Link> links; // The links originating from this node
70
71 /**
72 * Node constructor.
73 *
74 * @param nodeId the node ID.
75 */
76 public Node(long nodeId) {
77 this.nodeId = nodeId;
78 links = new LinkedList<Link>();
79 }
80
81 /**
82 * Add a neighbor.
83 *
84 * A new link to the neighbor will be created.
85 *
86 * @param neighbor the neighbor to add.
87 * @param myPort the local port number for the link to the neighbor.
88 * @param neighborPort the neighbor port number for the link.
89 */
90 public void addNeighbor(Node neighbor, short myPort, short neighborPort) {
91 Link link = new Link(this, neighbor, myPort, neighborPort);
92 links.add(link);
93 }
94};
95
Pankaj Berde15193092013-03-21 17:30:14 -070096
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080097public class TopoRouteService implements IFloodlightModule, ITopoRouteService {
98
99 /** The logger. */
Pavlin Radoslavov19343432013-03-06 10:43:18 -0800100 private static Logger log =
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800101 LoggerFactory.getLogger(TopoRouteService.class);
Pankaj Berde15193092013-03-21 17:30:14 -0700102
103 GraphDBConnection conn;
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800104
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700105 //
106 // Topology state for storing (on demand) Switch and Ports info for
107 // fast access during the shortest path computation.
108 // It is explicitly populated by method @ref prepareShortestPathTopo().
109 // See the documentation for that method for details.
110 //
111 HashMap<Long, Node> shortestPathTopo;
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
121 @Override
122 public Map<Class<? extends IFloodlightService>, IFloodlightService>
123 getServiceImpls() {
124 Map<Class<? extends IFloodlightService>,
125 IFloodlightService> m =
126 new HashMap<Class<? extends IFloodlightService>,
127 IFloodlightService>();
128 m.put(ITopoRouteService.class, this);
129 return m;
130 }
131
132 @Override
133 public Collection<Class<? extends IFloodlightService>>
134 getModuleDependencies() {
135 Collection<Class<? extends IFloodlightService>> l =
136 new ArrayList<Class<? extends IFloodlightService>>();
137 // TODO: Add the appropriate dependencies
138 // l.add(IRestApiService.class);
139 return l;
140 }
141
142 @Override
143 public void init(FloodlightModuleContext context)
144 throws FloodlightModuleException {
145 // TODO: Add the appropriate initialization
Pankaj Berde15193092013-03-21 17:30:14 -0700146 conn = GraphDBConnection.getInstance("");
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800147 }
148
149 @Override
150 public void startUp(FloodlightModuleContext context) {
151 // TODO: Add the approprate setup
152 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800153
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800154
Pavlin Radoslavovbfae5e02013-03-19 23:06:36 -0700155 static class ShortestPathLoopFunction implements PipeFunction<LoopBundle<Vertex>, Boolean> {
156 String dpid;
157 public ShortestPathLoopFunction(String dpid) {
158 super();
159 this.dpid = dpid;
160 }
161 public Boolean compute(LoopBundle<Vertex> bundle) {
162 Boolean output = false;
163 if (! bundle.getObject().getProperty("dpid").equals(dpid)) {
164 output = true;
165 }
166 return output;
167 }
168 }
169
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700170 /**
171 * Fetch the Switch and Ports info from the Titan Graph
172 * and store it locally for fast access during the shortest path
173 * computation.
174 *
175 * After fetching the state, method @ref getTopoShortestPath()
176 * can be used for fast shortest path computation.
177 *
178 * Note: There is certain cost to fetch the state, hence it should
179 * be used only when there is a large number of shortest path
180 * computations that need to be done on the same topology.
181 * Typically, a single call to @ref prepareShortestPathTopo()
182 * should be followed by a large number of calls to
183 * method @ref getTopoShortestPath().
184 * After the last @ref getTopoShortestPath() call,
185 * method @ref dropShortestPathTopo() should be used to release
186 * the internal state that is not needed anymore:
187 *
188 * prepareShortestPathTopo();
189 * for (int i = 0; i < 10000; i++) {
190 * dataPath = getTopoShortestPath(...);
191 * ...
192 * }
193 * dropShortestPathTopo();
194 */
Pankaj Berde15193092013-03-21 17:30:14 -0700195
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700196 public void prepareShortestPathTopo() {
Pankaj Berde15193092013-03-21 17:30:14 -0700197 TitanGraph titanGraph = TitanFactory.open("/tmp/cassandra.titan");
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700198 TitanTransaction titanTransaction = titanGraph.startTransaction();
199 shortestPathTopo = new HashMap<Long, Node>();
200
201 //
202 // Fetch the relevant info from the Switch and Port vertices
203 // from the Titan Graph.
204 //
205 Iterable<Vertex> nodes = titanTransaction.getVertices("type", "switch");
206 for (Vertex nodeVertex : nodes) {
Pankaj Berde15193092013-03-21 17:30:14 -0700207
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700208 //
209 // The Switch info
210 //
211 String nodeDpid = nodeVertex.getProperty("dpid").toString();
212 long nodeId = HexString.toLong(nodeDpid);
213 Node me = shortestPathTopo.get(nodeId);
214 if (me == null) {
215 me = new Node(nodeId);
216 shortestPathTopo.put(nodeId, me);
217 }
218
219 //
220 // The local Port info
221 //
222 for (Vertex myPortVertex : nodeVertex.getVertices(Direction.OUT, "on")) {
223 short myPort = 0;
224 Object obj = myPortVertex.getProperty("number");
225 if (obj instanceof Short) {
226 myPort = (Short)obj;
227 } else if (obj instanceof Integer) {
228 Integer int_nodeId = (Integer)obj;
229 myPort = int_nodeId.shortValue();
230 }
231
232 //
233 // The neighbor Port info
234 //
235 for (Vertex neighborPortVertex : myPortVertex.getVertices(Direction.OUT, "link")) {
236 short neighborPort = 0;
237 obj = neighborPortVertex.getProperty("number");
238 if (obj instanceof Short) {
239 neighborPort = (Short)obj;
240 } else if (obj instanceof Integer) {
241 Integer int_nodeId = (Integer)obj;
242 neighborPort = int_nodeId.shortValue();
243 }
244 //
245 // The neighbor Switch info
246 //
247 for (Vertex neighborVertex : neighborPortVertex.getVertices(Direction.IN, "on")) {
248 String neighborDpid = neighborVertex.getProperty("dpid").toString();
249 long neighborId = HexString.toLong(neighborDpid);
250 Node neighbor = shortestPathTopo.get(neighborId);
251 if (neighbor == null) {
252 neighbor = new Node(neighborId);
253 shortestPathTopo.put(neighborId, neighbor);
254 }
255 me.addNeighbor(neighbor, myPort, neighborPort);
256 }
257 }
258 }
259 }
260
261 titanTransaction.stopTransaction(Conclusion.SUCCESS);
262 }
263
264 /**
265 * Release the state that was populated by
266 * method @ref prepareShortestPathTopo().
267 *
268 * See the documentation for method @ref prepareShortestPathTopo()
269 * for additional information and usage.
270 */
Pankaj Berde15193092013-03-21 17:30:14 -0700271
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700272 public void dropShortestPathTopo() {
273 shortestPathTopo = null;
274 }
275
276 /**
277 * Get the shortest path from a source to a destination by
278 * using the pre-populated local topology state prepared
279 * by method @ref prepareShortestPathTopo().
280 *
281 * See the documentation for method @ref prepareShortestPathTopo()
282 * for additional information and usage.
283 *
284 * @param src the source in the shortest path computation.
285 * @param dest the destination in the shortest path computation.
286 * @return the data path with the computed shortest path if
287 * found, otherwise null.
288 */
Pankaj Berde15193092013-03-21 17:30:14 -0700289
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700290 public DataPath getTopoShortestPath(SwitchPort src, SwitchPort dest) {
291 DataPath result_data_path = new DataPath();
292
293 // Initialize the source and destination in the data path to return
294 result_data_path.setSrcPort(src);
295 result_data_path.setDstPort(dest);
296
297 String dpid_src = src.dpid().toString();
298 String dpid_dest = dest.dpid().toString();
299
300 // Get the source vertex
301 Node v_src = shortestPathTopo.get(src.dpid().value());
302 if (v_src == null) {
303 return null; // Source vertex not found
304 }
305
306 // Get the destination vertex
307 Node v_dest = shortestPathTopo.get(dest.dpid().value());
308 if (v_dest == null) {
309 return null; // Destination vertex not found
310 }
311
312 //
313 // Test whether we are computing a path from/to the same DPID.
314 // If "yes", then just add a single flow entry in the return result.
315 //
316 if (dpid_src.equals(dpid_dest)) {
317 FlowEntry flowEntry = new FlowEntry();
318 flowEntry.setDpid(src.dpid());
319 flowEntry.setInPort(src.port());
320 flowEntry.setOutPort(dest.port());
321 result_data_path.flowEntries().add(flowEntry);
322 return result_data_path;
323 }
324
325 //
326 // Implement the Shortest Path computation by using Breath First Search
327 //
328 Set<Node> visitedSet = new HashSet<Node>();
329 Queue<Node> processingList = new LinkedList<Node>();
330 Map<Node, Node.Link> previousVertexMap = new HashMap<Node, Node.Link>();
331 processingList.add(v_src);
332 visitedSet.add(v_src);
333 Boolean path_found = false;
334 while (! processingList.isEmpty()) {
335 Node nextVertex = processingList.poll();
336 if (v_dest == nextVertex) {
337 path_found = true;
338 break;
339 }
340 for (Node.Link link : nextVertex.links) {
341 Node child = link.neighbor;
342 if (! visitedSet.contains(child)) {
343 previousVertexMap.put(child, link);
344 visitedSet.add(child);
345 processingList.add(child);
346 }
347 }
348 }
349 if (! path_found)
350 return null; // No path found
351
352 // Collect the path as a list of links
353 List<Node.Link> resultPath = new LinkedList<Node.Link>();
354 Node previousVertex = v_dest;
355 while (! v_src.equals(previousVertex)) {
356 Node.Link currentLink = previousVertexMap.get(previousVertex);
357 resultPath.add(currentLink);
358 previousVertex = currentLink.me;
359 }
360 Collections.reverse(resultPath);
361
362 //
363 // Loop through the result and prepare the return result
364 // as a list of Flow Entries.
365 //
366 Port inPort = new Port(src.port().value());
367 Port outPort;
368 for (Node.Link link: resultPath) {
369 // Setup the outgoing port, and add the Flow Entry
370 outPort = new Port(link.neighborPort);
371
372 FlowEntry flowEntry = new FlowEntry();
373 flowEntry.setDpid(new Dpid(link.me.nodeId));
374 flowEntry.setInPort(inPort);
375 flowEntry.setOutPort(outPort);
376 result_data_path.flowEntries().add(flowEntry);
377
378 // Setup the next incoming port
379 inPort = new Port(link.neighborPort);
380 }
381 if (resultPath.size() > 0) {
382 // Add the last Flow Entry
383 FlowEntry flowEntry = new FlowEntry();
384 flowEntry.setDpid(new Dpid(dest.dpid().value()));
385 flowEntry.setInPort(inPort);
386 flowEntry.setOutPort(dest.port());
387 result_data_path.flowEntries().add(flowEntry);
388 }
389
390 if (result_data_path.flowEntries().size() > 0)
391 return result_data_path;
392
393 return null;
394 }
395
396 /**
397 * Get the shortest path from a source to a destination.
398 *
399 * @param src the source in the shortest path computation.
400 * @param dest the destination in the shortest path computation.
401 * @return the data path with the computed shortest path if
402 * found, otherwise null.
403 */
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800404 @Override
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800405 public DataPath getShortestPath(SwitchPort src, SwitchPort dest) {
406 DataPath result_data_path = new DataPath();
407
408 // Initialize the source and destination in the data path to return
409 result_data_path.setSrcPort(src);
410 result_data_path.setDstPort(dest);
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800411
Pankaj Berde15193092013-03-21 17:30:14 -0700412 TitanGraph titanGraph = TitanFactory.open("/tmp/cassandra.titan");
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700413 TitanTransaction titanTransaction = titanGraph.startTransaction();
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800414
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800415 String dpid_src = src.dpid().toString();
416 String dpid_dest = dest.dpid().toString();
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800417
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800418
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800419 //
420 // Test whether we are computing a path from/to the same DPID.
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800421 // If "yes", then just add a single flow entry in the return result.
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800422 //
423 if (dpid_src.equals(dpid_dest)) {
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800424 FlowEntry flowEntry = new FlowEntry();
425 flowEntry.setDpid(src.dpid());
426 flowEntry.setInPort(src.port());
427 flowEntry.setOutPort(dest.port());
428 result_data_path.flowEntries().add(flowEntry);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700429 titanTransaction.stopTransaction(Conclusion.SUCCESS);
430 // titanTransaction.shutdown();
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
435 // Get the source vertex
436
437 ISwitchObject srcSwitch = conn.utils().searchSwitch(conn, dpid_src);
438 ISwitchObject destSwitch = conn.utils().searchSwitch(conn, dpid_dest);
439
440 if (srcSwitch == null || destSwitch == null) {
441 return null;
442 }
443
444
445 Vertex v_src = srcSwitch.asVertex();
446 Vertex v_dest = destSwitch.asVertex();
447
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700448 //
449 // Implement the Shortest Path computation by using Breath First Search
450 //
451 Set<Vertex> visitedSet = new HashSet<Vertex>();
452 Queue<Vertex> processingList = new LinkedList<Vertex>();
453 Map<Vertex, Vertex> previousVertexMap = new HashMap<Vertex, Vertex>();
454
455 processingList.add(v_src);
456 visitedSet.add(v_src);
457 Boolean path_found = false;
458 while (! processingList.isEmpty()) {
459 Vertex nextVertex = processingList.poll();
460 if (v_dest.equals(nextVertex)) {
461 path_found = true;
462 break;
463 }
464 for (Vertex parentPort : nextVertex.getVertices(Direction.OUT, "on")) {
465 for (Vertex childPort : parentPort.getVertices(Direction.OUT, "link")) {
466 for (Vertex child : childPort.getVertices(Direction.IN, "on")) {
467 if (! visitedSet.contains(child)) {
468 previousVertexMap.put(parentPort, nextVertex);
469 previousVertexMap.put(childPort, parentPort);
470 previousVertexMap.put(child, childPort);
471 visitedSet.add(child);
472 processingList.add(child);
473 }
474 }
475 }
476 }
477 }
478 if (! path_found)
479 return null; // No path found
480
481 List<Vertex> resultPath = new LinkedList<Vertex>();
482 Vertex previousVertex = v_dest;
483 resultPath.add(v_dest);
484 while (! v_src.equals(previousVertex)) {
485 Vertex currentVertex = previousVertexMap.get(previousVertex);
486 resultPath.add(currentVertex);
487 previousVertex = currentVertex;
488 }
489 Collections.reverse(resultPath);
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800490
Pankaj Berde15193092013-03-21 17:30:14 -0700491
492
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800493 //
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700494 // Loop through the result and prepare the return result
495 // as a list of Flow Entries.
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800496 //
497 long nodeId = 0;
498 short portId = 0;
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800499 Port inPort = new Port(src.port().value());
500 Port outPort = new Port();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700501 int idx = 0;
502 for (Vertex v: resultPath) {
503 String type = v.getProperty("type").toString();
504 // System.out.println("type: " + type);
505 if (type.equals("port")) {
506 String number = v.getProperty("number").toString();
507 // System.out.println("number: " + number);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800508
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700509 Object obj = v.getProperty("number");
510 // String class_str = obj.getClass().toString();
511 if (obj instanceof Short) {
512 portId = (Short)obj;
513 } else if (obj instanceof Integer) {
514 Integer int_nodeId = (Integer)obj;
515 portId = int_nodeId.shortValue();
516 // int int_nodeId = (Integer)obj;
517 // portId = (short)int_nodeId.;
518 }
519 } else if (type.equals("switch")) {
520 String dpid = v.getProperty("dpid").toString();
521 nodeId = HexString.toLong(dpid);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800522
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700523 // System.out.println("dpid: " + dpid);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800524 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700525 idx++;
526 if (idx == 1) {
527 continue;
528 }
529 int mod = idx % 3;
530 if (mod == 0) {
531 // Setup the incoming port
532 inPort = new Port(portId);
533 continue;
534 }
535 if (mod == 2) {
536 // Setup the outgoing port, and add the Flow Entry
537 outPort = new Port(portId);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800538
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800539 FlowEntry flowEntry = new FlowEntry();
540 flowEntry.setDpid(new Dpid(nodeId));
541 flowEntry.setInPort(inPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700542 flowEntry.setOutPort(outPort);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800543 result_data_path.flowEntries().add(flowEntry);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700544 continue;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800545 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800546 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700547 if (idx > 0) {
548 // Add the last Flow Entry
549 FlowEntry flowEntry = new FlowEntry();
550 flowEntry.setDpid(new Dpid(nodeId));
551 flowEntry.setInPort(inPort);
552 flowEntry.setOutPort(dest.port());
553 result_data_path.flowEntries().add(flowEntry);
554 }
555
556 titanTransaction.stopTransaction(Conclusion.SUCCESS);
557 // titanTransaction.shutdown();
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}