blob: d9e1314ddb2f5c6a3105636d5126e3cb0d4f398c [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
yoshi0fee3de2013-11-23 09:13:37 -080012import net.onrc.onos.graph.DBOperation;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070013import 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.
Pavlin Radoslavovfbb9ef32013-12-13 13:02:35 -080072 // However, if the "in" and "out" ports are same, return null.
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070073 //
74 if (dpid_src.equals(dpid_dest)) {
Pavlin Radoslavovfbb9ef32013-12-13 13:02:35 -080075 if (src.port().value() == dest.port().value())
76 return null; // "In" and "Out" ports are same
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070077 FlowEntry flowEntry = new FlowEntry();
78 flowEntry.setDpid(src.dpid());
79 flowEntry.setInPort(src.port());
80 flowEntry.setOutPort(dest.port());
81 result_data_path.flowEntries().add(flowEntry);
82 return result_data_path;
83 }
84
85 //
86 // Implement the Shortest Path computation by using Breath First Search
87 //
88 Set<Node> visitedSet = new HashSet<Node>();
89 Queue<Node> processingList = new LinkedList<Node>();
90 Map<Node, Node.Link> previousVertexMap = new HashMap<Node, Node.Link>();
91 processingList.add(v_src);
92 visitedSet.add(v_src);
93 Boolean path_found = false;
94 while (! processingList.isEmpty()) {
95 Node nextVertex = processingList.poll();
96 if (v_dest == nextVertex) {
97 path_found = true;
98 break;
99 }
100 for (Node.Link link : nextVertex.links.values()) {
101 Node child = link.neighbor;
102 if (! visitedSet.contains(child)) {
103 previousVertexMap.put(child, link);
104 visitedSet.add(child);
105 processingList.add(child);
106 }
107 }
108 }
109 if (! path_found)
110 return null; // No path found
111
112 // Collect the path as a list of links
113 List<Node.Link> resultPath = new LinkedList<Node.Link>();
114 Node previousVertex = v_dest;
115 while (! v_src.equals(previousVertex)) {
116 Node.Link currentLink = previousVertexMap.get(previousVertex);
117 resultPath.add(currentLink);
118 previousVertex = currentLink.me;
119 }
120 Collections.reverse(resultPath);
121
122 //
123 // Loop through the result and prepare the return result
124 // as a list of Flow Entries.
125 //
126 Port inPort = new Port(src.port().value());
127 Port outPort;
128 for (Node.Link link: resultPath) {
129 // Setup the outgoing port, and add the Flow Entry
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700130 outPort = new Port((short)link.myPort);
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700131
132 FlowEntry flowEntry = new FlowEntry();
133 flowEntry.setDpid(new Dpid(link.me.nodeId));
134 flowEntry.setInPort(inPort);
135 flowEntry.setOutPort(outPort);
136 result_data_path.flowEntries().add(flowEntry);
137
138 // Setup the next incoming port
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700139 inPort = new Port((short)link.neighborPort);
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700140 }
141 if (resultPath.size() > 0) {
142 // Add the last Flow Entry
143 FlowEntry flowEntry = new FlowEntry();
144 flowEntry.setDpid(new Dpid(dest.dpid().value()));
145 flowEntry.setInPort(inPort);
146 flowEntry.setOutPort(dest.port());
147 result_data_path.flowEntries().add(flowEntry);
148 }
149
150 if (result_data_path.flowEntries().size() > 0)
151 return result_data_path;
152
153 return null;
154 }
155
156 /**
157 * Get the shortest path from a source to a destination by using
158 * the underlying Graph Database.
159 *
160 * @param dbHandler the Graph Database handler to use.
161 * @param src the source in the shortest path computation.
162 * @param dest the destination in the shortest path computation.
163 * @return the data path with the computed shortest path if
164 * found, otherwise null.
165 */
yoshi0fee3de2013-11-23 09:13:37 -0800166 public static DataPath getDatabaseShortestPath(DBOperation dbHandler,
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700167 SwitchPort src, SwitchPort dest) {
168 DataPath result_data_path = new DataPath();
169
170 // Initialize the source and destination in the data path to return
171 result_data_path.setSrcPort(src);
172 result_data_path.setDstPort(dest);
173
174 String dpid_src = src.dpid().toString();
175 String dpid_dest = dest.dpid().toString();
176
177 // Get the source and destination switches
178 ISwitchObject srcSwitch =
179 dbHandler.searchActiveSwitch(dpid_src);
180 ISwitchObject destSwitch =
181 dbHandler.searchActiveSwitch(dpid_dest);
182 if (srcSwitch == null || destSwitch == null) {
183 return null;
184 }
185
186 //
187 // Test whether we are computing a path from/to the same DPID.
188 // If "yes", then just add a single flow entry in the return result.
189 //
190 if (dpid_src.equals(dpid_dest)) {
191 FlowEntry flowEntry = new FlowEntry();
192 flowEntry.setDpid(src.dpid());
193 flowEntry.setInPort(src.port());
194 flowEntry.setOutPort(dest.port());
195 result_data_path.flowEntries().add(flowEntry);
196 dbHandler.commit();
197 return result_data_path;
198 }
199
200 Vertex v_src = srcSwitch.asVertex();
201 Vertex v_dest = destSwitch.asVertex();
202
203 //
204 // Implement the Shortest Path computation by using Breath First Search
205 //
206 Set<Vertex> visitedSet = new HashSet<Vertex>();
207 Queue<Vertex> processingList = new LinkedList<Vertex>();
208 Map<Vertex, Vertex> previousVertexMap = new HashMap<Vertex, Vertex>();
209
210 processingList.add(v_src);
211 visitedSet.add(v_src);
212 Boolean path_found = false;
213 while (! processingList.isEmpty()) {
214 Vertex nextVertex = processingList.poll();
215 if (v_dest.equals(nextVertex)) {
216 path_found = true;
217 break;
218 }
219 for (Vertex parentPort : nextVertex.getVertices(Direction.OUT, "on")) {
220 // Ignore inactive ports
221 if (! parentPort.getProperty("state").toString().equals("ACTIVE"))
222 continue;
223
224 for (Vertex childPort : parentPort.getVertices(Direction.OUT, "link")) {
225 // Ignore inactive ports
226 if (! childPort.getProperty("state").toString().equals("ACTIVE"))
227 continue;
228
229 for (Vertex child : childPort.getVertices(Direction.IN, "on")) {
230 // Ignore inactive switches
231 String state = child.getProperty("state").toString();
232 if (! state.equals(SwitchState.ACTIVE.toString()))
233 continue;
234
235 if (! visitedSet.contains(child)) {
236 previousVertexMap.put(parentPort, nextVertex);
237 previousVertexMap.put(childPort, parentPort);
238 previousVertexMap.put(child, childPort);
239 visitedSet.add(child);
240 processingList.add(child);
241 }
242 }
243 }
244 }
245 }
246 if (! path_found)
247 return null; // No path found
248
249 List<Vertex> resultPath = new LinkedList<Vertex>();
250 Vertex previousVertex = v_dest;
251 resultPath.add(v_dest);
252 while (! v_src.equals(previousVertex)) {
253 Vertex currentVertex = previousVertexMap.get(previousVertex);
254 resultPath.add(currentVertex);
255 previousVertex = currentVertex;
256 }
257 Collections.reverse(resultPath);
258
259
260 //
261 // Loop through the result and prepare the return result
262 // as a list of Flow Entries.
263 //
264 long nodeId = 0;
265 short portId = 0;
266 Port inPort = new Port(src.port().value());
267 Port outPort = new Port();
268 int idx = 0;
269 for (Vertex v: resultPath) {
270 String type = v.getProperty("type").toString();
271 // System.out.println("type: " + type);
272 if (type.equals("port")) {
273 //String number = v.getProperty("number").toString();
274 // System.out.println("number: " + number);
275
276 Object obj = v.getProperty("number");
277 // String class_str = obj.getClass().toString();
278 if (obj instanceof Short) {
279 portId = (Short)obj;
280 } else if (obj instanceof Integer) {
281 Integer int_nodeId = (Integer)obj;
282 portId = int_nodeId.shortValue();
283 // int int_nodeId = (Integer)obj;
284 // portId = (short)int_nodeId.;
285 }
286 } else if (type.equals("switch")) {
287 String dpid = v.getProperty("dpid").toString();
288 nodeId = HexString.toLong(dpid);
289
290 // System.out.println("dpid: " + dpid);
291 }
292 idx++;
293 if (idx == 1) {
294 continue;
295 }
296 int mod = idx % 3;
297 if (mod == 0) {
298 // Setup the incoming port
299 inPort = new Port(portId);
300 continue;
301 }
302 if (mod == 2) {
303 // Setup the outgoing port, and add the Flow Entry
304 outPort = new Port(portId);
305
306 FlowEntry flowEntry = new FlowEntry();
307 flowEntry.setDpid(new Dpid(nodeId));
308 flowEntry.setInPort(inPort);
309 flowEntry.setOutPort(outPort);
310 result_data_path.flowEntries().add(flowEntry);
311 continue;
312 }
313 }
314 if (idx > 0) {
315 // Add the last Flow Entry
316 FlowEntry flowEntry = new FlowEntry();
317 flowEntry.setDpid(new Dpid(nodeId));
318 flowEntry.setInPort(inPort);
319 flowEntry.setOutPort(dest.port());
320 result_data_path.flowEntries().add(flowEntry);
321 }
322
323 dbHandler.commit();
324 if (result_data_path.flowEntries().size() > 0)
325 return result_data_path;
326
327 return null;
328 }
yoshi0fee3de2013-11-23 09:13:37 -0800329}