blob: 10bfff4c58853f33c72fb09cd33c66007f1f50f4 [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 {
43 class Link {
44 public Node me; // The node this link originates from
45 public Node neighbor; // The neighbor node on the other side
46 public short myPort; // Local port number for the link
47 public short neighborPort; // Neighbor port number for the link
48
49 /**
50 * Link constructor.
51 *
52 * @param me the node this link originates from.
53 * @param the neighbor node on the other side of the link.
54 * @param myPort local port number for the link.
55 * @param neighborPort neighrobr port number for the link.
56 */
57 public Link(Node me, Node neighbor, short myPort, short neighborPort) {
58 this.me = me;
59 this.neighbor = neighbor;
60 this.myPort = myPort;
61 this.neighborPort = neighborPort;
62 }
63 };
64
65 public long nodeId; // The node ID
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -070066 public HashMap<Short, Link> links; // The links originating from this node
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070067
68 /**
69 * Node constructor.
70 *
71 * @param nodeId the node ID.
72 */
73 public Node(long nodeId) {
74 this.nodeId = nodeId;
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -070075 links = new HashMap<Short, Link>();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070076 }
77
78 /**
79 * Add a neighbor.
80 *
81 * A new link to the neighbor will be created.
82 *
83 * @param neighbor the neighbor to add.
84 * @param myPort the local port number for the link to the neighbor.
85 * @param neighborPort the neighbor port number for the link.
86 */
87 public void addNeighbor(Node neighbor, short myPort, short neighborPort) {
88 Link link = new Link(this, neighbor, myPort, neighborPort);
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -070089 links.put(myPort, link);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070090 }
91};
92
Pankaj Berde15193092013-03-21 17:30:14 -070093
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080094public class TopoRouteService implements IFloodlightModule, ITopoRouteService {
95
96 /** The logger. */
Pavlin Radoslavov19343432013-03-06 10:43:18 -080097 private static Logger log =
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080098 LoggerFactory.getLogger(TopoRouteService.class);
Pankaj Berde15193092013-03-21 17:30:14 -070099
Toshio Koide18e47202013-06-13 14:07:13 -0700100 protected GraphDBOperation op;
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800101
102 @Override
103 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
104 Collection<Class<? extends IFloodlightService>> l =
105 new ArrayList<Class<? extends IFloodlightService>>();
106 l.add(ITopoRouteService.class);
107 return l;
108 }
109
110 @Override
111 public Map<Class<? extends IFloodlightService>, IFloodlightService>
112 getServiceImpls() {
113 Map<Class<? extends IFloodlightService>,
114 IFloodlightService> m =
115 new HashMap<Class<? extends IFloodlightService>,
116 IFloodlightService>();
117 m.put(ITopoRouteService.class, this);
118 return m;
119 }
120
121 @Override
122 public Collection<Class<? extends IFloodlightService>>
123 getModuleDependencies() {
124 Collection<Class<? extends IFloodlightService>> l =
125 new ArrayList<Class<? extends IFloodlightService>>();
126 // TODO: Add the appropriate dependencies
127 // l.add(IRestApiService.class);
128 return l;
129 }
130
131 @Override
132 public void init(FloodlightModuleContext context)
133 throws FloodlightModuleException {
134 // TODO: Add the appropriate initialization
Toshio Koidebfe9b922013-06-18 10:56:05 -0700135 op = new GraphDBOperation("");
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800136 }
137
138 @Override
139 public void startUp(FloodlightModuleContext context) {
140 // TODO: Add the approprate setup
141 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800142
Pavlin Radoslavovcec899a2013-06-27 15:47:50 -0700143 public void setDbOperationHandler(GraphDBOperation init_op) {
144 op = init_op;
145 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800146
Pavlin Radoslavovbfae5e02013-03-19 23:06:36 -0700147 static class ShortestPathLoopFunction implements PipeFunction<LoopBundle<Vertex>, Boolean> {
148 String dpid;
149 public ShortestPathLoopFunction(String dpid) {
150 super();
151 this.dpid = dpid;
152 }
153 public Boolean compute(LoopBundle<Vertex> bundle) {
154 Boolean output = false;
155 if (! bundle.getObject().getProperty("dpid").equals(dpid)) {
156 output = true;
157 }
158 return output;
159 }
160 }
161
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700162 /**
163 * Fetch the Switch and Ports info from the Titan Graph
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000164 * and return it for fast access during the shortest path
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700165 * computation.
166 *
167 * After fetching the state, method @ref getTopoShortestPath()
168 * can be used for fast shortest path computation.
169 *
170 * Note: There is certain cost to fetch the state, hence it should
171 * be used only when there is a large number of shortest path
172 * computations that need to be done on the same topology.
173 * Typically, a single call to @ref prepareShortestPathTopo()
174 * should be followed by a large number of calls to
175 * method @ref getTopoShortestPath().
176 * After the last @ref getTopoShortestPath() call,
177 * method @ref dropShortestPathTopo() should be used to release
178 * the internal state that is not needed anymore:
179 *
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000180 * Map<Long, ?> shortestPathTopo;
181 * shortestPathTopo = prepareShortestPathTopo();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700182 * for (int i = 0; i < 10000; i++) {
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000183 * dataPath = getTopoShortestPath(shortestPathTopo, ...);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700184 * ...
185 * }
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000186 * dropShortestPathTopo(shortestPathTopo);
187 *
188 * @return the Shortest Path info handler stored in a map.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700189 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000190 public Map<Long, ?> prepareShortestPathTopo() {
191 Map<Long, Node> shortestPathTopo = new HashMap<Long, Node>();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700192
193 //
194 // Fetch the relevant info from the Switch and Port vertices
195 // from the Titan Graph.
196 //
Toshio Koide18e47202013-06-13 14:07:13 -0700197 Iterable<ISwitchObject> nodes = op.getActiveSwitches();
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700198 for (ISwitchObject switchObj : nodes) {
199 Vertex nodeVertex = switchObj.asVertex();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700200 //
201 // The Switch info
202 //
203 String nodeDpid = nodeVertex.getProperty("dpid").toString();
204 long nodeId = HexString.toLong(nodeDpid);
205 Node me = shortestPathTopo.get(nodeId);
206 if (me == null) {
207 me = new Node(nodeId);
208 shortestPathTopo.put(nodeId, me);
209 }
210
211 //
212 // The local Port info
213 //
214 for (Vertex myPortVertex : nodeVertex.getVertices(Direction.OUT, "on")) {
215 short myPort = 0;
216 Object obj = myPortVertex.getProperty("number");
217 if (obj instanceof Short) {
218 myPort = (Short)obj;
219 } else if (obj instanceof Integer) {
220 Integer int_nodeId = (Integer)obj;
221 myPort = int_nodeId.shortValue();
222 }
223
224 //
225 // The neighbor Port info
226 //
227 for (Vertex neighborPortVertex : myPortVertex.getVertices(Direction.OUT, "link")) {
228 short neighborPort = 0;
229 obj = neighborPortVertex.getProperty("number");
230 if (obj instanceof Short) {
231 neighborPort = (Short)obj;
232 } else if (obj instanceof Integer) {
233 Integer int_nodeId = (Integer)obj;
234 neighborPort = int_nodeId.shortValue();
235 }
236 //
237 // The neighbor Switch info
238 //
239 for (Vertex neighborVertex : neighborPortVertex.getVertices(Direction.IN, "on")) {
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700240 // Ignore inactive switches
241 String state = neighborVertex.getProperty("state").toString();
242 if (! state.equals(SwitchState.ACTIVE.toString()))
243 continue;
244
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700245 String neighborDpid = neighborVertex.getProperty("dpid").toString();
246 long neighborId = HexString.toLong(neighborDpid);
247 Node neighbor = shortestPathTopo.get(neighborId);
248 if (neighbor == null) {
249 neighbor = new Node(neighborId);
250 shortestPathTopo.put(neighborId, neighbor);
251 }
252 me.addNeighbor(neighbor, myPort, neighborPort);
253 }
254 }
255 }
256 }
Toshio Koide18e47202013-06-13 14:07:13 -0700257 op.commit();
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000258
259 return shortestPathTopo;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700260 }
261
262 /**
263 * Release the state that was populated by
264 * method @ref prepareShortestPathTopo().
265 *
266 * See the documentation for method @ref prepareShortestPathTopo()
267 * for additional information and usage.
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000268 *
Pavlin Radoslavoved13a242013-06-20 17:37:20 -0700269 * @param shortestPathTopo the Shortest Path info handler to release.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700270 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000271 public void dropShortestPathTopo(Map<Long, ?> shortestPathTopo) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700272 shortestPathTopo = null;
273 }
274
275 /**
276 * Get the shortest path from a source to a destination by
277 * using the pre-populated local topology state prepared
278 * by method @ref prepareShortestPathTopo().
279 *
280 * See the documentation for method @ref prepareShortestPathTopo()
281 * for additional information and usage.
282 *
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000283 * @param shortestPathTopoHandler the Shortest Path info handler
284 * to use.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700285 * @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 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000290 public DataPath getTopoShortestPath(Map<Long, ?> shortestPathTopoHandler,
291 SwitchPort src, SwitchPort dest) {
292 @SuppressWarnings("unchecked")
293 Map<Long, Node> shortestPathTopo = (Map)shortestPathTopoHandler;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700294 DataPath result_data_path = new DataPath();
295
296 // Initialize the source and destination in the data path to return
297 result_data_path.setSrcPort(src);
298 result_data_path.setDstPort(dest);
299
300 String dpid_src = src.dpid().toString();
301 String dpid_dest = dest.dpid().toString();
302
303 // Get the source vertex
304 Node v_src = shortestPathTopo.get(src.dpid().value());
305 if (v_src == null) {
306 return null; // Source vertex not found
307 }
308
309 // Get the destination vertex
310 Node v_dest = shortestPathTopo.get(dest.dpid().value());
311 if (v_dest == null) {
312 return null; // Destination vertex not found
313 }
314
315 //
316 // Test whether we are computing a path from/to the same DPID.
317 // If "yes", then just add a single flow entry in the return result.
318 //
319 if (dpid_src.equals(dpid_dest)) {
320 FlowEntry flowEntry = new FlowEntry();
321 flowEntry.setDpid(src.dpid());
322 flowEntry.setInPort(src.port());
323 flowEntry.setOutPort(dest.port());
324 result_data_path.flowEntries().add(flowEntry);
325 return result_data_path;
326 }
327
328 //
329 // Implement the Shortest Path computation by using Breath First Search
330 //
331 Set<Node> visitedSet = new HashSet<Node>();
332 Queue<Node> processingList = new LinkedList<Node>();
333 Map<Node, Node.Link> previousVertexMap = new HashMap<Node, Node.Link>();
334 processingList.add(v_src);
335 visitedSet.add(v_src);
336 Boolean path_found = false;
337 while (! processingList.isEmpty()) {
338 Node nextVertex = processingList.poll();
339 if (v_dest == nextVertex) {
340 path_found = true;
341 break;
342 }
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -0700343 for (Node.Link link : nextVertex.links.values()) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700344 Node child = link.neighbor;
345 if (! visitedSet.contains(child)) {
346 previousVertexMap.put(child, link);
347 visitedSet.add(child);
348 processingList.add(child);
349 }
350 }
351 }
352 if (! path_found)
353 return null; // No path found
354
355 // Collect the path as a list of links
356 List<Node.Link> resultPath = new LinkedList<Node.Link>();
357 Node previousVertex = v_dest;
358 while (! v_src.equals(previousVertex)) {
359 Node.Link currentLink = previousVertexMap.get(previousVertex);
360 resultPath.add(currentLink);
361 previousVertex = currentLink.me;
362 }
363 Collections.reverse(resultPath);
364
365 //
366 // Loop through the result and prepare the return result
367 // as a list of Flow Entries.
368 //
369 Port inPort = new Port(src.port().value());
370 Port outPort;
371 for (Node.Link link: resultPath) {
372 // Setup the outgoing port, and add the Flow Entry
Pavlin Radoslavova1ff1192013-03-29 04:11:32 -0700373 outPort = new Port(link.myPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700374
375 FlowEntry flowEntry = new FlowEntry();
376 flowEntry.setDpid(new Dpid(link.me.nodeId));
377 flowEntry.setInPort(inPort);
378 flowEntry.setOutPort(outPort);
379 result_data_path.flowEntries().add(flowEntry);
380
381 // Setup the next incoming port
382 inPort = new Port(link.neighborPort);
383 }
384 if (resultPath.size() > 0) {
385 // Add the last Flow Entry
386 FlowEntry flowEntry = new FlowEntry();
387 flowEntry.setDpid(new Dpid(dest.dpid().value()));
388 flowEntry.setInPort(inPort);
389 flowEntry.setOutPort(dest.port());
390 result_data_path.flowEntries().add(flowEntry);
391 }
392
393 if (result_data_path.flowEntries().size() > 0)
394 return result_data_path;
395
396 return null;
397 }
398
399 /**
400 * Get the shortest path from a source to a destination.
401 *
402 * @param src the source in the shortest path computation.
403 * @param dest the destination in the shortest path computation.
404 * @return the data path with the computed shortest path if
405 * found, otherwise null.
406 */
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800407 @Override
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800408 public DataPath getShortestPath(SwitchPort src, SwitchPort dest) {
409 DataPath result_data_path = new DataPath();
410
411 // Initialize the source and destination in the data path to return
412 result_data_path.setSrcPort(src);
413 result_data_path.setDstPort(dest);
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 Radoslavov010f2862013-03-28 16:44:20 -0700418 // Get the source and destination switches
419 ISwitchObject srcSwitch =
Toshio Koide18e47202013-06-13 14:07:13 -0700420 op.searchActiveSwitch(dpid_src);
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700421 ISwitchObject destSwitch =
Toshio Koide18e47202013-06-13 14:07:13 -0700422 op.searchActiveSwitch(dpid_dest);
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700423 if (srcSwitch == null || destSwitch == null) {
424 return null;
425 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800426
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800427 //
428 // Test whether we are computing a path from/to the same DPID.
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800429 // If "yes", then just add a single flow entry in the return result.
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800430 //
431 if (dpid_src.equals(dpid_dest)) {
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800432 FlowEntry flowEntry = new FlowEntry();
433 flowEntry.setDpid(src.dpid());
434 flowEntry.setInPort(src.port());
435 flowEntry.setOutPort(dest.port());
436 result_data_path.flowEntries().add(flowEntry);
Toshio Koide18e47202013-06-13 14:07:13 -0700437 op.commit();
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800438 return result_data_path;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800439 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800440
Pankaj Berde15193092013-03-21 17:30:14 -0700441 Vertex v_src = srcSwitch.asVertex();
442 Vertex v_dest = destSwitch.asVertex();
443
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700444 //
445 // Implement the Shortest Path computation by using Breath First Search
446 //
447 Set<Vertex> visitedSet = new HashSet<Vertex>();
448 Queue<Vertex> processingList = new LinkedList<Vertex>();
449 Map<Vertex, Vertex> previousVertexMap = new HashMap<Vertex, Vertex>();
450
451 processingList.add(v_src);
452 visitedSet.add(v_src);
453 Boolean path_found = false;
454 while (! processingList.isEmpty()) {
455 Vertex nextVertex = processingList.poll();
456 if (v_dest.equals(nextVertex)) {
457 path_found = true;
458 break;
459 }
460 for (Vertex parentPort : nextVertex.getVertices(Direction.OUT, "on")) {
461 for (Vertex childPort : parentPort.getVertices(Direction.OUT, "link")) {
462 for (Vertex child : childPort.getVertices(Direction.IN, "on")) {
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700463 // Ignore inactive switches
464 String state = child.getProperty("state").toString();
465 if (! state.equals(SwitchState.ACTIVE.toString()))
466 continue;
467
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700468 if (! visitedSet.contains(child)) {
469 previousVertexMap.put(parentPort, nextVertex);
470 previousVertexMap.put(childPort, parentPort);
471 previousVertexMap.put(child, childPort);
472 visitedSet.add(child);
473 processingList.add(child);
474 }
475 }
476 }
477 }
478 }
479 if (! path_found)
480 return null; // No path found
481
482 List<Vertex> resultPath = new LinkedList<Vertex>();
483 Vertex previousVertex = v_dest;
484 resultPath.add(v_dest);
485 while (! v_src.equals(previousVertex)) {
486 Vertex currentVertex = previousVertexMap.get(previousVertex);
487 resultPath.add(currentVertex);
488 previousVertex = currentVertex;
489 }
490 Collections.reverse(resultPath);
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800491
Pankaj Berde15193092013-03-21 17:30:14 -0700492
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
Toshio Koide18e47202013-06-13 14:07:13 -0700556 op.commit();
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800557 if (result_data_path.flowEntries().size() > 0)
558 return result_data_path;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800559
560 return null;
561 }
562
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700563 /**
564 * Test whether a route exists from a source to a destination.
565 *
566 * @param src the source node for the test.
567 * @param dest the destination node for the test.
568 * @return true if a route exists, otherwise false.
569 */
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800570 @Override
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800571 public Boolean routeExists(SwitchPort src, SwitchPort dest) {
572 DataPath dataPath = getShortestPath(src, dest);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700573 return (dataPath != null);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800574 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800575}