blob: 1e002aab38db1c32cd3ee74c34ba0d0dada3e062 [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
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -070068 public HashMap<Short, Link> links; // The links originating from this node
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070069
70 /**
71 * Node constructor.
72 *
73 * @param nodeId the node ID.
74 */
75 public Node(long nodeId) {
76 this.nodeId = nodeId;
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -070077 links = new HashMap<Short, Link>();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070078 }
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);
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -070091 links.put(myPort, link);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070092 }
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
104 @Override
105 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
106 Collection<Class<? extends IFloodlightService>> l =
107 new ArrayList<Class<? extends IFloodlightService>>();
108 l.add(ITopoRouteService.class);
109 return l;
110 }
111
112 @Override
113 public Map<Class<? extends IFloodlightService>, IFloodlightService>
114 getServiceImpls() {
115 Map<Class<? extends IFloodlightService>,
116 IFloodlightService> m =
117 new HashMap<Class<? extends IFloodlightService>,
118 IFloodlightService>();
119 m.put(ITopoRouteService.class, this);
120 return m;
121 }
122
123 @Override
124 public Collection<Class<? extends IFloodlightService>>
125 getModuleDependencies() {
126 Collection<Class<? extends IFloodlightService>> l =
127 new ArrayList<Class<? extends IFloodlightService>>();
128 // TODO: Add the appropriate dependencies
129 // l.add(IRestApiService.class);
130 return l;
131 }
132
133 @Override
134 public void init(FloodlightModuleContext context)
135 throws FloodlightModuleException {
136 // TODO: Add the appropriate initialization
Pankaj Berde15193092013-03-21 17:30:14 -0700137 conn = GraphDBConnection.getInstance("");
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800138 }
139
140 @Override
141 public void startUp(FloodlightModuleContext context) {
142 // TODO: Add the approprate setup
143 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800144
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800145
Pavlin Radoslavovbfae5e02013-03-19 23:06:36 -0700146 static class ShortestPathLoopFunction implements PipeFunction<LoopBundle<Vertex>, Boolean> {
147 String dpid;
148 public ShortestPathLoopFunction(String dpid) {
149 super();
150 this.dpid = dpid;
151 }
152 public Boolean compute(LoopBundle<Vertex> bundle) {
153 Boolean output = false;
154 if (! bundle.getObject().getProperty("dpid").equals(dpid)) {
155 output = true;
156 }
157 return output;
158 }
159 }
160
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700161 /**
162 * Fetch the Switch and Ports info from the Titan Graph
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000163 * and return it for fast access during the shortest path
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700164 * computation.
165 *
166 * After fetching the state, method @ref getTopoShortestPath()
167 * can be used for fast shortest path computation.
168 *
169 * Note: There is certain cost to fetch the state, hence it should
170 * be used only when there is a large number of shortest path
171 * computations that need to be done on the same topology.
172 * Typically, a single call to @ref prepareShortestPathTopo()
173 * should be followed by a large number of calls to
174 * method @ref getTopoShortestPath().
175 * After the last @ref getTopoShortestPath() call,
176 * method @ref dropShortestPathTopo() should be used to release
177 * the internal state that is not needed anymore:
178 *
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000179 * Map<Long, ?> shortestPathTopo;
180 * shortestPathTopo = prepareShortestPathTopo();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700181 * for (int i = 0; i < 10000; i++) {
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000182 * dataPath = getTopoShortestPath(shortestPathTopo, ...);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700183 * ...
184 * }
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000185 * dropShortestPathTopo(shortestPathTopo);
186 *
187 * @return the Shortest Path info handler stored in a map.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700188 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000189 public Map<Long, ?> prepareShortestPathTopo() {
190 Map<Long, Node> shortestPathTopo = new HashMap<Long, Node>();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700191
192 //
193 // Fetch the relevant info from the Switch and Port vertices
194 // from the Titan Graph.
195 //
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700196 Iterable<ISwitchObject> nodes = conn.utils().getActiveSwitches(conn);
197 for (ISwitchObject switchObj : nodes) {
198 Vertex nodeVertex = switchObj.asVertex();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700199 //
200 // The Switch info
201 //
202 String nodeDpid = nodeVertex.getProperty("dpid").toString();
203 long nodeId = HexString.toLong(nodeDpid);
204 Node me = shortestPathTopo.get(nodeId);
205 if (me == null) {
206 me = new Node(nodeId);
207 shortestPathTopo.put(nodeId, me);
208 }
209
210 //
211 // The local Port info
212 //
213 for (Vertex myPortVertex : nodeVertex.getVertices(Direction.OUT, "on")) {
214 short myPort = 0;
215 Object obj = myPortVertex.getProperty("number");
216 if (obj instanceof Short) {
217 myPort = (Short)obj;
218 } else if (obj instanceof Integer) {
219 Integer int_nodeId = (Integer)obj;
220 myPort = int_nodeId.shortValue();
221 }
222
223 //
224 // The neighbor Port info
225 //
226 for (Vertex neighborPortVertex : myPortVertex.getVertices(Direction.OUT, "link")) {
227 short neighborPort = 0;
228 obj = neighborPortVertex.getProperty("number");
229 if (obj instanceof Short) {
230 neighborPort = (Short)obj;
231 } else if (obj instanceof Integer) {
232 Integer int_nodeId = (Integer)obj;
233 neighborPort = int_nodeId.shortValue();
234 }
235 //
236 // The neighbor Switch info
237 //
238 for (Vertex neighborVertex : neighborPortVertex.getVertices(Direction.IN, "on")) {
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700239 // Ignore inactive switches
240 String state = neighborVertex.getProperty("state").toString();
241 if (! state.equals(SwitchState.ACTIVE.toString()))
242 continue;
243
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700244 String neighborDpid = neighborVertex.getProperty("dpid").toString();
245 long neighborId = HexString.toLong(neighborDpid);
246 Node neighbor = shortestPathTopo.get(neighborId);
247 if (neighbor == null) {
248 neighbor = new Node(neighborId);
249 shortestPathTopo.put(neighborId, neighbor);
250 }
251 me.addNeighbor(neighbor, myPort, neighborPort);
252 }
253 }
254 }
255 }
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700256 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000257
258 return shortestPathTopo;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700259 }
260
261 /**
262 * Release the state that was populated by
263 * method @ref prepareShortestPathTopo().
264 *
265 * See the documentation for method @ref prepareShortestPathTopo()
266 * for additional information and usage.
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000267 *
268 * @shortestPathTopo the Shortest Path info handler to release.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700269 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000270 public void dropShortestPathTopo(Map<Long, ?> shortestPathTopo) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700271 shortestPathTopo = null;
272 }
273
274 /**
275 * Get the shortest path from a source to a destination by
276 * using the pre-populated local topology state prepared
277 * by method @ref prepareShortestPathTopo().
278 *
279 * See the documentation for method @ref prepareShortestPathTopo()
280 * for additional information and usage.
281 *
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000282 * @param shortestPathTopoHandler the Shortest Path info handler
283 * to use.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700284 * @param src the source in the shortest path computation.
285 * @param dest the destination in the shortest path computation.
286 * @return the data path with the computed shortest path if
287 * found, otherwise null.
288 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000289 public DataPath getTopoShortestPath(Map<Long, ?> shortestPathTopoHandler,
290 SwitchPort src, SwitchPort dest) {
291 @SuppressWarnings("unchecked")
292 Map<Long, Node> shortestPathTopo = (Map)shortestPathTopoHandler;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700293 DataPath result_data_path = new DataPath();
294
295 // Initialize the source and destination in the data path to return
296 result_data_path.setSrcPort(src);
297 result_data_path.setDstPort(dest);
298
299 String dpid_src = src.dpid().toString();
300 String dpid_dest = dest.dpid().toString();
301
302 // Get the source vertex
303 Node v_src = shortestPathTopo.get(src.dpid().value());
304 if (v_src == null) {
305 return null; // Source vertex not found
306 }
307
308 // Get the destination vertex
309 Node v_dest = shortestPathTopo.get(dest.dpid().value());
310 if (v_dest == null) {
311 return null; // Destination vertex not found
312 }
313
314 //
315 // Test whether we are computing a path from/to the same DPID.
316 // If "yes", then just add a single flow entry in the return result.
317 //
318 if (dpid_src.equals(dpid_dest)) {
319 FlowEntry flowEntry = new FlowEntry();
320 flowEntry.setDpid(src.dpid());
321 flowEntry.setInPort(src.port());
322 flowEntry.setOutPort(dest.port());
323 result_data_path.flowEntries().add(flowEntry);
324 return result_data_path;
325 }
326
327 //
328 // Implement the Shortest Path computation by using Breath First Search
329 //
330 Set<Node> visitedSet = new HashSet<Node>();
331 Queue<Node> processingList = new LinkedList<Node>();
332 Map<Node, Node.Link> previousVertexMap = new HashMap<Node, Node.Link>();
333 processingList.add(v_src);
334 visitedSet.add(v_src);
335 Boolean path_found = false;
336 while (! processingList.isEmpty()) {
337 Node nextVertex = processingList.poll();
338 if (v_dest == nextVertex) {
339 path_found = true;
340 break;
341 }
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -0700342 for (Node.Link link : nextVertex.links.values()) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700343 Node child = link.neighbor;
344 if (! visitedSet.contains(child)) {
345 previousVertexMap.put(child, link);
346 visitedSet.add(child);
347 processingList.add(child);
348 }
349 }
350 }
351 if (! path_found)
352 return null; // No path found
353
354 // Collect the path as a list of links
355 List<Node.Link> resultPath = new LinkedList<Node.Link>();
356 Node previousVertex = v_dest;
357 while (! v_src.equals(previousVertex)) {
358 Node.Link currentLink = previousVertexMap.get(previousVertex);
359 resultPath.add(currentLink);
360 previousVertex = currentLink.me;
361 }
362 Collections.reverse(resultPath);
363
364 //
365 // Loop through the result and prepare the return result
366 // as a list of Flow Entries.
367 //
368 Port inPort = new Port(src.port().value());
369 Port outPort;
370 for (Node.Link link: resultPath) {
371 // Setup the outgoing port, and add the Flow Entry
Pavlin Radoslavova1ff1192013-03-29 04:11:32 -0700372 outPort = new Port(link.myPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700373
374 FlowEntry flowEntry = new FlowEntry();
375 flowEntry.setDpid(new Dpid(link.me.nodeId));
376 flowEntry.setInPort(inPort);
377 flowEntry.setOutPort(outPort);
378 result_data_path.flowEntries().add(flowEntry);
379
380 // Setup the next incoming port
381 inPort = new Port(link.neighborPort);
382 }
383 if (resultPath.size() > 0) {
384 // Add the last Flow Entry
385 FlowEntry flowEntry = new FlowEntry();
386 flowEntry.setDpid(new Dpid(dest.dpid().value()));
387 flowEntry.setInPort(inPort);
388 flowEntry.setOutPort(dest.port());
389 result_data_path.flowEntries().add(flowEntry);
390 }
391
392 if (result_data_path.flowEntries().size() > 0)
393 return result_data_path;
394
395 return null;
396 }
397
398 /**
399 * Get the shortest path from a source to a destination.
400 *
401 * @param src the source in the shortest path computation.
402 * @param dest the destination in the shortest path computation.
403 * @return the data path with the computed shortest path if
404 * found, otherwise null.
405 */
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800406 @Override
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800407 public DataPath getShortestPath(SwitchPort src, SwitchPort dest) {
408 DataPath result_data_path = new DataPath();
409
410 // Initialize the source and destination in the data path to return
411 result_data_path.setSrcPort(src);
412 result_data_path.setDstPort(dest);
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800413
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800414 String dpid_src = src.dpid().toString();
415 String dpid_dest = dest.dpid().toString();
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800416
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700417 // Get the source and destination switches
418 ISwitchObject srcSwitch =
419 conn.utils().searchActiveSwitch(conn, dpid_src);
420 ISwitchObject destSwitch =
421 conn.utils().searchActiveSwitch(conn, dpid_dest);
422 if (srcSwitch == null || destSwitch == null) {
423 return null;
424 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800425
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800426 //
427 // Test whether we are computing a path from/to the same DPID.
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800428 // If "yes", then just add a single flow entry in the return result.
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800429 //
430 if (dpid_src.equals(dpid_dest)) {
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800431 FlowEntry flowEntry = new FlowEntry();
432 flowEntry.setDpid(src.dpid());
433 flowEntry.setInPort(src.port());
434 flowEntry.setOutPort(dest.port());
435 result_data_path.flowEntries().add(flowEntry);
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700436 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800437 return result_data_path;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800438 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800439
Pankaj Berde15193092013-03-21 17:30:14 -0700440 Vertex v_src = srcSwitch.asVertex();
441 Vertex v_dest = destSwitch.asVertex();
442
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700443 //
444 // Implement the Shortest Path computation by using Breath First Search
445 //
446 Set<Vertex> visitedSet = new HashSet<Vertex>();
447 Queue<Vertex> processingList = new LinkedList<Vertex>();
448 Map<Vertex, Vertex> previousVertexMap = new HashMap<Vertex, Vertex>();
449
450 processingList.add(v_src);
451 visitedSet.add(v_src);
452 Boolean path_found = false;
453 while (! processingList.isEmpty()) {
454 Vertex nextVertex = processingList.poll();
455 if (v_dest.equals(nextVertex)) {
456 path_found = true;
457 break;
458 }
459 for (Vertex parentPort : nextVertex.getVertices(Direction.OUT, "on")) {
460 for (Vertex childPort : parentPort.getVertices(Direction.OUT, "link")) {
461 for (Vertex child : childPort.getVertices(Direction.IN, "on")) {
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700462 // Ignore inactive switches
463 String state = child.getProperty("state").toString();
464 if (! state.equals(SwitchState.ACTIVE.toString()))
465 continue;
466
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700467 if (! visitedSet.contains(child)) {
468 previousVertexMap.put(parentPort, nextVertex);
469 previousVertexMap.put(childPort, parentPort);
470 previousVertexMap.put(child, childPort);
471 visitedSet.add(child);
472 processingList.add(child);
473 }
474 }
475 }
476 }
477 }
478 if (! path_found)
479 return null; // No path found
480
481 List<Vertex> resultPath = new LinkedList<Vertex>();
482 Vertex previousVertex = v_dest;
483 resultPath.add(v_dest);
484 while (! v_src.equals(previousVertex)) {
485 Vertex currentVertex = previousVertexMap.get(previousVertex);
486 resultPath.add(currentVertex);
487 previousVertex = currentVertex;
488 }
489 Collections.reverse(resultPath);
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800490
Pankaj Berde15193092013-03-21 17:30:14 -0700491
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800492 //
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700493 // Loop through the result and prepare the return result
494 // as a list of Flow Entries.
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800495 //
496 long nodeId = 0;
497 short portId = 0;
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800498 Port inPort = new Port(src.port().value());
499 Port outPort = new Port();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700500 int idx = 0;
501 for (Vertex v: resultPath) {
502 String type = v.getProperty("type").toString();
503 // System.out.println("type: " + type);
504 if (type.equals("port")) {
505 String number = v.getProperty("number").toString();
506 // System.out.println("number: " + number);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800507
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700508 Object obj = v.getProperty("number");
509 // String class_str = obj.getClass().toString();
510 if (obj instanceof Short) {
511 portId = (Short)obj;
512 } else if (obj instanceof Integer) {
513 Integer int_nodeId = (Integer)obj;
514 portId = int_nodeId.shortValue();
515 // int int_nodeId = (Integer)obj;
516 // portId = (short)int_nodeId.;
517 }
518 } else if (type.equals("switch")) {
519 String dpid = v.getProperty("dpid").toString();
520 nodeId = HexString.toLong(dpid);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800521
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700522 // System.out.println("dpid: " + dpid);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800523 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700524 idx++;
525 if (idx == 1) {
526 continue;
527 }
528 int mod = idx % 3;
529 if (mod == 0) {
530 // Setup the incoming port
531 inPort = new Port(portId);
532 continue;
533 }
534 if (mod == 2) {
535 // Setup the outgoing port, and add the Flow Entry
536 outPort = new Port(portId);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800537
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800538 FlowEntry flowEntry = new FlowEntry();
539 flowEntry.setDpid(new Dpid(nodeId));
540 flowEntry.setInPort(inPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700541 flowEntry.setOutPort(outPort);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800542 result_data_path.flowEntries().add(flowEntry);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700543 continue;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800544 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800545 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700546 if (idx > 0) {
547 // Add the last Flow Entry
548 FlowEntry flowEntry = new FlowEntry();
549 flowEntry.setDpid(new Dpid(nodeId));
550 flowEntry.setInPort(inPort);
551 flowEntry.setOutPort(dest.port());
552 result_data_path.flowEntries().add(flowEntry);
553 }
554
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700555 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800556 if (result_data_path.flowEntries().size() > 0)
557 return result_data_path;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800558
559 return null;
560 }
561
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700562 /**
563 * Test whether a route exists from a source to a destination.
564 *
565 * @param src the source node for the test.
566 * @param dest the destination node for the test.
567 * @return true if a route exists, otherwise false.
568 */
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800569 @Override
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800570 public Boolean routeExists(SwitchPort src, SwitchPort dest) {
571 DataPath dataPath = getShortestPath(src, dest);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700572 return (dataPath != null);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800573 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800574}