blob: 864bb74b1928e1485700fb11ca94960b57b6b88b [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;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070018import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
19import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoRouteService;
20import net.onrc.onos.ofcontroller.core.ISwitchStorage.SwitchState;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070021import net.onrc.onos.ofcontroller.util.DataPath;
22import net.onrc.onos.ofcontroller.util.Dpid;
23import net.onrc.onos.ofcontroller.util.FlowEntry;
24import net.onrc.onos.ofcontroller.util.Port;
25import net.onrc.onos.ofcontroller.util.SwitchPort;
Pankaj Berde15193092013-03-21 17:30:14 -070026import net.onrc.onos.util.GraphDBConnection;
Toshio Koide18e47202013-06-13 14:07:13 -070027import net.onrc.onos.util.GraphDBOperation;
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 Radoslavov382b22a2013-01-28 09:24:04 -080034import com.tinkerpop.blueprints.Vertex;
Pavlin Radoslavovbfae5e02013-03-19 23:06:36 -070035import com.tinkerpop.pipes.PipeFunction;
36import com.tinkerpop.pipes.branch.LoopPipe.LoopBundle;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080037
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070038
39/**
40 * A class for storing Node and Link information for fast computation
41 * of shortest paths.
42 */
43class Node {
44 class Link {
45 public Node me; // The node this link originates from
46 public Node neighbor; // The neighbor node on the other side
47 public short myPort; // Local port number for the link
48 public short neighborPort; // Neighbor port number for the link
49
50 /**
51 * Link constructor.
52 *
53 * @param me the node this link originates from.
54 * @param the neighbor node on the other side of the link.
55 * @param myPort local port number for the link.
56 * @param neighborPort neighrobr port number for the link.
57 */
58 public Link(Node me, Node neighbor, short myPort, short neighborPort) {
59 this.me = me;
60 this.neighbor = neighbor;
61 this.myPort = myPort;
62 this.neighborPort = neighborPort;
63 }
64 };
65
66 public long nodeId; // The node ID
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -070067 public HashMap<Short, Link> links; // The links originating from this node
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070068
69 /**
70 * Node constructor.
71 *
72 * @param nodeId the node ID.
73 */
74 public Node(long nodeId) {
75 this.nodeId = nodeId;
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -070076 links = new HashMap<Short, Link>();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070077 }
78
79 /**
80 * Add a neighbor.
81 *
82 * A new link to the neighbor will be created.
83 *
84 * @param neighbor the neighbor to add.
85 * @param myPort the local port number for the link to the neighbor.
86 * @param neighborPort the neighbor port number for the link.
87 */
88 public void addNeighbor(Node neighbor, short myPort, short neighborPort) {
89 Link link = new Link(this, neighbor, myPort, neighborPort);
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -070090 links.put(myPort, link);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070091 }
92};
93
Pankaj Berde15193092013-03-21 17:30:14 -070094
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080095public class TopoRouteService implements IFloodlightModule, ITopoRouteService {
96
97 /** The logger. */
Pavlin Radoslavov19343432013-03-06 10:43:18 -080098 private static Logger log =
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080099 LoggerFactory.getLogger(TopoRouteService.class);
Pankaj Berde15193092013-03-21 17:30:14 -0700100
Toshio Koide18e47202013-06-13 14:07:13 -0700101 protected GraphDBOperation op;
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800102
103 @Override
104 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
105 Collection<Class<? extends IFloodlightService>> l =
106 new ArrayList<Class<? extends IFloodlightService>>();
107 l.add(ITopoRouteService.class);
108 return l;
109 }
110
111 @Override
112 public Map<Class<? extends IFloodlightService>, IFloodlightService>
113 getServiceImpls() {
114 Map<Class<? extends IFloodlightService>,
115 IFloodlightService> m =
116 new HashMap<Class<? extends IFloodlightService>,
117 IFloodlightService>();
118 m.put(ITopoRouteService.class, this);
119 return m;
120 }
121
122 @Override
123 public Collection<Class<? extends IFloodlightService>>
124 getModuleDependencies() {
125 Collection<Class<? extends IFloodlightService>> l =
126 new ArrayList<Class<? extends IFloodlightService>>();
127 // TODO: Add the appropriate dependencies
128 // l.add(IRestApiService.class);
129 return l;
130 }
131
132 @Override
133 public void init(FloodlightModuleContext context)
134 throws FloodlightModuleException {
135 // TODO: Add the appropriate initialization
Toshio Koide18e47202013-06-13 14:07:13 -0700136 op = new GraphDBOperation(GraphDBConnection.getInstance(""));
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800137 }
138
139 @Override
140 public void startUp(FloodlightModuleContext context) {
141 // TODO: Add the approprate setup
142 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800143
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800144
Pavlin Radoslavovbfae5e02013-03-19 23:06:36 -0700145 static class ShortestPathLoopFunction implements PipeFunction<LoopBundle<Vertex>, Boolean> {
146 String dpid;
147 public ShortestPathLoopFunction(String dpid) {
148 super();
149 this.dpid = dpid;
150 }
151 public Boolean compute(LoopBundle<Vertex> bundle) {
152 Boolean output = false;
153 if (! bundle.getObject().getProperty("dpid").equals(dpid)) {
154 output = true;
155 }
156 return output;
157 }
158 }
159
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700160 /**
161 * Fetch the Switch and Ports info from the Titan Graph
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000162 * and return it for fast access during the shortest path
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700163 * computation.
164 *
165 * After fetching the state, method @ref getTopoShortestPath()
166 * can be used for fast shortest path computation.
167 *
168 * Note: There is certain cost to fetch the state, hence it should
169 * be used only when there is a large number of shortest path
170 * computations that need to be done on the same topology.
171 * Typically, a single call to @ref prepareShortestPathTopo()
172 * should be followed by a large number of calls to
173 * method @ref getTopoShortestPath().
174 * After the last @ref getTopoShortestPath() call,
175 * method @ref dropShortestPathTopo() should be used to release
176 * the internal state that is not needed anymore:
177 *
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000178 * Map<Long, ?> shortestPathTopo;
179 * shortestPathTopo = prepareShortestPathTopo();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700180 * for (int i = 0; i < 10000; i++) {
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000181 * dataPath = getTopoShortestPath(shortestPathTopo, ...);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700182 * ...
183 * }
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000184 * dropShortestPathTopo(shortestPathTopo);
185 *
186 * @return the Shortest Path info handler stored in a map.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700187 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000188 public Map<Long, ?> prepareShortestPathTopo() {
189 Map<Long, Node> shortestPathTopo = new HashMap<Long, Node>();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700190
191 //
192 // Fetch the relevant info from the Switch and Port vertices
193 // from the Titan Graph.
194 //
Toshio Koide18e47202013-06-13 14:07:13 -0700195 Iterable<ISwitchObject> nodes = op.getActiveSwitches();
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700196 for (ISwitchObject switchObj : nodes) {
197 Vertex nodeVertex = switchObj.asVertex();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700198 //
199 // The Switch info
200 //
201 String nodeDpid = nodeVertex.getProperty("dpid").toString();
202 long nodeId = HexString.toLong(nodeDpid);
203 Node me = shortestPathTopo.get(nodeId);
204 if (me == null) {
205 me = new Node(nodeId);
206 shortestPathTopo.put(nodeId, me);
207 }
208
209 //
210 // The local Port info
211 //
212 for (Vertex myPortVertex : nodeVertex.getVertices(Direction.OUT, "on")) {
213 short myPort = 0;
214 Object obj = myPortVertex.getProperty("number");
215 if (obj instanceof Short) {
216 myPort = (Short)obj;
217 } else if (obj instanceof Integer) {
218 Integer int_nodeId = (Integer)obj;
219 myPort = int_nodeId.shortValue();
220 }
221
222 //
223 // The neighbor Port info
224 //
225 for (Vertex neighborPortVertex : myPortVertex.getVertices(Direction.OUT, "link")) {
226 short neighborPort = 0;
227 obj = neighborPortVertex.getProperty("number");
228 if (obj instanceof Short) {
229 neighborPort = (Short)obj;
230 } else if (obj instanceof Integer) {
231 Integer int_nodeId = (Integer)obj;
232 neighborPort = int_nodeId.shortValue();
233 }
234 //
235 // The neighbor Switch info
236 //
237 for (Vertex neighborVertex : neighborPortVertex.getVertices(Direction.IN, "on")) {
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700238 // Ignore inactive switches
239 String state = neighborVertex.getProperty("state").toString();
240 if (! state.equals(SwitchState.ACTIVE.toString()))
241 continue;
242
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700243 String neighborDpid = neighborVertex.getProperty("dpid").toString();
244 long neighborId = HexString.toLong(neighborDpid);
245 Node neighbor = shortestPathTopo.get(neighborId);
246 if (neighbor == null) {
247 neighbor = new Node(neighborId);
248 shortestPathTopo.put(neighborId, neighbor);
249 }
250 me.addNeighbor(neighbor, myPort, neighborPort);
251 }
252 }
253 }
254 }
Toshio Koide18e47202013-06-13 14:07:13 -0700255 op.commit();
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000256
257 return shortestPathTopo;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700258 }
259
260 /**
261 * Release the state that was populated by
262 * method @ref prepareShortestPathTopo().
263 *
264 * See the documentation for method @ref prepareShortestPathTopo()
265 * for additional information and usage.
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000266 *
267 * @shortestPathTopo the Shortest Path info handler to release.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700268 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000269 public void dropShortestPathTopo(Map<Long, ?> shortestPathTopo) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700270 shortestPathTopo = null;
271 }
272
273 /**
274 * Get the shortest path from a source to a destination by
275 * using the pre-populated local topology state prepared
276 * by method @ref prepareShortestPathTopo().
277 *
278 * See the documentation for method @ref prepareShortestPathTopo()
279 * for additional information and usage.
280 *
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000281 * @param shortestPathTopoHandler the Shortest Path info handler
282 * to use.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700283 * @param src the source in the shortest path computation.
284 * @param dest the destination in the shortest path computation.
285 * @return the data path with the computed shortest path if
286 * found, otherwise null.
287 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000288 public DataPath getTopoShortestPath(Map<Long, ?> shortestPathTopoHandler,
289 SwitchPort src, SwitchPort dest) {
290 @SuppressWarnings("unchecked")
291 Map<Long, Node> shortestPathTopo = (Map)shortestPathTopoHandler;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700292 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 }
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -0700341 for (Node.Link link : nextVertex.links.values()) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700342 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 =
Toshio Koide18e47202013-06-13 14:07:13 -0700418 op.searchActiveSwitch(dpid_src);
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700419 ISwitchObject destSwitch =
Toshio Koide18e47202013-06-13 14:07:13 -0700420 op.searchActiveSwitch(dpid_dest);
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700421 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);
Toshio Koide18e47202013-06-13 14:07:13 -0700435 op.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
Toshio Koide18e47202013-06-13 14:07:13 -0700554 op.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}