blob: e23baf4c94eabc0ccfaf3f30c77001c6603f6396 [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 Radoslavov382b22a2013-01-28 09:24:04 -08008import java.util.Iterator;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -07009import java.util.LinkedList;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080010import java.util.List;
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080011import java.util.Map;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070012import java.util.Queue;
13import java.util.Set;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080014
15import net.floodlightcontroller.core.internal.SwitchStorageImpl;
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 Radoslavov382b22a2013-01-28 09:24:04 -080020import net.floodlightcontroller.core.INetMapTopologyService.ITopoRouteService;
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -080021import net.floodlightcontroller.util.DataPath;
22import net.floodlightcontroller.util.Dpid;
23import net.floodlightcontroller.util.FlowEntry;
24import net.floodlightcontroller.util.Port;
25import net.floodlightcontroller.util.SwitchPort;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080026
27import org.openflow.util.HexString;
28
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080029import com.thinkaurelius.titan.core.TitanGraph;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070030import com.thinkaurelius.titan.core.TitanTransaction;
31import com.tinkerpop.blueprints.Direction;
Pavlin Radoslavov19343432013-03-06 10:43:18 -080032import com.tinkerpop.blueprints.TransactionalGraph.Conclusion;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080033import com.tinkerpop.blueprints.Vertex;
Pavlin Radoslavovbfae5e02013-03-19 23:06:36 -070034import com.tinkerpop.gremlin.java.GremlinPipeline;
35import com.tinkerpop.pipes.PipeFunction;
36import com.tinkerpop.pipes.branch.LoopPipe.LoopBundle;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080037
38import javax.script.ScriptContext;
39import javax.script.ScriptEngine;
40import javax.script.ScriptException;
41import com.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine;
42
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080043import org.slf4j.Logger;
44import org.slf4j.LoggerFactory;
45
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070046
47/**
48 * A class for storing Node and Link information for fast computation
49 * of shortest paths.
50 */
51class Node {
52 class Link {
53 public Node me; // The node this link originates from
54 public Node neighbor; // The neighbor node on the other side
55 public short myPort; // Local port number for the link
56 public short neighborPort; // Neighbor port number for the link
57
58 /**
59 * Link constructor.
60 *
61 * @param me the node this link originates from.
62 * @param the neighbor node on the other side of the link.
63 * @param myPort local port number for the link.
64 * @param neighborPort neighrobr port number for the link.
65 */
66 public Link(Node me, Node neighbor, short myPort, short neighborPort) {
67 this.me = me;
68 this.neighbor = neighbor;
69 this.myPort = myPort;
70 this.neighborPort = neighborPort;
71 }
72 };
73
74 public long nodeId; // The node ID
75 public LinkedList<Link> links; // The links originating from this node
76
77 /**
78 * Node constructor.
79 *
80 * @param nodeId the node ID.
81 */
82 public Node(long nodeId) {
83 this.nodeId = nodeId;
84 links = new LinkedList<Link>();
85 }
86
87 /**
88 * Add a neighbor.
89 *
90 * A new link to the neighbor will be created.
91 *
92 * @param neighbor the neighbor to add.
93 * @param myPort the local port number for the link to the neighbor.
94 * @param neighborPort the neighbor port number for the link.
95 */
96 public void addNeighbor(Node neighbor, short myPort, short neighborPort) {
97 Link link = new Link(this, neighbor, myPort, neighborPort);
98 links.add(link);
99 }
100};
101
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800102public class TopoRouteService implements IFloodlightModule, ITopoRouteService {
103
104 /** The logger. */
Pavlin Radoslavov19343432013-03-06 10:43:18 -0800105 private static Logger log =
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800106 LoggerFactory.getLogger(TopoRouteService.class);
107
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700108 //
109 // Topology state for storing (on demand) Switch and Ports info for
110 // fast access during the shortest path computation.
111 // It is explicitly populated by method @ref prepareShortestPathTopo().
112 // See the documentation for that method for details.
113 //
114 HashMap<Long, Node> shortestPathTopo;
115
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800116 @Override
117 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
118 Collection<Class<? extends IFloodlightService>> l =
119 new ArrayList<Class<? extends IFloodlightService>>();
120 l.add(ITopoRouteService.class);
121 return l;
122 }
123
124 @Override
125 public Map<Class<? extends IFloodlightService>, IFloodlightService>
126 getServiceImpls() {
127 Map<Class<? extends IFloodlightService>,
128 IFloodlightService> m =
129 new HashMap<Class<? extends IFloodlightService>,
130 IFloodlightService>();
131 m.put(ITopoRouteService.class, this);
132 return m;
133 }
134
135 @Override
136 public Collection<Class<? extends IFloodlightService>>
137 getModuleDependencies() {
138 Collection<Class<? extends IFloodlightService>> l =
139 new ArrayList<Class<? extends IFloodlightService>>();
140 // TODO: Add the appropriate dependencies
141 // l.add(IRestApiService.class);
142 return l;
143 }
144
145 @Override
146 public void init(FloodlightModuleContext context)
147 throws FloodlightModuleException {
148 // TODO: Add the appropriate initialization
149 }
150
151 @Override
152 public void startUp(FloodlightModuleContext context) {
153 // TODO: Add the approprate setup
154 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800155
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800156 ThreadLocal<SwitchStorageImpl> store = new ThreadLocal<SwitchStorageImpl>() {
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800157 @Override
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800158 protected SwitchStorageImpl initialValue() {
159 SwitchStorageImpl swStore = new SwitchStorageImpl();
160 // NOTE: This is the file path from global properties
161 swStore.init("/tmp/cassandra.titan");
162 return swStore;
163 }
164 };
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800165
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800166 SwitchStorageImpl swStore = store.get();
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800167
Pavlin Radoslavovbfae5e02013-03-19 23:06:36 -0700168 static class ShortestPathLoopFunction implements PipeFunction<LoopBundle<Vertex>, Boolean> {
169 String dpid;
170 public ShortestPathLoopFunction(String dpid) {
171 super();
172 this.dpid = dpid;
173 }
174 public Boolean compute(LoopBundle<Vertex> bundle) {
175 Boolean output = false;
176 if (! bundle.getObject().getProperty("dpid").equals(dpid)) {
177 output = true;
178 }
179 return output;
180 }
181 }
182
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700183 /**
184 * Fetch the Switch and Ports info from the Titan Graph
185 * and store it locally for fast access during the shortest path
186 * 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 *
201 * prepareShortestPathTopo();
202 * for (int i = 0; i < 10000; i++) {
203 * dataPath = getTopoShortestPath(...);
204 * ...
205 * }
206 * dropShortestPathTopo();
207 */
208 @Override
209 public void prepareShortestPathTopo() {
210 TitanGraph titanGraph = swStore.graph;
211 TitanTransaction titanTransaction = titanGraph.startTransaction();
212 shortestPathTopo = new HashMap<Long, Node>();
213
214 //
215 // Fetch the relevant info from the Switch and Port vertices
216 // from the Titan Graph.
217 //
218 Iterable<Vertex> nodes = titanTransaction.getVertices("type", "switch");
219 for (Vertex nodeVertex : nodes) {
220 //
221 // The Switch info
222 //
223 String nodeDpid = nodeVertex.getProperty("dpid").toString();
224 long nodeId = HexString.toLong(nodeDpid);
225 Node me = shortestPathTopo.get(nodeId);
226 if (me == null) {
227 me = new Node(nodeId);
228 shortestPathTopo.put(nodeId, me);
229 }
230
231 //
232 // The local Port info
233 //
234 for (Vertex myPortVertex : nodeVertex.getVertices(Direction.OUT, "on")) {
235 short myPort = 0;
236 Object obj = myPortVertex.getProperty("number");
237 if (obj instanceof Short) {
238 myPort = (Short)obj;
239 } else if (obj instanceof Integer) {
240 Integer int_nodeId = (Integer)obj;
241 myPort = int_nodeId.shortValue();
242 }
243
244 //
245 // The neighbor Port info
246 //
247 for (Vertex neighborPortVertex : myPortVertex.getVertices(Direction.OUT, "link")) {
248 short neighborPort = 0;
249 obj = neighborPortVertex.getProperty("number");
250 if (obj instanceof Short) {
251 neighborPort = (Short)obj;
252 } else if (obj instanceof Integer) {
253 Integer int_nodeId = (Integer)obj;
254 neighborPort = int_nodeId.shortValue();
255 }
256 //
257 // The neighbor Switch info
258 //
259 for (Vertex neighborVertex : neighborPortVertex.getVertices(Direction.IN, "on")) {
260 String neighborDpid = neighborVertex.getProperty("dpid").toString();
261 long neighborId = HexString.toLong(neighborDpid);
262 Node neighbor = shortestPathTopo.get(neighborId);
263 if (neighbor == null) {
264 neighbor = new Node(neighborId);
265 shortestPathTopo.put(neighborId, neighbor);
266 }
267 me.addNeighbor(neighbor, myPort, neighborPort);
268 }
269 }
270 }
271 }
272
273 titanTransaction.stopTransaction(Conclusion.SUCCESS);
274 }
275
276 /**
277 * Release the state that was populated by
278 * method @ref prepareShortestPathTopo().
279 *
280 * See the documentation for method @ref prepareShortestPathTopo()
281 * for additional information and usage.
282 */
283 @Override
284 public void dropShortestPathTopo() {
285 shortestPathTopo = null;
286 }
287
288 /**
289 * Get the shortest path from a source to a destination by
290 * using the pre-populated local topology state prepared
291 * by method @ref prepareShortestPathTopo().
292 *
293 * See the documentation for method @ref prepareShortestPathTopo()
294 * for additional information and usage.
295 *
296 * @param src the source in the shortest path computation.
297 * @param dest the destination in the shortest path computation.
298 * @return the data path with the computed shortest path if
299 * found, otherwise null.
300 */
301 @Override
302 public DataPath getTopoShortestPath(SwitchPort src, SwitchPort dest) {
303 DataPath result_data_path = new DataPath();
304
305 // Initialize the source and destination in the data path to return
306 result_data_path.setSrcPort(src);
307 result_data_path.setDstPort(dest);
308
309 String dpid_src = src.dpid().toString();
310 String dpid_dest = dest.dpid().toString();
311
312 // Get the source vertex
313 Node v_src = shortestPathTopo.get(src.dpid().value());
314 if (v_src == null) {
315 return null; // Source vertex not found
316 }
317
318 // Get the destination vertex
319 Node v_dest = shortestPathTopo.get(dest.dpid().value());
320 if (v_dest == null) {
321 return null; // Destination vertex not found
322 }
323
324 //
325 // Test whether we are computing a path from/to the same DPID.
326 // If "yes", then just add a single flow entry in the return result.
327 //
328 if (dpid_src.equals(dpid_dest)) {
329 FlowEntry flowEntry = new FlowEntry();
330 flowEntry.setDpid(src.dpid());
331 flowEntry.setInPort(src.port());
332 flowEntry.setOutPort(dest.port());
333 result_data_path.flowEntries().add(flowEntry);
334 return result_data_path;
335 }
336
337 //
338 // Implement the Shortest Path computation by using Breath First Search
339 //
340 Set<Node> visitedSet = new HashSet<Node>();
341 Queue<Node> processingList = new LinkedList<Node>();
342 Map<Node, Node.Link> previousVertexMap = new HashMap<Node, Node.Link>();
343 processingList.add(v_src);
344 visitedSet.add(v_src);
345 Boolean path_found = false;
346 while (! processingList.isEmpty()) {
347 Node nextVertex = processingList.poll();
348 if (v_dest == nextVertex) {
349 path_found = true;
350 break;
351 }
352 for (Node.Link link : nextVertex.links) {
353 Node child = link.neighbor;
354 if (! visitedSet.contains(child)) {
355 previousVertexMap.put(child, link);
356 visitedSet.add(child);
357 processingList.add(child);
358 }
359 }
360 }
361 if (! path_found)
362 return null; // No path found
363
364 // Collect the path as a list of links
365 List<Node.Link> resultPath = new LinkedList<Node.Link>();
366 Node previousVertex = v_dest;
367 while (! v_src.equals(previousVertex)) {
368 Node.Link currentLink = previousVertexMap.get(previousVertex);
369 resultPath.add(currentLink);
370 previousVertex = currentLink.me;
371 }
372 Collections.reverse(resultPath);
373
374 //
375 // Loop through the result and prepare the return result
376 // as a list of Flow Entries.
377 //
378 Port inPort = new Port(src.port().value());
379 Port outPort;
380 for (Node.Link link: resultPath) {
381 // Setup the outgoing port, and add the Flow Entry
382 outPort = new Port(link.neighborPort);
383
384 FlowEntry flowEntry = new FlowEntry();
385 flowEntry.setDpid(new Dpid(link.me.nodeId));
386 flowEntry.setInPort(inPort);
387 flowEntry.setOutPort(outPort);
388 result_data_path.flowEntries().add(flowEntry);
389
390 // Setup the next incoming port
391 inPort = new Port(link.neighborPort);
392 }
393 if (resultPath.size() > 0) {
394 // Add the last Flow Entry
395 FlowEntry flowEntry = new FlowEntry();
396 flowEntry.setDpid(new Dpid(dest.dpid().value()));
397 flowEntry.setInPort(inPort);
398 flowEntry.setOutPort(dest.port());
399 result_data_path.flowEntries().add(flowEntry);
400 }
401
402 if (result_data_path.flowEntries().size() > 0)
403 return result_data_path;
404
405 return null;
406 }
407
408 /**
409 * Get the shortest path from a source to a destination.
410 *
411 * @param src the source in the shortest path computation.
412 * @param dest the destination in the shortest path computation.
413 * @return the data path with the computed shortest path if
414 * found, otherwise null.
415 */
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800416 @Override
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800417 public DataPath getShortestPath(SwitchPort src, SwitchPort dest) {
418 DataPath result_data_path = new DataPath();
419
420 // Initialize the source and destination in the data path to return
421 result_data_path.setSrcPort(src);
422 result_data_path.setDstPort(dest);
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800423
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800424 TitanGraph titanGraph = swStore.graph;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700425 TitanTransaction titanTransaction = titanGraph.startTransaction();
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800426
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800427 String dpid_src = src.dpid().toString();
428 String dpid_dest = dest.dpid().toString();
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800429
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800430 // Get the source vertex
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700431 Iterator<Vertex> iter = titanTransaction.getVertices("dpid", dpid_src).iterator();
Pavlin Radoslavov19343432013-03-06 10:43:18 -0800432 if (! iter.hasNext()) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700433 titanTransaction.stopTransaction(Conclusion.SUCCESS);
434 // titanTransaction.shutdown();
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800435 return null; // Source vertex not found
Pavlin Radoslavov19343432013-03-06 10:43:18 -0800436 }
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800437 Vertex v_src = iter.next();
Pavlin Radoslavov2f686c52013-02-13 11:27:13 -0800438
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800439 // Get the destination vertex
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700440 iter = titanTransaction.getVertices("dpid", dpid_dest).iterator();
Pavlin Radoslavov19343432013-03-06 10:43:18 -0800441 if (! iter.hasNext()) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700442 titanTransaction.stopTransaction(Conclusion.SUCCESS);
443 // titanTransaction.shutdown();
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800444 return null; // Destination vertex not found
Pavlin Radoslavov19343432013-03-06 10:43:18 -0800445 }
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800446 Vertex v_dest = iter.next();
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);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700458 titanTransaction.stopTransaction(Conclusion.SUCCESS);
459 // titanTransaction.shutdown();
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800460 return result_data_path;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800461 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800462
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700463 //
464 // Implement the Shortest Path computation by using Breath First Search
465 //
466 Set<Vertex> visitedSet = new HashSet<Vertex>();
467 Queue<Vertex> processingList = new LinkedList<Vertex>();
468 Map<Vertex, Vertex> previousVertexMap = new HashMap<Vertex, Vertex>();
469
470 processingList.add(v_src);
471 visitedSet.add(v_src);
472 Boolean path_found = false;
473 while (! processingList.isEmpty()) {
474 Vertex nextVertex = processingList.poll();
475 if (v_dest.equals(nextVertex)) {
476 path_found = true;
477 break;
478 }
479 for (Vertex parentPort : nextVertex.getVertices(Direction.OUT, "on")) {
480 for (Vertex childPort : parentPort.getVertices(Direction.OUT, "link")) {
481 for (Vertex child : childPort.getVertices(Direction.IN, "on")) {
482 if (! visitedSet.contains(child)) {
483 previousVertexMap.put(parentPort, nextVertex);
484 previousVertexMap.put(childPort, parentPort);
485 previousVertexMap.put(child, childPort);
486 visitedSet.add(child);
487 processingList.add(child);
488 }
489 }
490 }
491 }
492 }
493 if (! path_found)
494 return null; // No path found
495
496 List<Vertex> resultPath = new LinkedList<Vertex>();
497 Vertex previousVertex = v_dest;
498 resultPath.add(v_dest);
499 while (! v_src.equals(previousVertex)) {
500 Vertex currentVertex = previousVertexMap.get(previousVertex);
501 resultPath.add(currentVertex);
502 previousVertex = currentVertex;
503 }
504 Collections.reverse(resultPath);
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800505
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800506 //
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700507 // Loop through the result and prepare the return result
508 // as a list of Flow Entries.
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800509 //
510 long nodeId = 0;
511 short portId = 0;
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800512 Port inPort = new Port(src.port().value());
513 Port outPort = new Port();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700514 int idx = 0;
515 for (Vertex v: resultPath) {
516 String type = v.getProperty("type").toString();
517 // System.out.println("type: " + type);
518 if (type.equals("port")) {
519 String number = v.getProperty("number").toString();
520 // System.out.println("number: " + number);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800521
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700522 Object obj = v.getProperty("number");
523 // String class_str = obj.getClass().toString();
524 if (obj instanceof Short) {
525 portId = (Short)obj;
526 } else if (obj instanceof Integer) {
527 Integer int_nodeId = (Integer)obj;
528 portId = int_nodeId.shortValue();
529 // int int_nodeId = (Integer)obj;
530 // portId = (short)int_nodeId.;
531 }
532 } else if (type.equals("switch")) {
533 String dpid = v.getProperty("dpid").toString();
534 nodeId = HexString.toLong(dpid);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800535
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700536 // System.out.println("dpid: " + dpid);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800537 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700538 idx++;
539 if (idx == 1) {
540 continue;
541 }
542 int mod = idx % 3;
543 if (mod == 0) {
544 // Setup the incoming port
545 inPort = new Port(portId);
546 continue;
547 }
548 if (mod == 2) {
549 // Setup the outgoing port, and add the Flow Entry
550 outPort = new Port(portId);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800551
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800552 FlowEntry flowEntry = new FlowEntry();
553 flowEntry.setDpid(new Dpid(nodeId));
554 flowEntry.setInPort(inPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700555 flowEntry.setOutPort(outPort);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800556 result_data_path.flowEntries().add(flowEntry);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700557 continue;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800558 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800559 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700560 if (idx > 0) {
561 // Add the last Flow Entry
562 FlowEntry flowEntry = new FlowEntry();
563 flowEntry.setDpid(new Dpid(nodeId));
564 flowEntry.setInPort(inPort);
565 flowEntry.setOutPort(dest.port());
566 result_data_path.flowEntries().add(flowEntry);
567 }
568
569 titanTransaction.stopTransaction(Conclusion.SUCCESS);
570 // titanTransaction.shutdown();
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800571 if (result_data_path.flowEntries().size() > 0)
572 return result_data_path;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800573
574 return null;
575 }
576
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700577 /**
578 * Test whether a route exists from a source to a destination.
579 *
580 * @param src the source node for the test.
581 * @param dest the destination node for the test.
582 * @return true if a route exists, otherwise false.
583 */
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800584 @Override
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800585 public Boolean routeExists(SwitchPort src, SwitchPort dest) {
586 DataPath dataPath = getShortestPath(src, dest);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700587 return (dataPath != null);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800588 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800589}