blob: 0aa5f2e80e672ed2d88c5f1025679f171795a653 [file] [log] [blame]
HIGUCHI Yuta4e64f312013-06-12 14:40:39 -07001package net.onrc.onos.ofcontroller.routing;
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
yoshi2fd4c7e2013-11-22 15:47:55 -080012import net.onrc.onos.graph.DBOperation;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070013import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
14import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoRouteService;
15import net.onrc.onos.ofcontroller.core.ISwitchStorage.SwitchState;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070016import net.onrc.onos.ofcontroller.util.DataPath;
17import net.onrc.onos.ofcontroller.util.Dpid;
18import net.onrc.onos.ofcontroller.util.FlowEntry;
19import net.onrc.onos.ofcontroller.util.Port;
20import net.onrc.onos.ofcontroller.util.SwitchPort;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080021
22import org.openflow.util.HexString;
Pankaj Berde15193092013-03-21 17:30:14 -070023import org.slf4j.Logger;
24import org.slf4j.LoggerFactory;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080025
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070026import com.tinkerpop.blueprints.Direction;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080027import com.tinkerpop.blueprints.Vertex;
yoshi2fd4c7e2013-11-22 15:47:55 -080028import net.onrc.onos.graph.GraphDBManager;
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -080029
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070030
31/**
32 * A class for storing Node and Link information for fast computation
33 * of shortest paths.
34 */
35class Node {
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070036 /**
37 * A class for storing Link information for fast computation of shortest
38 * paths.
39 */
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070040 class Link {
41 public Node me; // The node this link originates from
42 public Node neighbor; // The neighbor node on the other side
43 public short myPort; // Local port number for the link
44 public short neighborPort; // Neighbor port number for the link
45
46 /**
47 * Link constructor.
48 *
49 * @param me the node this link originates from.
50 * @param the neighbor node on the other side of the link.
51 * @param myPort local port number for the link.
yoshi2fd4c7e2013-11-22 15:47:55 -080052 * @param neighborPort neighbor port number for the link.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070053 */
54 public Link(Node me, Node neighbor, short myPort, short neighborPort) {
55 this.me = me;
56 this.neighbor = neighbor;
57 this.myPort = myPort;
58 this.neighborPort = neighborPort;
59 }
60 };
61
62 public long nodeId; // The node ID
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -070063 public HashMap<Short, Link> links; // The links originating from this node
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070064
65 /**
66 * Node constructor.
67 *
68 * @param nodeId the node ID.
69 */
70 public Node(long nodeId) {
71 this.nodeId = nodeId;
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -070072 links = new HashMap<Short, Link>();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070073 }
74
75 /**
76 * Add a neighbor.
77 *
78 * A new link to the neighbor will be created.
79 *
80 * @param neighbor the neighbor to add.
81 * @param myPort the local port number for the link to the neighbor.
82 * @param neighborPort the neighbor port number for the link.
83 */
84 public void addNeighbor(Node neighbor, short myPort, short neighborPort) {
85 Link link = new Link(this, neighbor, myPort, neighborPort);
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -070086 links.put(myPort, link);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -070087 }
88};
89
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -070090/**
91 * A class for implementing Topology Route Service.
92 */
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070093public class TopoRouteService implements ITopoRouteService {
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080094
95 /** The logger. */
Pavlin Radoslavov19343432013-03-06 10:43:18 -080096 private static Logger log =
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -080097 LoggerFactory.getLogger(TopoRouteService.class);
Pankaj Berde15193092013-03-21 17:30:14 -070098
yoshi2fd4c7e2013-11-22 15:47:55 -080099 protected DBOperation op;
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800100
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700101
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700102 /**
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700103 * Default constructor.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700104 */
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700105 public TopoRouteService() {
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800106 }
107
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700108 /**
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700109 * Constructor for given database configuration file.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700110 *
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700111 * @param config the database configuration file to use for
112 * the initialization.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700113 */
yoshi2fd4c7e2013-11-22 15:47:55 -0800114 public TopoRouteService(final String dbStore, final String config) {
115 this.init(dbStore, config);
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800116 }
117
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700118 /**
119 * Init the module.
120 *
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700121 * @param config the database configuration file to use for
122 * the initialization.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700123 */
yoshi2fd4c7e2013-11-22 15:47:55 -0800124 public void init(final String dbStore, final String config) {
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700125 try {
yoshi2fd4c7e2013-11-22 15:47:55 -0800126 op = GraphDBManager.getDBOperation(dbStore, config);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700127 } catch (Exception e) {
128 log.error(e.getMessage());
129 }
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800130 }
131
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700132 /**
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700133 * Close the service. It will close the corresponding database connection.
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700134 */
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700135 public void close() {
136 op.close();
Pavlin Radoslavovd7d8b792013-02-22 10:24:38 -0800137 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800138
Pavlin Radoslavovc5d2fbc2013-06-27 18:15:56 -0700139 /**
140 * Set the database operation handler.
141 *
142 * @param init_op the database operation handler to use for the
143 * initialization.
144 */
yoshi2fd4c7e2013-11-22 15:47:55 -0800145 public void setDbOperationHandler(DBOperation init_op) {
Pavlin Radoslavovcec899a2013-06-27 15:47:50 -0700146 op = init_op;
147 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800148
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700149 /**
150 * Fetch the Switch and Ports info from the Titan Graph
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000151 * and return it for fast access during the shortest path
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700152 * computation.
153 *
154 * After fetching the state, method @ref getTopoShortestPath()
155 * can be used for fast shortest path computation.
156 *
157 * Note: There is certain cost to fetch the state, hence it should
158 * be used only when there is a large number of shortest path
159 * computations that need to be done on the same topology.
160 * Typically, a single call to @ref prepareShortestPathTopo()
161 * should be followed by a large number of calls to
162 * method @ref getTopoShortestPath().
163 * After the last @ref getTopoShortestPath() call,
164 * method @ref dropShortestPathTopo() should be used to release
165 * the internal state that is not needed anymore:
166 *
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000167 * Map<Long, ?> shortestPathTopo;
168 * shortestPathTopo = prepareShortestPathTopo();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700169 * for (int i = 0; i < 10000; i++) {
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000170 * dataPath = getTopoShortestPath(shortestPathTopo, ...);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700171 * ...
172 * }
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000173 * dropShortestPathTopo(shortestPathTopo);
174 *
175 * @return the Shortest Path info handler stored in a map.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700176 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000177 public Map<Long, ?> prepareShortestPathTopo() {
178 Map<Long, Node> shortestPathTopo = new HashMap<Long, Node>();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700179
180 //
181 // Fetch the relevant info from the Switch and Port vertices
182 // from the Titan Graph.
183 //
Toshio Koide18e47202013-06-13 14:07:13 -0700184 Iterable<ISwitchObject> nodes = op.getActiveSwitches();
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700185 for (ISwitchObject switchObj : nodes) {
186 Vertex nodeVertex = switchObj.asVertex();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700187 //
188 // The Switch info
189 //
190 String nodeDpid = nodeVertex.getProperty("dpid").toString();
191 long nodeId = HexString.toLong(nodeDpid);
192 Node me = shortestPathTopo.get(nodeId);
193 if (me == null) {
194 me = new Node(nodeId);
195 shortestPathTopo.put(nodeId, me);
196 }
197
198 //
199 // The local Port info
200 //
201 for (Vertex myPortVertex : nodeVertex.getVertices(Direction.OUT, "on")) {
Pavlin Radoslavov65d50b52013-09-05 14:24:59 -0700202 // Ignore inactive ports
203 if (! myPortVertex.getProperty("state").toString().equals("ACTIVE"))
204 continue;
205
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700206 short myPort = 0;
207 Object obj = myPortVertex.getProperty("number");
208 if (obj instanceof Short) {
209 myPort = (Short)obj;
210 } else if (obj instanceof Integer) {
211 Integer int_nodeId = (Integer)obj;
212 myPort = int_nodeId.shortValue();
213 }
214
215 //
216 // The neighbor Port info
217 //
218 for (Vertex neighborPortVertex : myPortVertex.getVertices(Direction.OUT, "link")) {
Pavlin Radoslavov65d50b52013-09-05 14:24:59 -0700219 // Ignore inactive ports
220 if (! neighborPortVertex.getProperty("state").toString().equals("ACTIVE"))
221 continue;
222
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700223 short neighborPort = 0;
224 obj = neighborPortVertex.getProperty("number");
225 if (obj instanceof Short) {
226 neighborPort = (Short)obj;
227 } else if (obj instanceof Integer) {
228 Integer int_nodeId = (Integer)obj;
229 neighborPort = int_nodeId.shortValue();
230 }
231 //
232 // The neighbor Switch info
233 //
234 for (Vertex neighborVertex : neighborPortVertex.getVertices(Direction.IN, "on")) {
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700235 // Ignore inactive switches
236 String state = neighborVertex.getProperty("state").toString();
237 if (! state.equals(SwitchState.ACTIVE.toString()))
238 continue;
239
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700240 String neighborDpid = neighborVertex.getProperty("dpid").toString();
241 long neighborId = HexString.toLong(neighborDpid);
242 Node neighbor = shortestPathTopo.get(neighborId);
243 if (neighbor == null) {
244 neighbor = new Node(neighborId);
245 shortestPathTopo.put(neighborId, neighbor);
246 }
247 me.addNeighbor(neighbor, myPort, neighborPort);
248 }
249 }
250 }
251 }
Toshio Koide18e47202013-06-13 14:07:13 -0700252 op.commit();
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000253
254 return shortestPathTopo;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700255 }
256
257 /**
258 * Release the state that was populated by
259 * method @ref prepareShortestPathTopo().
260 *
261 * See the documentation for method @ref prepareShortestPathTopo()
262 * for additional information and usage.
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000263 *
Pavlin Radoslavoved13a242013-06-20 17:37:20 -0700264 * @param shortestPathTopo the Shortest Path info handler to release.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700265 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000266 public void dropShortestPathTopo(Map<Long, ?> shortestPathTopo) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700267 shortestPathTopo = null;
268 }
269
270 /**
271 * Get the shortest path from a source to a destination by
272 * using the pre-populated local topology state prepared
273 * by method @ref prepareShortestPathTopo().
274 *
275 * See the documentation for method @ref prepareShortestPathTopo()
276 * for additional information and usage.
277 *
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000278 * @param shortestPathTopoHandler the Shortest Path info handler
279 * to use.
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700280 * @param src the source in the shortest path computation.
281 * @param dest the destination in the shortest path computation.
282 * @return the data path with the computed shortest path if
283 * found, otherwise null.
284 */
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000285 public DataPath getTopoShortestPath(Map<Long, ?> shortestPathTopoHandler,
286 SwitchPort src, SwitchPort dest) {
287 @SuppressWarnings("unchecked")
288 Map<Long, Node> shortestPathTopo = (Map)shortestPathTopoHandler;
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700289 DataPath result_data_path = new DataPath();
290
291 // Initialize the source and destination in the data path to return
292 result_data_path.setSrcPort(src);
293 result_data_path.setDstPort(dest);
294
295 String dpid_src = src.dpid().toString();
296 String dpid_dest = dest.dpid().toString();
297
298 // Get the source vertex
299 Node v_src = shortestPathTopo.get(src.dpid().value());
300 if (v_src == null) {
301 return null; // Source vertex not found
302 }
303
304 // Get the destination vertex
305 Node v_dest = shortestPathTopo.get(dest.dpid().value());
306 if (v_dest == null) {
307 return null; // Destination vertex not found
308 }
309
310 //
311 // Test whether we are computing a path from/to the same DPID.
312 // If "yes", then just add a single flow entry in the return result.
313 //
314 if (dpid_src.equals(dpid_dest)) {
315 FlowEntry flowEntry = new FlowEntry();
316 flowEntry.setDpid(src.dpid());
317 flowEntry.setInPort(src.port());
318 flowEntry.setOutPort(dest.port());
319 result_data_path.flowEntries().add(flowEntry);
320 return result_data_path;
321 }
322
323 //
324 // Implement the Shortest Path computation by using Breath First Search
325 //
326 Set<Node> visitedSet = new HashSet<Node>();
327 Queue<Node> processingList = new LinkedList<Node>();
328 Map<Node, Node.Link> previousVertexMap = new HashMap<Node, Node.Link>();
329 processingList.add(v_src);
330 visitedSet.add(v_src);
331 Boolean path_found = false;
332 while (! processingList.isEmpty()) {
333 Node nextVertex = processingList.poll();
334 if (v_dest == nextVertex) {
335 path_found = true;
336 break;
337 }
Pavlin Radoslavov16cbd372013-04-08 14:14:50 -0700338 for (Node.Link link : nextVertex.links.values()) {
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700339 Node child = link.neighbor;
340 if (! visitedSet.contains(child)) {
341 previousVertexMap.put(child, link);
342 visitedSet.add(child);
343 processingList.add(child);
344 }
345 }
346 }
347 if (! path_found)
348 return null; // No path found
349
350 // Collect the path as a list of links
351 List<Node.Link> resultPath = new LinkedList<Node.Link>();
352 Node previousVertex = v_dest;
353 while (! v_src.equals(previousVertex)) {
354 Node.Link currentLink = previousVertexMap.get(previousVertex);
355 resultPath.add(currentLink);
356 previousVertex = currentLink.me;
357 }
358 Collections.reverse(resultPath);
359
360 //
361 // Loop through the result and prepare the return result
362 // as a list of Flow Entries.
363 //
364 Port inPort = new Port(src.port().value());
365 Port outPort;
366 for (Node.Link link: resultPath) {
367 // Setup the outgoing port, and add the Flow Entry
Pavlin Radoslavova1ff1192013-03-29 04:11:32 -0700368 outPort = new Port(link.myPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700369
370 FlowEntry flowEntry = new FlowEntry();
371 flowEntry.setDpid(new Dpid(link.me.nodeId));
372 flowEntry.setInPort(inPort);
373 flowEntry.setOutPort(outPort);
374 result_data_path.flowEntries().add(flowEntry);
375
376 // Setup the next incoming port
377 inPort = new Port(link.neighborPort);
378 }
379 if (resultPath.size() > 0) {
380 // Add the last Flow Entry
381 FlowEntry flowEntry = new FlowEntry();
382 flowEntry.setDpid(new Dpid(dest.dpid().value()));
383 flowEntry.setInPort(inPort);
384 flowEntry.setOutPort(dest.port());
385 result_data_path.flowEntries().add(flowEntry);
386 }
387
388 if (result_data_path.flowEntries().size() > 0)
389 return result_data_path;
390
391 return null;
392 }
393
394 /**
395 * Get the shortest path from a source to a destination.
396 *
397 * @param src the source in the shortest path computation.
398 * @param dest the destination in the shortest path computation.
399 * @return the data path with the computed shortest path if
400 * found, otherwise null.
401 */
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800402 @Override
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800403 public DataPath getShortestPath(SwitchPort src, SwitchPort dest) {
404 DataPath result_data_path = new DataPath();
405
406 // Initialize the source and destination in the data path to return
407 result_data_path.setSrcPort(src);
408 result_data_path.setDstPort(dest);
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800409
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800410 String dpid_src = src.dpid().toString();
411 String dpid_dest = dest.dpid().toString();
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800412
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700413 // Get the source and destination switches
414 ISwitchObject srcSwitch =
Toshio Koide18e47202013-06-13 14:07:13 -0700415 op.searchActiveSwitch(dpid_src);
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700416 ISwitchObject destSwitch =
Toshio Koide18e47202013-06-13 14:07:13 -0700417 op.searchActiveSwitch(dpid_dest);
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700418 if (srcSwitch == null || destSwitch == null) {
419 return null;
420 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800421
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800422 //
423 // Test whether we are computing a path from/to the same DPID.
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800424 // If "yes", then just add a single flow entry in the return result.
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800425 //
426 if (dpid_src.equals(dpid_dest)) {
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800427 FlowEntry flowEntry = new FlowEntry();
428 flowEntry.setDpid(src.dpid());
429 flowEntry.setInPort(src.port());
430 flowEntry.setOutPort(dest.port());
431 result_data_path.flowEntries().add(flowEntry);
Toshio Koide18e47202013-06-13 14:07:13 -0700432 op.commit();
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800433 return result_data_path;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800434 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800435
Pankaj Berde15193092013-03-21 17:30:14 -0700436 Vertex v_src = srcSwitch.asVertex();
437 Vertex v_dest = destSwitch.asVertex();
438
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700439 //
440 // Implement the Shortest Path computation by using Breath First Search
441 //
442 Set<Vertex> visitedSet = new HashSet<Vertex>();
443 Queue<Vertex> processingList = new LinkedList<Vertex>();
444 Map<Vertex, Vertex> previousVertexMap = new HashMap<Vertex, Vertex>();
445
446 processingList.add(v_src);
447 visitedSet.add(v_src);
448 Boolean path_found = false;
449 while (! processingList.isEmpty()) {
450 Vertex nextVertex = processingList.poll();
451 if (v_dest.equals(nextVertex)) {
452 path_found = true;
453 break;
454 }
455 for (Vertex parentPort : nextVertex.getVertices(Direction.OUT, "on")) {
Pavlin Radoslavov65d50b52013-09-05 14:24:59 -0700456 // Ignore inactive ports
457 if (! parentPort.getProperty("state").toString().equals("ACTIVE"))
458 continue;
459
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700460 for (Vertex childPort : parentPort.getVertices(Direction.OUT, "link")) {
Pavlin Radoslavov65d50b52013-09-05 14:24:59 -0700461 // Ignore inactive ports
462 if (! childPort.getProperty("state").toString().equals("ACTIVE"))
463 continue;
464
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700465 for (Vertex child : childPort.getVertices(Direction.IN, "on")) {
Pavlin Radoslavov010f2862013-03-28 16:44:20 -0700466 // Ignore inactive switches
467 String state = child.getProperty("state").toString();
468 if (! state.equals(SwitchState.ACTIVE.toString()))
469 continue;
470
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700471 if (! visitedSet.contains(child)) {
472 previousVertexMap.put(parentPort, nextVertex);
473 previousVertexMap.put(childPort, parentPort);
474 previousVertexMap.put(child, childPort);
475 visitedSet.add(child);
476 processingList.add(child);
477 }
478 }
479 }
480 }
481 }
482 if (! path_found)
483 return null; // No path found
484
485 List<Vertex> resultPath = new LinkedList<Vertex>();
486 Vertex previousVertex = v_dest;
487 resultPath.add(v_dest);
488 while (! v_src.equals(previousVertex)) {
489 Vertex currentVertex = previousVertexMap.get(previousVertex);
490 resultPath.add(currentVertex);
491 previousVertex = currentVertex;
492 }
493 Collections.reverse(resultPath);
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800494
Pankaj Berde15193092013-03-21 17:30:14 -0700495
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800496 //
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700497 // Loop through the result and prepare the return result
498 // as a list of Flow Entries.
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800499 //
500 long nodeId = 0;
501 short portId = 0;
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800502 Port inPort = new Port(src.port().value());
503 Port outPort = new Port();
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700504 int idx = 0;
505 for (Vertex v: resultPath) {
506 String type = v.getProperty("type").toString();
507 // System.out.println("type: " + type);
508 if (type.equals("port")) {
509 String number = v.getProperty("number").toString();
510 // System.out.println("number: " + number);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800511
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700512 Object obj = v.getProperty("number");
513 // String class_str = obj.getClass().toString();
514 if (obj instanceof Short) {
515 portId = (Short)obj;
516 } else if (obj instanceof Integer) {
517 Integer int_nodeId = (Integer)obj;
518 portId = int_nodeId.shortValue();
519 // int int_nodeId = (Integer)obj;
520 // portId = (short)int_nodeId.;
521 }
522 } else if (type.equals("switch")) {
523 String dpid = v.getProperty("dpid").toString();
524 nodeId = HexString.toLong(dpid);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800525
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700526 // System.out.println("dpid: " + dpid);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800527 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700528 idx++;
529 if (idx == 1) {
530 continue;
531 }
532 int mod = idx % 3;
533 if (mod == 0) {
534 // Setup the incoming port
535 inPort = new Port(portId);
536 continue;
537 }
538 if (mod == 2) {
539 // Setup the outgoing port, and add the Flow Entry
540 outPort = new Port(portId);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800541
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800542 FlowEntry flowEntry = new FlowEntry();
543 flowEntry.setDpid(new Dpid(nodeId));
544 flowEntry.setInPort(inPort);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700545 flowEntry.setOutPort(outPort);
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800546 result_data_path.flowEntries().add(flowEntry);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700547 continue;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800548 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800549 }
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700550 if (idx > 0) {
551 // Add the last Flow Entry
552 FlowEntry flowEntry = new FlowEntry();
553 flowEntry.setDpid(new Dpid(nodeId));
554 flowEntry.setInPort(inPort);
555 flowEntry.setOutPort(dest.port());
556 result_data_path.flowEntries().add(flowEntry);
557 }
558
Toshio Koide18e47202013-06-13 14:07:13 -0700559 op.commit();
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800560 if (result_data_path.flowEntries().size() > 0)
561 return result_data_path;
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800562
563 return null;
564 }
565
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700566 /**
567 * Test whether a route exists from a source to a destination.
568 *
569 * @param src the source node for the test.
570 * @param dest the destination node for the test.
571 * @return true if a route exists, otherwise false.
572 */
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800573 @Override
Pavlin Radoslavovf83aa442013-02-26 14:09:01 -0800574 public Boolean routeExists(SwitchPort src, SwitchPort dest) {
575 DataPath dataPath = getShortestPath(src, dest);
Pavlin Radoslavova5f167b2013-03-21 11:39:27 -0700576 return (dataPath != null);
Pavlin Radoslavovf34c2902013-02-22 10:33:34 -0800577 }
Pavlin Radoslavov382b22a2013-01-28 09:24:04 -0800578}