blob: a784d7d29116958996cc9e967f83ecf9b5769440 [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
Pankaj Berde38646d62013-06-21 11:34:04 -070014import net.onrc.onos.graph.GraphDBOperation;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070015import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
16import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoRouteService;
17import net.onrc.onos.ofcontroller.core.ISwitchStorage.SwitchState;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070018import net.onrc.onos.ofcontroller.util.DataPath;
19import net.onrc.onos.ofcontroller.util.Dpid;
20import net.onrc.onos.ofcontroller.util.FlowEntry;
21import net.onrc.onos.ofcontroller.util.Port;
22import net.onrc.onos.ofcontroller.util.SwitchPort;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080023
24import org.openflow.util.HexString;
Pankaj Berde15193092013-03-21 17:30:14 -070025import org.slf4j.Logger;
26import org.slf4j.LoggerFactory;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080027
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070028import com.tinkerpop.blueprints.Direction;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080029import com.tinkerpop.blueprints.Vertex;
Pavlin Radoslavovbfae5e02013-03-19 23:06:36 -070030import com.tinkerpop.pipes.PipeFunction;
31import com.tinkerpop.pipes.branch.LoopPipe.LoopBundle;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080032
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070033
34/**
35 * A class for storing Node and Link information for fast computation
36 * of shortest paths.
37 */
38class Node {
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070039 /**
40 * A class for storing Link information for fast computation of shortest
41 * paths.
42 */
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070043 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
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070093/**
94 * A class for implementing Topology Route Service.
95 */
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070096public class TopoRouteService implements ITopoRouteService {
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080097
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
Toshio Koide18e47202013-06-13 14:07:13 -0700102 protected GraphDBOperation op;
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800103
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700104
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700105 /**
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700106 * Default constructor.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700107 */
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700108 public TopoRouteService() {
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800109 }
110
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700111 /**
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700112 * Constructor for given database configuration file.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700113 *
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700114 * @param config the database configuration file to use for
115 * the initialization.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700116 */
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700117 public TopoRouteService(String config) {
118 this.init(config);
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800119 }
120
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700121 /**
122 * Init the module.
123 *
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700124 * @param config the database configuration file to use for
125 * the initialization.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700126 */
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700127 public void init(String config) {
128 try {
129 op = new GraphDBOperation(config);
130 } catch (Exception e) {
131 log.error(e.getMessage());
132 }
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800133 }
134
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700135 /**
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700136 * Close the service. It will close the corresponding database connection.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700137 */
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700138 public void close() {
139 op.close();
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800140 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800141
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700142 /**
143 * Set the database operation handler.
144 *
145 * @param init_op the database operation handler to use for the
146 * initialization.
147 */
Pavlin Radoslavovcec899a2013-06-27 15:47:50 -0700148 public void setDbOperationHandler(GraphDBOperation init_op) {
149 op = init_op;
150 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800151
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700152 /**
153 * Fetch the Switch and Ports info from the Titan Graph
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000154 * and return it for fast access during the shortest path
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700155 * computation.
156 *
157 * After fetching the state, method @ref getTopoShortestPath()
158 * can be used for fast shortest path computation.
159 *
160 * Note: There is certain cost to fetch the state, hence it should
161 * be used only when there is a large number of shortest path
162 * computations that need to be done on the same topology.
163 * Typically, a single call to @ref prepareShortestPathTopo()
164 * should be followed by a large number of calls to
165 * method @ref getTopoShortestPath().
166 * After the last @ref getTopoShortestPath() call,
167 * method @ref dropShortestPathTopo() should be used to release
168 * the internal state that is not needed anymore:
169 *
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000170 * Map<Long, ?> shortestPathTopo;
171 * shortestPathTopo = prepareShortestPathTopo();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700172 * for (int i = 0; i < 10000; i++) {
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000173 * dataPath = getTopoShortestPath(shortestPathTopo, ...);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700174 * ...
175 * }
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000176 * dropShortestPathTopo(shortestPathTopo);
177 *
178 * @return the Shortest Path info handler stored in a map.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700179 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000180 public Map<Long, ?> prepareShortestPathTopo() {
181 Map<Long, Node> shortestPathTopo = new HashMap<Long, Node>();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700182
183 //
184 // Fetch the relevant info from the Switch and Port vertices
185 // from the Titan Graph.
186 //
Toshio Koide18e47202013-06-13 14:07:13 -0700187 Iterable<ISwitchObject> nodes = op.getActiveSwitches();
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700188 for (ISwitchObject switchObj : nodes) {
189 Vertex nodeVertex = switchObj.asVertex();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700190 //
191 // The Switch info
192 //
193 String nodeDpid = nodeVertex.getProperty("dpid").toString();
194 long nodeId = HexString.toLong(nodeDpid);
195 Node me = shortestPathTopo.get(nodeId);
196 if (me == null) {
197 me = new Node(nodeId);
198 shortestPathTopo.put(nodeId, me);
199 }
200
201 //
202 // The local Port info
203 //
204 for (Vertex myPortVertex : nodeVertex.getVertices(Direction.OUT, "on")) {
Pavlin Radoslavov65d50b52013-09-05 14:24:59 -0700205 // Ignore inactive ports
206 if (! myPortVertex.getProperty("state").toString().equals("ACTIVE"))
207 continue;
208
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700209 short myPort = 0;
210 Object obj = myPortVertex.getProperty("number");
211 if (obj instanceof Short) {
212 myPort = (Short)obj;
213 } else if (obj instanceof Integer) {
214 Integer int_nodeId = (Integer)obj;
215 myPort = int_nodeId.shortValue();
216 }
217
218 //
219 // The neighbor Port info
220 //
221 for (Vertex neighborPortVertex : myPortVertex.getVertices(Direction.OUT, "link")) {
Pavlin Radoslavov65d50b52013-09-05 14:24:59 -0700222 // Ignore inactive ports
223 if (! neighborPortVertex.getProperty("state").toString().equals("ACTIVE"))
224 continue;
225
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700226 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 *
Pavlin Radoslavoved13a242013-06-20 17:37:20 -0700267 * @param 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")) {
Pavlin Radoslavov65d50b52013-09-05 14:24:59 -0700459 // Ignore inactive ports
460 if (! parentPort.getProperty("state").toString().equals("ACTIVE"))
461 continue;
462
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700463 for (Vertex childPort : parentPort.getVertices(Direction.OUT, "link")) {
Pavlin Radoslavov65d50b52013-09-05 14:24:59 -0700464 // Ignore inactive ports
465 if (! childPort.getProperty("state").toString().equals("ACTIVE"))
466 continue;
467
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700468 for (Vertex child : childPort.getVertices(Direction.IN, "on")) {
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700469 // Ignore inactive switches
470 String state = child.getProperty("state").toString();
471 if (! state.equals(SwitchState.ACTIVE.toString()))
472 continue;
473
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700474 if (! visitedSet.contains(child)) {
475 previousVertexMap.put(parentPort, nextVertex);
476 previousVertexMap.put(childPort, parentPort);
477 previousVertexMap.put(child, childPort);
478 visitedSet.add(child);
479 processingList.add(child);
480 }
481 }
482 }
483 }
484 }
485 if (! path_found)
486 return null; // No path found
487
488 List<Vertex> resultPath = new LinkedList<Vertex>();
489 Vertex previousVertex = v_dest;
490 resultPath.add(v_dest);
491 while (! v_src.equals(previousVertex)) {
492 Vertex currentVertex = previousVertexMap.get(previousVertex);
493 resultPath.add(currentVertex);
494 previousVertex = currentVertex;
495 }
496 Collections.reverse(resultPath);
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800497
Pankaj Berde15193092013-03-21 17:30:14 -0700498
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800499 //
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700500 // Loop through the result and prepare the return result
501 // as a list of Flow Entries.
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800502 //
503 long nodeId = 0;
504 short portId = 0;
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800505 Port inPort = new Port(src.port().value());
506 Port outPort = new Port();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700507 int idx = 0;
508 for (Vertex v: resultPath) {
509 String type = v.getProperty("type").toString();
510 // System.out.println("type: " + type);
511 if (type.equals("port")) {
512 String number = v.getProperty("number").toString();
513 // System.out.println("number: " + number);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800514
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700515 Object obj = v.getProperty("number");
516 // String class_str = obj.getClass().toString();
517 if (obj instanceof Short) {
518 portId = (Short)obj;
519 } else if (obj instanceof Integer) {
520 Integer int_nodeId = (Integer)obj;
521 portId = int_nodeId.shortValue();
522 // int int_nodeId = (Integer)obj;
523 // portId = (short)int_nodeId.;
524 }
525 } else if (type.equals("switch")) {
526 String dpid = v.getProperty("dpid").toString();
527 nodeId = HexString.toLong(dpid);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800528
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700529 // System.out.println("dpid: " + dpid);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800530 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700531 idx++;
532 if (idx == 1) {
533 continue;
534 }
535 int mod = idx % 3;
536 if (mod == 0) {
537 // Setup the incoming port
538 inPort = new Port(portId);
539 continue;
540 }
541 if (mod == 2) {
542 // Setup the outgoing port, and add the Flow Entry
543 outPort = new Port(portId);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800544
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800545 FlowEntry flowEntry = new FlowEntry();
546 flowEntry.setDpid(new Dpid(nodeId));
547 flowEntry.setInPort(inPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700548 flowEntry.setOutPort(outPort);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800549 result_data_path.flowEntries().add(flowEntry);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700550 continue;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800551 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800552 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700553 if (idx > 0) {
554 // Add the last Flow Entry
555 FlowEntry flowEntry = new FlowEntry();
556 flowEntry.setDpid(new Dpid(nodeId));
557 flowEntry.setInPort(inPort);
558 flowEntry.setOutPort(dest.port());
559 result_data_path.flowEntries().add(flowEntry);
560 }
561
Toshio Koide18e47202013-06-13 14:07:13 -0700562 op.commit();
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800563 if (result_data_path.flowEntries().size() > 0)
564 return result_data_path;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800565
566 return null;
567 }
568
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700569 /**
570 * Test whether a route exists from a source to a destination.
571 *
572 * @param src the source node for the test.
573 * @param dest the destination node for the test.
574 * @return true if a route exists, otherwise false.
575 */
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800576 @Override
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800577 public Boolean routeExists(SwitchPort src, SwitchPort dest) {
578 DataPath dataPath = getShortestPath(src, dest);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700579 return (dataPath != null);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800580 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800581}