blob: 1133d3decbb33ee3522b25589910feba8fb9e807 [file] [log] [blame]
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001package net.onrc.onos.ofcontroller.topology;
2
3import java.util.Collections;
4import java.util.HashMap;
5import java.util.HashSet;
6import java.util.LinkedList;
7import java.util.List;
8import java.util.Map;
9import java.util.Queue;
10import java.util.Set;
11
12import net.onrc.onos.graph.GraphDBOperation;
13import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
14import net.onrc.onos.ofcontroller.core.ISwitchStorage.SwitchState;
15import 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;
20
21import org.openflow.util.HexString;
22
23import com.tinkerpop.blueprints.Direction;
24import com.tinkerpop.blueprints.Vertex;
25
26/**
27 * A class for implementing the Shortest Path in a topology.
28 */
29public class ShortestPath {
30 /**
31 * Get the shortest path from a source to a destination by
32 * using the pre-populated local topology state prepared
33 * by method @ref TopologyManager.newDatabaseTopology().
34 *
35 * For additional documentation and usage, see method
36 * @ref TopologyManager.newDatabaseTopology()
37 *
38 * @param topology the topology handler to use.
39 * @param src the source in the shortest path computation.
40 * @param dest the destination in the shortest path computation.
41 * @return the data path with the computed shortest path if
42 * found, otherwise null.
43 */
44 public static DataPath getTopologyShortestPath(
45 Topology topology,
46 SwitchPort src, SwitchPort dest) {
47 DataPath result_data_path = new DataPath();
48
49 // Initialize the source and destination in the data path to return
50 result_data_path.setSrcPort(src);
51 result_data_path.setDstPort(dest);
52
53 String dpid_src = src.dpid().toString();
54 String dpid_dest = dest.dpid().toString();
55
56 // Get the source vertex
57 Node v_src = topology.getNode(src.dpid().value());
58 if (v_src == null) {
59 return null; // Source vertex not found
60 }
61
62 // Get the destination vertex
63 Node v_dest = topology.getNode(dest.dpid().value());
64 if (v_dest == null) {
65 return null; // Destination vertex not found
66 }
67
68 //
69 // Test whether we are computing a path from/to the same DPID.
70 // If "yes", then just add a single flow entry in the return result.
71 //
72 if (dpid_src.equals(dpid_dest)) {
73 FlowEntry flowEntry = new FlowEntry();
74 flowEntry.setDpid(src.dpid());
75 flowEntry.setInPort(src.port());
76 flowEntry.setOutPort(dest.port());
77 result_data_path.flowEntries().add(flowEntry);
78 return result_data_path;
79 }
80
81 //
82 // Implement the Shortest Path computation by using Breath First Search
83 //
84 Set<Node> visitedSet = new HashSet<Node>();
85 Queue<Node> processingList = new LinkedList<Node>();
86 Map<Node, Node.Link> previousVertexMap = new HashMap<Node, Node.Link>();
87 processingList.add(v_src);
88 visitedSet.add(v_src);
89 Boolean path_found = false;
90 while (! processingList.isEmpty()) {
91 Node nextVertex = processingList.poll();
92 if (v_dest == nextVertex) {
93 path_found = true;
94 break;
95 }
96 for (Node.Link link : nextVertex.links.values()) {
97 Node child = link.neighbor;
98 if (! visitedSet.contains(child)) {
99 previousVertexMap.put(child, link);
100 visitedSet.add(child);
101 processingList.add(child);
102 }
103 }
104 }
105 if (! path_found)
106 return null; // No path found
107
108 // Collect the path as a list of links
109 List<Node.Link> resultPath = new LinkedList<Node.Link>();
110 Node previousVertex = v_dest;
111 while (! v_src.equals(previousVertex)) {
112 Node.Link currentLink = previousVertexMap.get(previousVertex);
113 resultPath.add(currentLink);
114 previousVertex = currentLink.me;
115 }
116 Collections.reverse(resultPath);
117
118 //
119 // Loop through the result and prepare the return result
120 // as a list of Flow Entries.
121 //
122 Port inPort = new Port(src.port().value());
123 Port outPort;
124 for (Node.Link link: resultPath) {
125 // Setup the outgoing port, and add the Flow Entry
126 outPort = new Port(link.myPort);
127
128 FlowEntry flowEntry = new FlowEntry();
129 flowEntry.setDpid(new Dpid(link.me.nodeId));
130 flowEntry.setInPort(inPort);
131 flowEntry.setOutPort(outPort);
132 result_data_path.flowEntries().add(flowEntry);
133
134 // Setup the next incoming port
135 inPort = new Port(link.neighborPort);
136 }
137 if (resultPath.size() > 0) {
138 // Add the last Flow Entry
139 FlowEntry flowEntry = new FlowEntry();
140 flowEntry.setDpid(new Dpid(dest.dpid().value()));
141 flowEntry.setInPort(inPort);
142 flowEntry.setOutPort(dest.port());
143 result_data_path.flowEntries().add(flowEntry);
144 }
145
146 if (result_data_path.flowEntries().size() > 0)
147 return result_data_path;
148
149 return null;
150 }
151
152 /**
153 * Get the shortest path from a source to a destination by using
154 * the underlying Graph Database.
155 *
156 * @param dbHandler the Graph Database handler to use.
157 * @param src the source in the shortest path computation.
158 * @param dest the destination in the shortest path computation.
159 * @return the data path with the computed shortest path if
160 * found, otherwise null.
161 */
162 public static DataPath getDatabaseShortestPath(GraphDBOperation dbHandler,
163 SwitchPort src, SwitchPort dest) {
164 DataPath result_data_path = new DataPath();
165
166 // Initialize the source and destination in the data path to return
167 result_data_path.setSrcPort(src);
168 result_data_path.setDstPort(dest);
169
170 String dpid_src = src.dpid().toString();
171 String dpid_dest = dest.dpid().toString();
172
173 // Get the source and destination switches
174 ISwitchObject srcSwitch =
175 dbHandler.searchActiveSwitch(dpid_src);
176 ISwitchObject destSwitch =
177 dbHandler.searchActiveSwitch(dpid_dest);
178 if (srcSwitch == null || destSwitch == null) {
179 return null;
180 }
181
182 //
183 // Test whether we are computing a path from/to the same DPID.
184 // If "yes", then just add a single flow entry in the return result.
185 //
186 if (dpid_src.equals(dpid_dest)) {
187 FlowEntry flowEntry = new FlowEntry();
188 flowEntry.setDpid(src.dpid());
189 flowEntry.setInPort(src.port());
190 flowEntry.setOutPort(dest.port());
191 result_data_path.flowEntries().add(flowEntry);
192 dbHandler.commit();
193 return result_data_path;
194 }
195
196 Vertex v_src = srcSwitch.asVertex();
197 Vertex v_dest = destSwitch.asVertex();
198
199 //
200 // Implement the Shortest Path computation by using Breath First Search
201 //
202 Set<Vertex> visitedSet = new HashSet<Vertex>();
203 Queue<Vertex> processingList = new LinkedList<Vertex>();
204 Map<Vertex, Vertex> previousVertexMap = new HashMap<Vertex, Vertex>();
205
206 processingList.add(v_src);
207 visitedSet.add(v_src);
208 Boolean path_found = false;
209 while (! processingList.isEmpty()) {
210 Vertex nextVertex = processingList.poll();
211 if (v_dest.equals(nextVertex)) {
212 path_found = true;
213 break;
214 }
215 for (Vertex parentPort : nextVertex.getVertices(Direction.OUT, "on")) {
216 // Ignore inactive ports
217 if (! parentPort.getProperty("state").toString().equals("ACTIVE"))
218 continue;
219
220 for (Vertex childPort : parentPort.getVertices(Direction.OUT, "link")) {
221 // Ignore inactive ports
222 if (! childPort.getProperty("state").toString().equals("ACTIVE"))
223 continue;
224
225 for (Vertex child : childPort.getVertices(Direction.IN, "on")) {
226 // Ignore inactive switches
227 String state = child.getProperty("state").toString();
228 if (! state.equals(SwitchState.ACTIVE.toString()))
229 continue;
230
231 if (! visitedSet.contains(child)) {
232 previousVertexMap.put(parentPort, nextVertex);
233 previousVertexMap.put(childPort, parentPort);
234 previousVertexMap.put(child, childPort);
235 visitedSet.add(child);
236 processingList.add(child);
237 }
238 }
239 }
240 }
241 }
242 if (! path_found)
243 return null; // No path found
244
245 List<Vertex> resultPath = new LinkedList<Vertex>();
246 Vertex previousVertex = v_dest;
247 resultPath.add(v_dest);
248 while (! v_src.equals(previousVertex)) {
249 Vertex currentVertex = previousVertexMap.get(previousVertex);
250 resultPath.add(currentVertex);
251 previousVertex = currentVertex;
252 }
253 Collections.reverse(resultPath);
254
255
256 //
257 // Loop through the result and prepare the return result
258 // as a list of Flow Entries.
259 //
260 long nodeId = 0;
261 short portId = 0;
262 Port inPort = new Port(src.port().value());
263 Port outPort = new Port();
264 int idx = 0;
265 for (Vertex v: resultPath) {
266 String type = v.getProperty("type").toString();
267 // System.out.println("type: " + type);
268 if (type.equals("port")) {
269 //String number = v.getProperty("number").toString();
270 // System.out.println("number: " + number);
271
272 Object obj = v.getProperty("number");
273 // String class_str = obj.getClass().toString();
274 if (obj instanceof Short) {
275 portId = (Short)obj;
276 } else if (obj instanceof Integer) {
277 Integer int_nodeId = (Integer)obj;
278 portId = int_nodeId.shortValue();
279 // int int_nodeId = (Integer)obj;
280 // portId = (short)int_nodeId.;
281 }
282 } else if (type.equals("switch")) {
283 String dpid = v.getProperty("dpid").toString();
284 nodeId = HexString.toLong(dpid);
285
286 // System.out.println("dpid: " + dpid);
287 }
288 idx++;
289 if (idx == 1) {
290 continue;
291 }
292 int mod = idx % 3;
293 if (mod == 0) {
294 // Setup the incoming port
295 inPort = new Port(portId);
296 continue;
297 }
298 if (mod == 2) {
299 // Setup the outgoing port, and add the Flow Entry
300 outPort = new Port(portId);
301
302 FlowEntry flowEntry = new FlowEntry();
303 flowEntry.setDpid(new Dpid(nodeId));
304 flowEntry.setInPort(inPort);
305 flowEntry.setOutPort(outPort);
306 result_data_path.flowEntries().add(flowEntry);
307 continue;
308 }
309 }
310 if (idx > 0) {
311 // Add the last Flow Entry
312 FlowEntry flowEntry = new FlowEntry();
313 flowEntry.setDpid(new Dpid(nodeId));
314 flowEntry.setInPort(inPort);
315 flowEntry.setOutPort(dest.port());
316 result_data_path.flowEntries().add(flowEntry);
317 }
318
319 dbHandler.commit();
320 if (result_data_path.flowEntries().size() > 0)
321 return result_data_path;
322
323 return null;
324 }
325}