blob: 612b72a6b1f2b4ea66f12898697338cd0db9b300 [file] [log] [blame]
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001package net.onrc.onos.ofcontroller.topology;
2
3import java.util.HashMap;
4import java.util.Map;
5
6import net.onrc.onos.graph.GraphDBOperation;
7import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
8import net.onrc.onos.ofcontroller.core.ISwitchStorage.SwitchState;
9
10import org.openflow.util.HexString;
11
12import com.tinkerpop.blueprints.Direction;
13import com.tinkerpop.blueprints.Vertex;
14
15/**
16 * A class for storing Node and Link information for fast computation
17 * of shortest paths.
18 */
19class Node {
20 /**
21 * A class for storing Link information for fast computation of shortest
22 * paths.
23 */
24 class Link {
25 public Node me; // The node this link originates from
26 public Node neighbor; // The neighbor node on the other side
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070027 public int myPort; // Local port ID for the link
28 public int neighborPort; // Neighbor port ID for the link
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070029
30 /**
31 * Link constructor.
32 *
33 * @param me the node this link originates from.
34 * @param the neighbor node on the other side of the link.
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070035 * @param myPort local port ID for the link.
36 * @param neighborPort neighbor port ID for the link.
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070037 */
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070038 public Link(Node me, Node neighbor, int myPort, int neighborPort) {
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070039 this.me = me;
40 this.neighbor = neighbor;
41 this.myPort = myPort;
42 this.neighborPort = neighborPort;
43 }
44 };
45
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070046 public long nodeId; // The node ID
47 public HashMap<Integer, Link> links; // The links from this node
48 private HashMap<Integer, Link> reverseLinksMap; // The links to this node
49 private HashMap<Integer, Integer> portsMap; // The ports for this node
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070050
51 /**
52 * Node constructor.
53 *
54 * @param nodeId the node ID.
55 */
56 public Node(long nodeId) {
57 this.nodeId = nodeId;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070058 links = new HashMap<Integer, Link>();
59 reverseLinksMap = new HashMap<Integer, Link>();
60 portsMap = new HashMap<Integer, Integer>();
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070061 }
62
63 /**
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070064 * Get all ports.
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070065 *
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070066 * @return all ports.
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070067 */
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070068 public Map<Integer, Integer> ports() {
69 return portsMap;
70 }
71
72 /**
73 * Get the port for a given Port ID.
74 *
75 * Note: For now the port itself is just the Port ID. In the future
76 * it might contain more information.
77 *
78 * @return the port if found, otherwise null.
79 */
80 public Integer getPort(int portId) {
81 return portsMap.get(nodeId);
82 }
83
84 /**
85 * Add a port for a given Port ID.
86 *
87 * Note: For now the port itself is just the Port ID. In the future
88 * it might contain more information.
89 *
90 * @param portId the Port ID of the port to add.
91 * @return the added Port.
92 */
93 Integer addPort(int portId) {
94 Integer port = new Integer(portId);
95 portsMap.put(portId, port);
96 return port;
97 }
98
99 /**
100 * Remove a port for a given Port ID.
101 *
102 * NOTE: The outgoing and incoming links using this port are removed as
103 * well.
104 */
105 void removePort(int portId) {
106 // Remove the outgoing link
107 Link link = getLink(portId);
108 if (link != null) {
109 link.neighbor.removeReverseLink(link);
110 removeLink(portId);
111 }
112
113 // Remove the incoming link
114 Link reverseLink = reverseLinksMap.get(portId);
115 if (reverseLink != null) {
116 // NOTE: reverseLink.myPort is the neighbor's outgoing port
117 reverseLink.neighbor.removeLink(reverseLink.myPort);
118 removeReverseLink(reverseLink);
119 }
120
121 portsMap.remove(portId);
122 }
123
124 /**
125 * Get a link on a port to a neighbor.
126 *
127 * @param myPortId the local port ID for the link to the neighbor.
128 * @return the link if found, otherwise null.
129 */
130 public Link getLink(int myPortId) {
131 return links.get(myPortId);
132 }
133
134 /**
135 * Add a link to a neighbor.
136 *
137 * @param myPortId the local port ID for the link to the neighbor.
138 * @param neighbor the neighbor for the link.
139 * @param neighborPortId the neighbor port ID for the link.
140 * @return the added Link.
141 */
142 public Link addLink(int myPortId, Node neighbor, int neighborPortId) {
143 Link link = new Link(this, neighbor, myPortId, neighborPortId);
144 links.put(myPortId, link);
145 neighbor.addReverseLink(link);
146 return link;
147 }
148
149 /**
150 * Add a reverse link from a neighbor.
151 *
152 * @param link the reverse link from a neighbor to add.
153 */
154 private void addReverseLink(Link link) {
155 // NOTE: link.neghborPort is my port
156 reverseLinksMap.put(link.neighborPort, link);
157 }
158
159 /**
160 * Remove a link to a neighbor.
161 *
162 * @param myPortId the local port ID for the link to the neighbor.
163 */
164 public void removeLink(int myPortId) {
165 links.remove(myPortId);
166 }
167
168 /**
169 * Remove a reverse link from a neighbor.
170 *
171 * @param link the reverse link from a neighbor to remove.
172 */
173 private void removeReverseLink(Link link) {
174 // NOTE: link.neghborPort is my port
175 reverseLinksMap.remove(link.neighborPort);
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700176 }
177};
178
179/**
180 * A class for storing topology information.
181 */
182public class Topology {
183 private Map<Long, Node> nodesMap; // The dpid->Node mapping
184
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700185 /**
186 * Default constructor.
187 */
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700188 public Topology() {
189 nodesMap = new HashMap<Long, Node>();
190 }
191
192 /**
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700193 * Add a topology element to the topology.
194 *
195 * @param topologyElement the topology element to add.
196 * @return true if the topology was modified, otherwise false.
197 */
198 public boolean addTopologyElement(TopologyElement topologyElement) {
199 boolean isModified = false;
200
201 switch (topologyElement.getType()) {
202 case ELEMENT_SWITCH: {
203 // Add the switch
204 Node node = getNode(topologyElement.getSwitch());
205 if (node == null) {
206 node = addNode(topologyElement.getSwitch());
207 isModified = true;
208 }
209 // Add the ports for the switch
210 for (Integer portId : topologyElement.getSwitchPorts().values()) {
211 Integer port = node.getPort(portId);
212 if (port == null) {
213 node.addPort(portId);
214 isModified = true;
215 }
216 }
217 break;
218 }
219 case ELEMENT_PORT: {
220 // Add the switch
221 Node node = getNode(topologyElement.getSwitch());
222 if (node == null) {
223 node = addNode(topologyElement.getSwitch());
224 isModified = true;
225 }
226 // Add the port for the switch
227 Integer port = node.getPort(topologyElement.getSwitchPort());
228 if (port == null) {
229 node.addPort(topologyElement.getSwitchPort());
230 isModified = true;
231 }
232 break;
233 }
234 case ELEMENT_LINK: {
235 // Add the "from" switch
236 Node fromNode = getNode(topologyElement.getFromSwitch());
237 if (fromNode == null) {
238 fromNode = addNode(topologyElement.getFromSwitch());
239 isModified = true;
240 }
241 // Add the "to" switch
242 Node toNode = getNode(topologyElement.getToSwitch());
243 if (toNode == null) {
244 toNode = addNode(topologyElement.getToSwitch());
245 isModified = true;
246 }
247 // Add the "from" port
248 Integer fromPort = fromNode.getPort(topologyElement.getFromPort());
249 if (fromPort == null) {
250 fromNode.addPort(topologyElement.getFromPort());
251 isModified = true;
252 }
253 // Add the "to" port
254 Integer toPort = fromNode.getPort(topologyElement.getToPort());
255 if (toPort == null) {
256 toNode.addPort(topologyElement.getToPort());
257 isModified = true;
258 }
259 Node.Link link = fromNode.getLink(topologyElement.getFromPort());
260 if (link == null) {
261 fromNode.addLink(topologyElement.getFromPort(),
262 toNode,
263 topologyElement.getToPort());
264 isModified = true;
265 }
266
267 break;
268 }
269 }
270
271 return isModified;
272 }
273
274 /**
275 * Remove a topology element from the topology.
276 *
277 * @param topologyElement the topology element to remove.
278 * @return true if the topology was modified, otherwise false.
279 */
280 public boolean removeTopologyElement(TopologyElement topologyElement) {
281 boolean isModified = false;
282
283 switch (topologyElement.getType()) {
284 case ELEMENT_SWITCH: {
285 // Remove the switch
286 Node node = getNode(topologyElement.getSwitch());
287 if (node != null) {
288 removeNode(node);
289 isModified = true;
290 }
291 break;
292 }
293 case ELEMENT_PORT: {
294 // Find the switch
295 Node node = getNode(topologyElement.getSwitch());
296 if (node == null)
297 break;
298 // Remove the port for the switch
299 Integer port = node.getPort(topologyElement.getSwitchPort());
300 if (port != null) {
301 node.removePort(topologyElement.getSwitchPort());
302 isModified = true;
303 }
304 break;
305 }
306 case ELEMENT_LINK: {
307 // Find the "from" switch
308 Node fromNode = getNode(topologyElement.getFromSwitch());
309 if (fromNode == null)
310 break;
311 // Remove the link originating from the "from" port
312 Node.Link link = fromNode.getLink(topologyElement.getFromPort());
313 if (link != null) {
314 fromNode.removeLink(topologyElement.getFromPort());
315 isModified = true;
316 }
317 break;
318 }
319 }
320
321 return isModified;
322 }
323
324 /**
325 * Get a node for a given Node ID.
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700326 *
327 * @param nodeId the Node ID to use.
328 * @return the corresponding Node if found, otherwise null.
329 */
330 Node getNode(long nodeId) {
331 return nodesMap.get(nodeId);
332 }
333
334 /**
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700335 * Add a node for a given Node ID.
336 *
337 * @param nodeId the Node ID to use.
338 * @return the added Node.
339 */
340 Node addNode(long nodeId) {
341 Node node = new Node(nodeId);
342 nodesMap.put(nodeId, node);
343 return node;
344 }
345
346 /**
347 * Remove an existing node.
348 *
349 * @param node the Node to remove.
350 */
351 void removeNode(Node node) {
352 //
353 // Remove all ports one-by-one. This operation will also remove the
354 // incoming links originating from the neighbors.
355 //
356 for (Integer portId : node.ports().keySet())
357 node.removePort(portId);
358
359 nodesMap.remove(node.nodeId);
360 }
361
362 /**
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700363 * Read topology state from the database.
364 *
365 * @param dbHandler the Graph Database handler to use.
366 */
367 public void readFromDatabase(GraphDBOperation dbHandler) {
368 //
369 // Fetch the relevant info from the Switch and Port vertices
370 // from the Titan Graph.
371 //
372 Iterable<ISwitchObject> activeSwitches = dbHandler.getActiveSwitches();
373 for (ISwitchObject switchObj : activeSwitches) {
374 Vertex nodeVertex = switchObj.asVertex();
375 //
376 // The Switch info
377 //
378 String nodeDpid = nodeVertex.getProperty("dpid").toString();
379 long nodeId = HexString.toLong(nodeDpid);
380 Node me = nodesMap.get(nodeId);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700381 if (me == null)
382 me = addNode(nodeId);
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700383
384 //
385 // The local Port info
386 //
387 for (Vertex myPortVertex : nodeVertex.getVertices(Direction.OUT, "on")) {
388 // Ignore inactive ports
389 if (! myPortVertex.getProperty("state").toString().equals("ACTIVE"))
390 continue;
391
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700392 int myPort = 0;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700393 Object obj = myPortVertex.getProperty("number");
394 if (obj instanceof Short) {
395 myPort = (Short)obj;
396 } else if (obj instanceof Integer) {
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700397 myPort = (Integer)obj;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700398 }
399
400 //
401 // The neighbor Port info
402 //
403 for (Vertex neighborPortVertex : myPortVertex.getVertices(Direction.OUT, "link")) {
404 // Ignore inactive ports
405 if (! neighborPortVertex.getProperty("state").toString().equals("ACTIVE"))
406 continue;
407
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700408 int neighborPort = 0;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700409 obj = neighborPortVertex.getProperty("number");
410 if (obj instanceof Short) {
411 neighborPort = (Short)obj;
412 } else if (obj instanceof Integer) {
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700413 neighborPort = (Integer)obj;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700414 }
415 //
416 // The neighbor Switch info
417 //
418 for (Vertex neighborVertex : neighborPortVertex.getVertices(Direction.IN, "on")) {
419 // Ignore inactive switches
420 String state = neighborVertex.getProperty("state").toString();
421 if (! state.equals(SwitchState.ACTIVE.toString()))
422 continue;
423
424 String neighborDpid = neighborVertex.getProperty("dpid").toString();
425 long neighborId = HexString.toLong(neighborDpid);
426 Node neighbor = nodesMap.get(neighborId);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700427 if (neighbor == null)
428 neighbor = addNode(neighborId);
429 me.addLink(myPort, neighbor, neighborPort);
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700430 }
431 }
432 }
433 }
434 dbHandler.commit();
435 }
436}