blob: 432e5782dea330f02bbe70140e8fbeecc1f17720 [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 Radoslavov382b22a2013-01-28 09:24:04 -0800143
Pavlin Radoslavovbfae5e02013-03-19 23:06:36 -0700144 static class ShortestPathLoopFunction implements PipeFunction<LoopBundle<Vertex>, Boolean> {
145 String dpid;
146 public ShortestPathLoopFunction(String dpid) {
147 super();
148 this.dpid = dpid;
149 }
150 public Boolean compute(LoopBundle<Vertex> bundle) {
151 Boolean output = false;
152 if (! bundle.getObject().getProperty("dpid").equals(dpid)) {
153 output = true;
154 }
155 return output;
156 }
157 }
158
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700159 /**
160 * Fetch the Switch and Ports info from the Titan Graph
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000161 * and return it for fast access during the shortest path
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700162 * computation.
163 *
164 * After fetching the state, method @ref getTopoShortestPath()
165 * can be used for fast shortest path computation.
166 *
167 * Note: There is certain cost to fetch the state, hence it should
168 * be used only when there is a large number of shortest path
169 * computations that need to be done on the same topology.
170 * Typically, a single call to @ref prepareShortestPathTopo()
171 * should be followed by a large number of calls to
172 * method @ref getTopoShortestPath().
173 * After the last @ref getTopoShortestPath() call,
174 * method @ref dropShortestPathTopo() should be used to release
175 * the internal state that is not needed anymore:
176 *
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000177 * Map<Long, ?> shortestPathTopo;
178 * shortestPathTopo = prepareShortestPathTopo();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700179 * for (int i = 0; i < 10000; i++) {
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000180 * dataPath = getTopoShortestPath(shortestPathTopo, ...);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700181 * ...
182 * }
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000183 * dropShortestPathTopo(shortestPathTopo);
184 *
185 * @return the Shortest Path info handler stored in a map.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700186 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000187 public Map<Long, ?> prepareShortestPathTopo() {
188 Map<Long, Node> shortestPathTopo = new HashMap<Long, Node>();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700189
190 //
191 // Fetch the relevant info from the Switch and Port vertices
192 // from the Titan Graph.
193 //
Toshio Koide18e47202013-06-13 14:07:13 -0700194 Iterable<ISwitchObject> nodes = op.getActiveSwitches();
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700195 for (ISwitchObject switchObj : nodes) {
196 Vertex nodeVertex = switchObj.asVertex();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700197 //
198 // The Switch info
199 //
200 String nodeDpid = nodeVertex.getProperty("dpid").toString();
201 long nodeId = HexString.toLong(nodeDpid);
202 Node me = shortestPathTopo.get(nodeId);
203 if (me == null) {
204 me = new Node(nodeId);
205 shortestPathTopo.put(nodeId, me);
206 }
207
208 //
209 // The local Port info
210 //
211 for (Vertex myPortVertex : nodeVertex.getVertices(Direction.OUT, "on")) {
212 short myPort = 0;
213 Object obj = myPortVertex.getProperty("number");
214 if (obj instanceof Short) {
215 myPort = (Short)obj;
216 } else if (obj instanceof Integer) {
217 Integer int_nodeId = (Integer)obj;
218 myPort = int_nodeId.shortValue();
219 }
220
221 //
222 // The neighbor Port info
223 //
224 for (Vertex neighborPortVertex : myPortVertex.getVertices(Direction.OUT, "link")) {
225 short neighborPort = 0;
226 obj = neighborPortVertex.getProperty("number");
227 if (obj instanceof Short) {
228 neighborPort = (Short)obj;
229 } else if (obj instanceof Integer) {
230 Integer int_nodeId = (Integer)obj;
231 neighborPort = int_nodeId.shortValue();
232 }
233 //
234 // The neighbor Switch info
235 //
236 for (Vertex neighborVertex : neighborPortVertex.getVertices(Direction.IN, "on")) {
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700237 // Ignore inactive switches
238 String state = neighborVertex.getProperty("state").toString();
239 if (! state.equals(SwitchState.ACTIVE.toString()))
240 continue;
241
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700242 String neighborDpid = neighborVertex.getProperty("dpid").toString();
243 long neighborId = HexString.toLong(neighborDpid);
244 Node neighbor = shortestPathTopo.get(neighborId);
245 if (neighbor == null) {
246 neighbor = new Node(neighborId);
247 shortestPathTopo.put(neighborId, neighbor);
248 }
249 me.addNeighbor(neighbor, myPort, neighborPort);
250 }
251 }
252 }
253 }
Toshio Koide18e47202013-06-13 14:07:13 -0700254 op.commit();
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000255
256 return shortestPathTopo;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700257 }
258
259 /**
260 * Release the state that was populated by
261 * method @ref prepareShortestPathTopo().
262 *
263 * See the documentation for method @ref prepareShortestPathTopo()
264 * for additional information and usage.
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000265 *
Pavlin Radoslavoved13a242013-06-20 17:37:20 -0700266 * @param shortestPathTopo the Shortest Path info handler to release.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700267 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000268 public void dropShortestPathTopo(Map<Long, ?> shortestPathTopo) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700269 shortestPathTopo = null;
270 }
271
272 /**
273 * Get the shortest path from a source to a destination by
274 * using the pre-populated local topology state prepared
275 * by method @ref prepareShortestPathTopo().
276 *
277 * See the documentation for method @ref prepareShortestPathTopo()
278 * for additional information and usage.
279 *
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000280 * @param shortestPathTopoHandler the Shortest Path info handler
281 * to use.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700282 * @param src the source in the shortest path computation.
283 * @param dest the destination in the shortest path computation.
284 * @return the data path with the computed shortest path if
285 * found, otherwise null.
286 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000287 public DataPath getTopoShortestPath(Map<Long, ?> shortestPathTopoHandler,
288 SwitchPort src, SwitchPort dest) {
289 @SuppressWarnings("unchecked")
290 Map<Long, Node> shortestPathTopo = (Map)shortestPathTopoHandler;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700291 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 }
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -0700340 for (Node.Link link : nextVertex.links.values()) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700341 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
Pavlin Radoslavova1ff1192013-03-29 04:11:32 -0700370 outPort = new Port(link.myPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700371
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
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800412 String dpid_src = src.dpid().toString();
413 String dpid_dest = dest.dpid().toString();
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800414
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700415 // Get the source and destination switches
416 ISwitchObject srcSwitch =
Toshio Koide18e47202013-06-13 14:07:13 -0700417 op.searchActiveSwitch(dpid_src);
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700418 ISwitchObject destSwitch =
Toshio Koide18e47202013-06-13 14:07:13 -0700419 op.searchActiveSwitch(dpid_dest);
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700420 if (srcSwitch == null || destSwitch == null) {
421 return null;
422 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800423
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800424 //
425 // Test whether we are computing a path from/to the same DPID.
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800426 // If "yes", then just add a single flow entry in the return result.
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800427 //
428 if (dpid_src.equals(dpid_dest)) {
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800429 FlowEntry flowEntry = new FlowEntry();
430 flowEntry.setDpid(src.dpid());
431 flowEntry.setInPort(src.port());
432 flowEntry.setOutPort(dest.port());
433 result_data_path.flowEntries().add(flowEntry);
Toshio Koide18e47202013-06-13 14:07:13 -0700434 op.commit();
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800435 return result_data_path;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800436 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800437
Pankaj Berde15193092013-03-21 17:30:14 -0700438 Vertex v_src = srcSwitch.asVertex();
439 Vertex v_dest = destSwitch.asVertex();
440
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700441 //
442 // Implement the Shortest Path computation by using Breath First Search
443 //
444 Set<Vertex> visitedSet = new HashSet<Vertex>();
445 Queue<Vertex> processingList = new LinkedList<Vertex>();
446 Map<Vertex, Vertex> previousVertexMap = new HashMap<Vertex, Vertex>();
447
448 processingList.add(v_src);
449 visitedSet.add(v_src);
450 Boolean path_found = false;
451 while (! processingList.isEmpty()) {
452 Vertex nextVertex = processingList.poll();
453 if (v_dest.equals(nextVertex)) {
454 path_found = true;
455 break;
456 }
457 for (Vertex parentPort : nextVertex.getVertices(Direction.OUT, "on")) {
458 for (Vertex childPort : parentPort.getVertices(Direction.OUT, "link")) {
459 for (Vertex child : childPort.getVertices(Direction.IN, "on")) {
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700460 // Ignore inactive switches
461 String state = child.getProperty("state").toString();
462 if (! state.equals(SwitchState.ACTIVE.toString()))
463 continue;
464
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700465 if (! visitedSet.contains(child)) {
466 previousVertexMap.put(parentPort, nextVertex);
467 previousVertexMap.put(childPort, parentPort);
468 previousVertexMap.put(child, childPort);
469 visitedSet.add(child);
470 processingList.add(child);
471 }
472 }
473 }
474 }
475 }
476 if (! path_found)
477 return null; // No path found
478
479 List<Vertex> resultPath = new LinkedList<Vertex>();
480 Vertex previousVertex = v_dest;
481 resultPath.add(v_dest);
482 while (! v_src.equals(previousVertex)) {
483 Vertex currentVertex = previousVertexMap.get(previousVertex);
484 resultPath.add(currentVertex);
485 previousVertex = currentVertex;
486 }
487 Collections.reverse(resultPath);
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800488
Pankaj Berde15193092013-03-21 17:30:14 -0700489
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800490 //
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700491 // Loop through the result and prepare the return result
492 // as a list of Flow Entries.
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800493 //
494 long nodeId = 0;
495 short portId = 0;
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800496 Port inPort = new Port(src.port().value());
497 Port outPort = new Port();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700498 int idx = 0;
499 for (Vertex v: resultPath) {
500 String type = v.getProperty("type").toString();
501 // System.out.println("type: " + type);
502 if (type.equals("port")) {
503 String number = v.getProperty("number").toString();
504 // System.out.println("number: " + number);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800505
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700506 Object obj = v.getProperty("number");
507 // String class_str = obj.getClass().toString();
508 if (obj instanceof Short) {
509 portId = (Short)obj;
510 } else if (obj instanceof Integer) {
511 Integer int_nodeId = (Integer)obj;
512 portId = int_nodeId.shortValue();
513 // int int_nodeId = (Integer)obj;
514 // portId = (short)int_nodeId.;
515 }
516 } else if (type.equals("switch")) {
517 String dpid = v.getProperty("dpid").toString();
518 nodeId = HexString.toLong(dpid);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800519
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700520 // System.out.println("dpid: " + dpid);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800521 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700522 idx++;
523 if (idx == 1) {
524 continue;
525 }
526 int mod = idx % 3;
527 if (mod == 0) {
528 // Setup the incoming port
529 inPort = new Port(portId);
530 continue;
531 }
532 if (mod == 2) {
533 // Setup the outgoing port, and add the Flow Entry
534 outPort = new Port(portId);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800535
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800536 FlowEntry flowEntry = new FlowEntry();
537 flowEntry.setDpid(new Dpid(nodeId));
538 flowEntry.setInPort(inPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700539 flowEntry.setOutPort(outPort);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800540 result_data_path.flowEntries().add(flowEntry);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700541 continue;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800542 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800543 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700544 if (idx > 0) {
545 // Add the last Flow Entry
546 FlowEntry flowEntry = new FlowEntry();
547 flowEntry.setDpid(new Dpid(nodeId));
548 flowEntry.setInPort(inPort);
549 flowEntry.setOutPort(dest.port());
550 result_data_path.flowEntries().add(flowEntry);
551 }
552
Toshio Koide18e47202013-06-13 14:07:13 -0700553 op.commit();
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800554 if (result_data_path.flowEntries().size() > 0)
555 return result_data_path;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800556
557 return null;
558 }
559
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700560 /**
561 * Test whether a route exists from a source to a destination.
562 *
563 * @param src the source node for the test.
564 * @param dest the destination node for the test.
565 * @return true if a route exists, otherwise false.
566 */
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800567 @Override
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800568 public Boolean routeExists(SwitchPort src, SwitchPort dest) {
569 DataPath dataPath = getShortestPath(src, dest);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700570 return (dataPath != null);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800571 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800572}