blob: ca8d92fe6031d03132d260e08b901293d7938332 [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 Radoslavov010f2862013-03-28 16:44:20 -070016import net.floodlightcontroller.core.ISwitchStorage.SwitchState;
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080017import net.floodlightcontroller.core.module.FloodlightModuleContext;
18import net.floodlightcontroller.core.module.FloodlightModuleException;
19import net.floodlightcontroller.core.module.IFloodlightModule;
20import net.floodlightcontroller.core.module.IFloodlightService;
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;
Pankaj Berde15193092013-03-21 17:30:14 -070026import net.onrc.onos.util.GraphDBConnection;
Pavlin Radoslavov010f2862013-03-28 16:44:20 -070027import net.onrc.onos.util.GraphDBConnection.Transaction;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080028
29import org.openflow.util.HexString;
Pankaj Berde15193092013-03-21 17:30:14 -070030import org.slf4j.Logger;
31import org.slf4j.LoggerFactory;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080032
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070033import com.tinkerpop.blueprints.Direction;
Pavlin Radoslavov19343432013-03-06 10:43:18 -080034import com.tinkerpop.blueprints.TransactionalGraph.Conclusion;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080035import com.tinkerpop.blueprints.Vertex;
Pavlin Radoslavovbfae5e02013-03-19 23:06:36 -070036import com.tinkerpop.pipes.PipeFunction;
37import com.tinkerpop.pipes.branch.LoopPipe.LoopBundle;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080038
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070039
40/**
41 * A class for storing Node and Link information for fast computation
42 * of shortest paths.
43 */
44class Node {
45 class Link {
46 public Node me; // The node this link originates from
47 public Node neighbor; // The neighbor node on the other side
48 public short myPort; // Local port number for the link
49 public short neighborPort; // Neighbor port number for the link
50
51 /**
52 * Link constructor.
53 *
54 * @param me the node this link originates from.
55 * @param the neighbor node on the other side of the link.
56 * @param myPort local port number for the link.
57 * @param neighborPort neighrobr port number for the link.
58 */
59 public Link(Node me, Node neighbor, short myPort, short neighborPort) {
60 this.me = me;
61 this.neighbor = neighbor;
62 this.myPort = myPort;
63 this.neighborPort = neighborPort;
64 }
65 };
66
67 public long nodeId; // The node ID
68 public LinkedList<Link> links; // The links originating from this node
69
70 /**
71 * Node constructor.
72 *
73 * @param nodeId the node ID.
74 */
75 public Node(long nodeId) {
76 this.nodeId = nodeId;
77 links = new LinkedList<Link>();
78 }
79
80 /**
81 * Add a neighbor.
82 *
83 * A new link to the neighbor will be created.
84 *
85 * @param neighbor the neighbor to add.
86 * @param myPort the local port number for the link to the neighbor.
87 * @param neighborPort the neighbor port number for the link.
88 */
89 public void addNeighbor(Node neighbor, short myPort, short neighborPort) {
90 Link link = new Link(this, neighbor, myPort, neighborPort);
91 links.add(link);
92 }
93};
94
Pankaj Berde15193092013-03-21 17:30:14 -070095
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080096public class TopoRouteService implements IFloodlightModule, ITopoRouteService {
97
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
102 GraphDBConnection conn;
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800103
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700104 //
105 // Topology state for storing (on demand) Switch and Ports info for
106 // fast access during the shortest path computation.
107 // It is explicitly populated by method @ref prepareShortestPathTopo().
108 // See the documentation for that method for details.
109 //
110 HashMap<Long, Node> shortestPathTopo;
111
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800112 @Override
113 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
114 Collection<Class<? extends IFloodlightService>> l =
115 new ArrayList<Class<? extends IFloodlightService>>();
116 l.add(ITopoRouteService.class);
117 return l;
118 }
119
120 @Override
121 public Map<Class<? extends IFloodlightService>, IFloodlightService>
122 getServiceImpls() {
123 Map<Class<? extends IFloodlightService>,
124 IFloodlightService> m =
125 new HashMap<Class<? extends IFloodlightService>,
126 IFloodlightService>();
127 m.put(ITopoRouteService.class, this);
128 return m;
129 }
130
131 @Override
132 public Collection<Class<? extends IFloodlightService>>
133 getModuleDependencies() {
134 Collection<Class<? extends IFloodlightService>> l =
135 new ArrayList<Class<? extends IFloodlightService>>();
136 // TODO: Add the appropriate dependencies
137 // l.add(IRestApiService.class);
138 return l;
139 }
140
141 @Override
142 public void init(FloodlightModuleContext context)
143 throws FloodlightModuleException {
144 // TODO: Add the appropriate initialization
Pankaj Berde15193092013-03-21 17:30:14 -0700145 conn = GraphDBConnection.getInstance("");
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800146 }
147
148 @Override
149 public void startUp(FloodlightModuleContext context) {
150 // TODO: Add the approprate setup
151 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800152
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800153
Pavlin Radoslavovbfae5e02013-03-19 23:06:36 -0700154 static class ShortestPathLoopFunction implements PipeFunction<LoopBundle<Vertex>, Boolean> {
155 String dpid;
156 public ShortestPathLoopFunction(String dpid) {
157 super();
158 this.dpid = dpid;
159 }
160 public Boolean compute(LoopBundle<Vertex> bundle) {
161 Boolean output = false;
162 if (! bundle.getObject().getProperty("dpid").equals(dpid)) {
163 output = true;
164 }
165 return output;
166 }
167 }
168
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700169 /**
170 * Fetch the Switch and Ports info from the Titan Graph
171 * and store it locally for fast access during the shortest path
172 * computation.
173 *
174 * After fetching the state, method @ref getTopoShortestPath()
175 * can be used for fast shortest path computation.
176 *
177 * Note: There is certain cost to fetch the state, hence it should
178 * be used only when there is a large number of shortest path
179 * computations that need to be done on the same topology.
180 * Typically, a single call to @ref prepareShortestPathTopo()
181 * should be followed by a large number of calls to
182 * method @ref getTopoShortestPath().
183 * After the last @ref getTopoShortestPath() call,
184 * method @ref dropShortestPathTopo() should be used to release
185 * the internal state that is not needed anymore:
186 *
187 * prepareShortestPathTopo();
188 * for (int i = 0; i < 10000; i++) {
189 * dataPath = getTopoShortestPath(...);
190 * ...
191 * }
192 * dropShortestPathTopo();
193 */
Pankaj Berde15193092013-03-21 17:30:14 -0700194
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700195 public void prepareShortestPathTopo() {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700196 shortestPathTopo = new HashMap<Long, Node>();
197
198 //
199 // Fetch the relevant info from the Switch and Port vertices
200 // from the Titan Graph.
201 //
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700202 Iterable<ISwitchObject> nodes = conn.utils().getActiveSwitches(conn);
203 for (ISwitchObject switchObj : nodes) {
204 Vertex nodeVertex = switchObj.asVertex();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700205 //
206 // The Switch info
207 //
208 String nodeDpid = nodeVertex.getProperty("dpid").toString();
209 long nodeId = HexString.toLong(nodeDpid);
210 Node me = shortestPathTopo.get(nodeId);
211 if (me == null) {
212 me = new Node(nodeId);
213 shortestPathTopo.put(nodeId, me);
214 }
215
216 //
217 // The local Port info
218 //
219 for (Vertex myPortVertex : nodeVertex.getVertices(Direction.OUT, "on")) {
220 short myPort = 0;
221 Object obj = myPortVertex.getProperty("number");
222 if (obj instanceof Short) {
223 myPort = (Short)obj;
224 } else if (obj instanceof Integer) {
225 Integer int_nodeId = (Integer)obj;
226 myPort = int_nodeId.shortValue();
227 }
228
229 //
230 // The neighbor Port info
231 //
232 for (Vertex neighborPortVertex : myPortVertex.getVertices(Direction.OUT, "link")) {
233 short neighborPort = 0;
234 obj = neighborPortVertex.getProperty("number");
235 if (obj instanceof Short) {
236 neighborPort = (Short)obj;
237 } else if (obj instanceof Integer) {
238 Integer int_nodeId = (Integer)obj;
239 neighborPort = int_nodeId.shortValue();
240 }
241 //
242 // The neighbor Switch info
243 //
244 for (Vertex neighborVertex : neighborPortVertex.getVertices(Direction.IN, "on")) {
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700245 // Ignore inactive switches
246 String state = neighborVertex.getProperty("state").toString();
247 if (! state.equals(SwitchState.ACTIVE.toString()))
248 continue;
249
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700250 String neighborDpid = neighborVertex.getProperty("dpid").toString();
251 long neighborId = HexString.toLong(neighborDpid);
252 Node neighbor = shortestPathTopo.get(neighborId);
253 if (neighbor == null) {
254 neighbor = new Node(neighborId);
255 shortestPathTopo.put(neighborId, neighbor);
256 }
257 me.addNeighbor(neighbor, myPort, neighborPort);
258 }
259 }
260 }
261 }
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700262 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700263 }
264
265 /**
266 * Release the state that was populated by
267 * method @ref prepareShortestPathTopo().
268 *
269 * See the documentation for method @ref prepareShortestPathTopo()
270 * for additional information and usage.
271 */
Pankaj Berde15193092013-03-21 17:30:14 -0700272
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700273 public void dropShortestPathTopo() {
274 shortestPathTopo = null;
275 }
276
277 /**
278 * Get the shortest path from a source to a destination by
279 * using the pre-populated local topology state prepared
280 * by method @ref prepareShortestPathTopo().
281 *
282 * See the documentation for method @ref prepareShortestPathTopo()
283 * for additional information and usage.
284 *
285 * @param src the source in the shortest path computation.
286 * @param dest the destination in the shortest path computation.
287 * @return the data path with the computed shortest path if
288 * found, otherwise null.
289 */
Pankaj Berde15193092013-03-21 17:30:14 -0700290
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700291 public DataPath getTopoShortestPath(SwitchPort src, SwitchPort dest) {
292 DataPath result_data_path = new DataPath();
293
294 // Initialize the source and destination in the data path to return
295 result_data_path.setSrcPort(src);
296 result_data_path.setDstPort(dest);
297
298 String dpid_src = src.dpid().toString();
299 String dpid_dest = dest.dpid().toString();
300
301 // Get the source vertex
302 Node v_src = shortestPathTopo.get(src.dpid().value());
303 if (v_src == null) {
304 return null; // Source vertex not found
305 }
306
307 // Get the destination vertex
308 Node v_dest = shortestPathTopo.get(dest.dpid().value());
309 if (v_dest == null) {
310 return null; // Destination vertex not found
311 }
312
313 //
314 // Test whether we are computing a path from/to the same DPID.
315 // If "yes", then just add a single flow entry in the return result.
316 //
317 if (dpid_src.equals(dpid_dest)) {
318 FlowEntry flowEntry = new FlowEntry();
319 flowEntry.setDpid(src.dpid());
320 flowEntry.setInPort(src.port());
321 flowEntry.setOutPort(dest.port());
322 result_data_path.flowEntries().add(flowEntry);
323 return result_data_path;
324 }
325
326 //
327 // Implement the Shortest Path computation by using Breath First Search
328 //
329 Set<Node> visitedSet = new HashSet<Node>();
330 Queue<Node> processingList = new LinkedList<Node>();
331 Map<Node, Node.Link> previousVertexMap = new HashMap<Node, Node.Link>();
332 processingList.add(v_src);
333 visitedSet.add(v_src);
334 Boolean path_found = false;
335 while (! processingList.isEmpty()) {
336 Node nextVertex = processingList.poll();
337 if (v_dest == nextVertex) {
338 path_found = true;
339 break;
340 }
341 for (Node.Link link : nextVertex.links) {
342 Node child = link.neighbor;
343 if (! visitedSet.contains(child)) {
344 previousVertexMap.put(child, link);
345 visitedSet.add(child);
346 processingList.add(child);
347 }
348 }
349 }
350 if (! path_found)
351 return null; // No path found
352
353 // Collect the path as a list of links
354 List<Node.Link> resultPath = new LinkedList<Node.Link>();
355 Node previousVertex = v_dest;
356 while (! v_src.equals(previousVertex)) {
357 Node.Link currentLink = previousVertexMap.get(previousVertex);
358 resultPath.add(currentLink);
359 previousVertex = currentLink.me;
360 }
361 Collections.reverse(resultPath);
362
363 //
364 // Loop through the result and prepare the return result
365 // as a list of Flow Entries.
366 //
367 Port inPort = new Port(src.port().value());
368 Port outPort;
369 for (Node.Link link: resultPath) {
370 // Setup the outgoing port, and add the Flow Entry
Pavlin Radoslavova1ff1192013-03-29 04:11:32 -0700371 outPort = new Port(link.myPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700372
373 FlowEntry flowEntry = new FlowEntry();
374 flowEntry.setDpid(new Dpid(link.me.nodeId));
375 flowEntry.setInPort(inPort);
376 flowEntry.setOutPort(outPort);
377 result_data_path.flowEntries().add(flowEntry);
378
379 // Setup the next incoming port
380 inPort = new Port(link.neighborPort);
381 }
382 if (resultPath.size() > 0) {
383 // Add the last Flow Entry
384 FlowEntry flowEntry = new FlowEntry();
385 flowEntry.setDpid(new Dpid(dest.dpid().value()));
386 flowEntry.setInPort(inPort);
387 flowEntry.setOutPort(dest.port());
388 result_data_path.flowEntries().add(flowEntry);
389 }
390
391 if (result_data_path.flowEntries().size() > 0)
392 return result_data_path;
393
394 return null;
395 }
396
397 /**
398 * Get the shortest path from a source to a destination.
399 *
400 * @param src the source in the shortest path computation.
401 * @param dest the destination in the shortest path computation.
402 * @return the data path with the computed shortest path if
403 * found, otherwise null.
404 */
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800405 @Override
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800406 public DataPath getShortestPath(SwitchPort src, SwitchPort dest) {
407 DataPath result_data_path = new DataPath();
408
409 // Initialize the source and destination in the data path to return
410 result_data_path.setSrcPort(src);
411 result_data_path.setDstPort(dest);
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800412
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800413 String dpid_src = src.dpid().toString();
414 String dpid_dest = dest.dpid().toString();
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800415
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700416 // Get the source and destination switches
417 ISwitchObject srcSwitch =
418 conn.utils().searchActiveSwitch(conn, dpid_src);
419 ISwitchObject destSwitch =
420 conn.utils().searchActiveSwitch(conn, dpid_dest);
421 if (srcSwitch == null || destSwitch == null) {
422 return null;
423 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800424
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800425 //
426 // Test whether we are computing a path from/to the same DPID.
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800427 // If "yes", then just add a single flow entry in the return result.
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800428 //
429 if (dpid_src.equals(dpid_dest)) {
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800430 FlowEntry flowEntry = new FlowEntry();
431 flowEntry.setDpid(src.dpid());
432 flowEntry.setInPort(src.port());
433 flowEntry.setOutPort(dest.port());
434 result_data_path.flowEntries().add(flowEntry);
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700435 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800436 return result_data_path;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800437 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800438
Pankaj Berde15193092013-03-21 17:30:14 -0700439 Vertex v_src = srcSwitch.asVertex();
440 Vertex v_dest = destSwitch.asVertex();
441
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700442 //
443 // Implement the Shortest Path computation by using Breath First Search
444 //
445 Set<Vertex> visitedSet = new HashSet<Vertex>();
446 Queue<Vertex> processingList = new LinkedList<Vertex>();
447 Map<Vertex, Vertex> previousVertexMap = new HashMap<Vertex, Vertex>();
448
449 processingList.add(v_src);
450 visitedSet.add(v_src);
451 Boolean path_found = false;
452 while (! processingList.isEmpty()) {
453 Vertex nextVertex = processingList.poll();
454 if (v_dest.equals(nextVertex)) {
455 path_found = true;
456 break;
457 }
458 for (Vertex parentPort : nextVertex.getVertices(Direction.OUT, "on")) {
459 for (Vertex childPort : parentPort.getVertices(Direction.OUT, "link")) {
460 for (Vertex child : childPort.getVertices(Direction.IN, "on")) {
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700461 // Ignore inactive switches
462 String state = child.getProperty("state").toString();
463 if (! state.equals(SwitchState.ACTIVE.toString()))
464 continue;
465
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700466 if (! visitedSet.contains(child)) {
467 previousVertexMap.put(parentPort, nextVertex);
468 previousVertexMap.put(childPort, parentPort);
469 previousVertexMap.put(child, childPort);
470 visitedSet.add(child);
471 processingList.add(child);
472 }
473 }
474 }
475 }
476 }
477 if (! path_found)
478 return null; // No path found
479
480 List<Vertex> resultPath = new LinkedList<Vertex>();
481 Vertex previousVertex = v_dest;
482 resultPath.add(v_dest);
483 while (! v_src.equals(previousVertex)) {
484 Vertex currentVertex = previousVertexMap.get(previousVertex);
485 resultPath.add(currentVertex);
486 previousVertex = currentVertex;
487 }
488 Collections.reverse(resultPath);
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800489
Pankaj Berde15193092013-03-21 17:30:14 -0700490
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800491 //
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700492 // Loop through the result and prepare the return result
493 // as a list of Flow Entries.
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800494 //
495 long nodeId = 0;
496 short portId = 0;
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800497 Port inPort = new Port(src.port().value());
498 Port outPort = new Port();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700499 int idx = 0;
500 for (Vertex v: resultPath) {
501 String type = v.getProperty("type").toString();
502 // System.out.println("type: " + type);
503 if (type.equals("port")) {
504 String number = v.getProperty("number").toString();
505 // System.out.println("number: " + number);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800506
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700507 Object obj = v.getProperty("number");
508 // String class_str = obj.getClass().toString();
509 if (obj instanceof Short) {
510 portId = (Short)obj;
511 } else if (obj instanceof Integer) {
512 Integer int_nodeId = (Integer)obj;
513 portId = int_nodeId.shortValue();
514 // int int_nodeId = (Integer)obj;
515 // portId = (short)int_nodeId.;
516 }
517 } else if (type.equals("switch")) {
518 String dpid = v.getProperty("dpid").toString();
519 nodeId = HexString.toLong(dpid);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800520
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700521 // System.out.println("dpid: " + dpid);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800522 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700523 idx++;
524 if (idx == 1) {
525 continue;
526 }
527 int mod = idx % 3;
528 if (mod == 0) {
529 // Setup the incoming port
530 inPort = new Port(portId);
531 continue;
532 }
533 if (mod == 2) {
534 // Setup the outgoing port, and add the Flow Entry
535 outPort = new Port(portId);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800536
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800537 FlowEntry flowEntry = new FlowEntry();
538 flowEntry.setDpid(new Dpid(nodeId));
539 flowEntry.setInPort(inPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700540 flowEntry.setOutPort(outPort);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800541 result_data_path.flowEntries().add(flowEntry);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700542 continue;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800543 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800544 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700545 if (idx > 0) {
546 // Add the last Flow Entry
547 FlowEntry flowEntry = new FlowEntry();
548 flowEntry.setDpid(new Dpid(nodeId));
549 flowEntry.setInPort(inPort);
550 flowEntry.setOutPort(dest.port());
551 result_data_path.flowEntries().add(flowEntry);
552 }
553
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700554 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800555 if (result_data_path.flowEntries().size() > 0)
556 return result_data_path;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800557
558 return null;
559 }
560
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700561 /**
562 * Test whether a route exists from a source to a destination.
563 *
564 * @param src the source node for the test.
565 * @param dest the destination node for the test.
566 * @return true if a route exists, otherwise false.
567 */
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800568 @Override
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800569 public Boolean routeExists(SwitchPort src, SwitchPort dest) {
570 DataPath dataPath = getShortestPath(src, dest);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700571 return (dataPath != null);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800572 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800573}