blob: 545128d0050d79b09c098941b8ab7c249f917f42 [file] [log] [blame]
Pavlin Radoslavove1b37bc2013-10-16 03:57:06 -07001package net.onrc.onos.ofcontroller.topology;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -08002
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -07003import java.util.Collections;
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -08004import java.util.HashMap;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -07005import java.util.HashSet;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -07006import java.util.LinkedList;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -08007import java.util.List;
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -08008import java.util.Map;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -07009import java.util.Queue;
10import java.util.Set;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080011
Pankaj Berde38646d62013-06-21 11:34:04 -070012import net.onrc.onos.graph.GraphDBOperation;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070013import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070014import net.onrc.onos.ofcontroller.core.ISwitchStorage.SwitchState;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070015import net.onrc.onos.ofcontroller.util.DataPath;
16import net.onrc.onos.ofcontroller.util.Dpid;
17import net.onrc.onos.ofcontroller.util.FlowEntry;
18import net.onrc.onos.ofcontroller.util.Port;
19import net.onrc.onos.ofcontroller.util.SwitchPort;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080020
21import org.openflow.util.HexString;
Pankaj Berde15193092013-03-21 17:30:14 -070022import org.slf4j.Logger;
23import org.slf4j.LoggerFactory;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080024
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070025import com.tinkerpop.blueprints.Direction;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080026import com.tinkerpop.blueprints.Vertex;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080027
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070028
29/**
30 * A class for storing Node and Link information for fast computation
31 * of shortest paths.
32 */
33class Node {
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070034 /**
35 * A class for storing Link information for fast computation of shortest
36 * paths.
37 */
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070038 class Link {
39 public Node me; // The node this link originates from
40 public Node neighbor; // The neighbor node on the other side
41 public short myPort; // Local port number for the link
42 public short neighborPort; // Neighbor port number for the link
43
44 /**
45 * Link constructor.
46 *
47 * @param me the node this link originates from.
48 * @param the neighbor node on the other side of the link.
49 * @param myPort local port number for the link.
50 * @param neighborPort neighrobr port number for the link.
51 */
52 public Link(Node me, Node neighbor, short myPort, short neighborPort) {
53 this.me = me;
54 this.neighbor = neighbor;
55 this.myPort = myPort;
56 this.neighborPort = neighborPort;
57 }
58 };
59
60 public long nodeId; // The node ID
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -070061 public HashMap<Short, Link> links; // The links originating from this node
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070062
63 /**
64 * Node constructor.
65 *
66 * @param nodeId the node ID.
67 */
68 public Node(long nodeId) {
69 this.nodeId = nodeId;
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -070070 links = new HashMap<Short, Link>();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070071 }
72
73 /**
74 * Add a neighbor.
75 *
76 * A new link to the neighbor will be created.
77 *
78 * @param neighbor the neighbor to add.
79 * @param myPort the local port number for the link to the neighbor.
80 * @param neighborPort the neighbor port number for the link.
81 */
82 public void addNeighbor(Node neighbor, short myPort, short neighborPort) {
83 Link link = new Link(this, neighbor, myPort, neighborPort);
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -070084 links.put(myPort, link);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070085 }
86};
87
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070088/**
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070089 * A class for implementing Topology Network Service.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070090 */
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070091public class TopologyManager implements ITopologyNetService {
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080092
93 /** The logger. */
Pavlin Radoslavove1b37bc2013-10-16 03:57:06 -070094 private static Logger log = LoggerFactory.getLogger(TopologyManager.class);
Pankaj Berde15193092013-03-21 17:30:14 -070095
Toshio Koide18e47202013-06-13 14:07:13 -070096 protected GraphDBOperation op;
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080097
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070098
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070099 /**
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700100 * Default constructor.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700101 */
Pavlin Radoslavove1b37bc2013-10-16 03:57:06 -0700102 public TopologyManager() {
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800103 }
104
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700105 /**
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700106 * Constructor for given database configuration file.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700107 *
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700108 * @param config the database configuration file to use for
109 * the initialization.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700110 */
Pavlin Radoslavove1b37bc2013-10-16 03:57:06 -0700111 public TopologyManager(String config) {
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700112 this.init(config);
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800113 }
114
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700115 /**
116 * Init the module.
117 *
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700118 * @param config the database configuration file to use for
119 * the initialization.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700120 */
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700121 public void init(String config) {
122 try {
123 op = new GraphDBOperation(config);
124 } catch (Exception e) {
125 log.error(e.getMessage());
126 }
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800127 }
128
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700129 /**
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700130 * Close the service. It will close the corresponding database connection.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700131 */
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700132 public void close() {
133 op.close();
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800134 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800135
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700136 /**
137 * Set the database operation handler.
138 *
139 * @param init_op the database operation handler to use for the
140 * initialization.
141 */
Pavlin Radoslavovcec899a2013-06-27 15:47:50 -0700142 public void setDbOperationHandler(GraphDBOperation init_op) {
143 op = init_op;
144 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800145
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700146 /**
147 * Fetch the Switch and Ports info from the Titan Graph
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000148 * and return it for fast access during the shortest path
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700149 * computation.
150 *
151 * After fetching the state, method @ref getTopoShortestPath()
152 * can be used for fast shortest path computation.
153 *
154 * Note: There is certain cost to fetch the state, hence it should
155 * be used only when there is a large number of shortest path
156 * computations that need to be done on the same topology.
157 * Typically, a single call to @ref prepareShortestPathTopo()
158 * should be followed by a large number of calls to
159 * method @ref getTopoShortestPath().
160 * After the last @ref getTopoShortestPath() call,
161 * method @ref dropShortestPathTopo() should be used to release
162 * the internal state that is not needed anymore:
163 *
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000164 * Map<Long, ?> shortestPathTopo;
165 * shortestPathTopo = prepareShortestPathTopo();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700166 * for (int i = 0; i < 10000; i++) {
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000167 * dataPath = getTopoShortestPath(shortestPathTopo, ...);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700168 * ...
169 * }
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000170 * dropShortestPathTopo(shortestPathTopo);
171 *
172 * @return the Shortest Path info handler stored in a map.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700173 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000174 public Map<Long, ?> prepareShortestPathTopo() {
175 Map<Long, Node> shortestPathTopo = new HashMap<Long, Node>();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700176
177 //
178 // Fetch the relevant info from the Switch and Port vertices
179 // from the Titan Graph.
180 //
Toshio Koide18e47202013-06-13 14:07:13 -0700181 Iterable<ISwitchObject> nodes = op.getActiveSwitches();
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700182 for (ISwitchObject switchObj : nodes) {
183 Vertex nodeVertex = switchObj.asVertex();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700184 //
185 // The Switch info
186 //
187 String nodeDpid = nodeVertex.getProperty("dpid").toString();
188 long nodeId = HexString.toLong(nodeDpid);
189 Node me = shortestPathTopo.get(nodeId);
190 if (me == null) {
191 me = new Node(nodeId);
192 shortestPathTopo.put(nodeId, me);
193 }
194
195 //
196 // The local Port info
197 //
198 for (Vertex myPortVertex : nodeVertex.getVertices(Direction.OUT, "on")) {
Pavlin Radoslavov65d50b52013-09-05 14:24:59 -0700199 // Ignore inactive ports
200 if (! myPortVertex.getProperty("state").toString().equals("ACTIVE"))
201 continue;
202
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700203 short myPort = 0;
204 Object obj = myPortVertex.getProperty("number");
205 if (obj instanceof Short) {
206 myPort = (Short)obj;
207 } else if (obj instanceof Integer) {
208 Integer int_nodeId = (Integer)obj;
209 myPort = int_nodeId.shortValue();
210 }
211
212 //
213 // The neighbor Port info
214 //
215 for (Vertex neighborPortVertex : myPortVertex.getVertices(Direction.OUT, "link")) {
Pavlin Radoslavov65d50b52013-09-05 14:24:59 -0700216 // Ignore inactive ports
217 if (! neighborPortVertex.getProperty("state").toString().equals("ACTIVE"))
218 continue;
219
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700220 short neighborPort = 0;
221 obj = neighborPortVertex.getProperty("number");
222 if (obj instanceof Short) {
223 neighborPort = (Short)obj;
224 } else if (obj instanceof Integer) {
225 Integer int_nodeId = (Integer)obj;
226 neighborPort = int_nodeId.shortValue();
227 }
228 //
229 // The neighbor Switch info
230 //
231 for (Vertex neighborVertex : neighborPortVertex.getVertices(Direction.IN, "on")) {
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700232 // Ignore inactive switches
233 String state = neighborVertex.getProperty("state").toString();
234 if (! state.equals(SwitchState.ACTIVE.toString()))
235 continue;
236
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700237 String neighborDpid = neighborVertex.getProperty("dpid").toString();
238 long neighborId = HexString.toLong(neighborDpid);
239 Node neighbor = shortestPathTopo.get(neighborId);
240 if (neighbor == null) {
241 neighbor = new Node(neighborId);
242 shortestPathTopo.put(neighborId, neighbor);
243 }
244 me.addNeighbor(neighbor, myPort, neighborPort);
245 }
246 }
247 }
248 }
Toshio Koide18e47202013-06-13 14:07:13 -0700249 op.commit();
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000250
251 return shortestPathTopo;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700252 }
253
254 /**
255 * Release the state that was populated by
256 * method @ref prepareShortestPathTopo().
257 *
258 * See the documentation for method @ref prepareShortestPathTopo()
259 * for additional information and usage.
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000260 *
Pavlin Radoslavoved13a242013-06-20 17:37:20 -0700261 * @param shortestPathTopo the Shortest Path info handler to release.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700262 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000263 public void dropShortestPathTopo(Map<Long, ?> shortestPathTopo) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700264 shortestPathTopo = null;
265 }
266
267 /**
268 * Get the shortest path from a source to a destination by
269 * using the pre-populated local topology state prepared
270 * by method @ref prepareShortestPathTopo().
271 *
272 * See the documentation for method @ref prepareShortestPathTopo()
273 * for additional information and usage.
274 *
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000275 * @param shortestPathTopoHandler the Shortest Path info handler
276 * to use.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700277 * @param src the source in the shortest path computation.
278 * @param dest the destination in the shortest path computation.
279 * @return the data path with the computed shortest path if
280 * found, otherwise null.
281 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000282 public DataPath getTopoShortestPath(Map<Long, ?> shortestPathTopoHandler,
283 SwitchPort src, SwitchPort dest) {
284 @SuppressWarnings("unchecked")
285 Map<Long, Node> shortestPathTopo = (Map)shortestPathTopoHandler;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700286 DataPath result_data_path = new DataPath();
287
288 // Initialize the source and destination in the data path to return
289 result_data_path.setSrcPort(src);
290 result_data_path.setDstPort(dest);
291
292 String dpid_src = src.dpid().toString();
293 String dpid_dest = dest.dpid().toString();
294
295 // Get the source vertex
296 Node v_src = shortestPathTopo.get(src.dpid().value());
297 if (v_src == null) {
298 return null; // Source vertex not found
299 }
300
301 // Get the destination vertex
302 Node v_dest = shortestPathTopo.get(dest.dpid().value());
303 if (v_dest == null) {
304 return null; // Destination vertex not found
305 }
306
307 //
308 // Test whether we are computing a path from/to the same DPID.
309 // If "yes", then just add a single flow entry in the return result.
310 //
311 if (dpid_src.equals(dpid_dest)) {
312 FlowEntry flowEntry = new FlowEntry();
313 flowEntry.setDpid(src.dpid());
314 flowEntry.setInPort(src.port());
315 flowEntry.setOutPort(dest.port());
316 result_data_path.flowEntries().add(flowEntry);
317 return result_data_path;
318 }
319
320 //
321 // Implement the Shortest Path computation by using Breath First Search
322 //
323 Set<Node> visitedSet = new HashSet<Node>();
324 Queue<Node> processingList = new LinkedList<Node>();
325 Map<Node, Node.Link> previousVertexMap = new HashMap<Node, Node.Link>();
326 processingList.add(v_src);
327 visitedSet.add(v_src);
328 Boolean path_found = false;
329 while (! processingList.isEmpty()) {
330 Node nextVertex = processingList.poll();
331 if (v_dest == nextVertex) {
332 path_found = true;
333 break;
334 }
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -0700335 for (Node.Link link : nextVertex.links.values()) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700336 Node child = link.neighbor;
337 if (! visitedSet.contains(child)) {
338 previousVertexMap.put(child, link);
339 visitedSet.add(child);
340 processingList.add(child);
341 }
342 }
343 }
344 if (! path_found)
345 return null; // No path found
346
347 // Collect the path as a list of links
348 List<Node.Link> resultPath = new LinkedList<Node.Link>();
349 Node previousVertex = v_dest;
350 while (! v_src.equals(previousVertex)) {
351 Node.Link currentLink = previousVertexMap.get(previousVertex);
352 resultPath.add(currentLink);
353 previousVertex = currentLink.me;
354 }
355 Collections.reverse(resultPath);
356
357 //
358 // Loop through the result and prepare the return result
359 // as a list of Flow Entries.
360 //
361 Port inPort = new Port(src.port().value());
362 Port outPort;
363 for (Node.Link link: resultPath) {
364 // Setup the outgoing port, and add the Flow Entry
Pavlin Radoslavova1ff1192013-03-29 04:11:32 -0700365 outPort = new Port(link.myPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700366
367 FlowEntry flowEntry = new FlowEntry();
368 flowEntry.setDpid(new Dpid(link.me.nodeId));
369 flowEntry.setInPort(inPort);
370 flowEntry.setOutPort(outPort);
371 result_data_path.flowEntries().add(flowEntry);
372
373 // Setup the next incoming port
374 inPort = new Port(link.neighborPort);
375 }
376 if (resultPath.size() > 0) {
377 // Add the last Flow Entry
378 FlowEntry flowEntry = new FlowEntry();
379 flowEntry.setDpid(new Dpid(dest.dpid().value()));
380 flowEntry.setInPort(inPort);
381 flowEntry.setOutPort(dest.port());
382 result_data_path.flowEntries().add(flowEntry);
383 }
384
385 if (result_data_path.flowEntries().size() > 0)
386 return result_data_path;
387
388 return null;
389 }
390
391 /**
392 * Get the shortest path from a source to a destination.
393 *
394 * @param src the source in the shortest path computation.
395 * @param dest the destination in the shortest path computation.
396 * @return the data path with the computed shortest path if
397 * found, otherwise null.
398 */
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800399 @Override
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800400 public DataPath getShortestPath(SwitchPort src, SwitchPort dest) {
401 DataPath result_data_path = new DataPath();
402
403 // Initialize the source and destination in the data path to return
404 result_data_path.setSrcPort(src);
405 result_data_path.setDstPort(dest);
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800406
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800407 String dpid_src = src.dpid().toString();
408 String dpid_dest = dest.dpid().toString();
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800409
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700410 // Get the source and destination switches
411 ISwitchObject srcSwitch =
Toshio Koide18e47202013-06-13 14:07:13 -0700412 op.searchActiveSwitch(dpid_src);
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700413 ISwitchObject destSwitch =
Toshio Koide18e47202013-06-13 14:07:13 -0700414 op.searchActiveSwitch(dpid_dest);
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700415 if (srcSwitch == null || destSwitch == null) {
416 return null;
417 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800418
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800419 //
420 // Test whether we are computing a path from/to the same DPID.
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800421 // If "yes", then just add a single flow entry in the return result.
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800422 //
423 if (dpid_src.equals(dpid_dest)) {
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800424 FlowEntry flowEntry = new FlowEntry();
425 flowEntry.setDpid(src.dpid());
426 flowEntry.setInPort(src.port());
427 flowEntry.setOutPort(dest.port());
428 result_data_path.flowEntries().add(flowEntry);
Toshio Koide18e47202013-06-13 14:07:13 -0700429 op.commit();
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800430 return result_data_path;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800431 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800432
Pankaj Berde15193092013-03-21 17:30:14 -0700433 Vertex v_src = srcSwitch.asVertex();
434 Vertex v_dest = destSwitch.asVertex();
435
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700436 //
437 // Implement the Shortest Path computation by using Breath First Search
438 //
439 Set<Vertex> visitedSet = new HashSet<Vertex>();
440 Queue<Vertex> processingList = new LinkedList<Vertex>();
441 Map<Vertex, Vertex> previousVertexMap = new HashMap<Vertex, Vertex>();
442
443 processingList.add(v_src);
444 visitedSet.add(v_src);
445 Boolean path_found = false;
446 while (! processingList.isEmpty()) {
447 Vertex nextVertex = processingList.poll();
448 if (v_dest.equals(nextVertex)) {
449 path_found = true;
450 break;
451 }
452 for (Vertex parentPort : nextVertex.getVertices(Direction.OUT, "on")) {
Pavlin Radoslavov65d50b52013-09-05 14:24:59 -0700453 // Ignore inactive ports
454 if (! parentPort.getProperty("state").toString().equals("ACTIVE"))
455 continue;
456
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700457 for (Vertex childPort : parentPort.getVertices(Direction.OUT, "link")) {
Pavlin Radoslavov65d50b52013-09-05 14:24:59 -0700458 // Ignore inactive ports
459 if (! childPort.getProperty("state").toString().equals("ACTIVE"))
460 continue;
461
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700462 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}