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