blob: b7a812c5ecb3cc50287606f9389930b42305deb6 [file] [log] [blame]
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001package net.onrc.onos.ofcontroller.topology;
2
3import java.util.HashMap;
Pavlin Radoslavovcfe7b402013-10-30 19:44:22 -07004import java.util.List;
5import java.util.LinkedList;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07006import java.util.Map;
7
8import net.onrc.onos.graph.GraphDBOperation;
9import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
10import net.onrc.onos.ofcontroller.core.ISwitchStorage.SwitchState;
11
12import org.openflow.util.HexString;
13
14import com.tinkerpop.blueprints.Direction;
15import com.tinkerpop.blueprints.Vertex;
16
17/**
18 * A class for storing Node and Link information for fast computation
19 * of shortest paths.
20 */
21class Node {
22 /**
23 * A class for storing Link information for fast computation of shortest
24 * paths.
25 */
26 class Link {
27 public Node me; // The node this link originates from
28 public Node neighbor; // The neighbor node on the other side
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070029 public int myPort; // Local port ID for the link
30 public int neighborPort; // Neighbor port ID for the link
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070031
32 /**
33 * Link constructor.
34 *
35 * @param me the node this link originates from.
36 * @param the neighbor node on the other side of the link.
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070037 * @param myPort local port ID for the link.
38 * @param neighborPort neighbor port ID for the link.
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070039 */
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070040 public Link(Node me, Node neighbor, int myPort, int neighborPort) {
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070041 this.me = me;
42 this.neighbor = neighbor;
43 this.myPort = myPort;
44 this.neighborPort = neighborPort;
45 }
46 };
47
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070048 public long nodeId; // The node ID
Yuta HIGUCHI63ee5a82013-10-31 10:16:15 -070049 public HashMap<Integer, Link> links; // The links from this node (src Port ID -> Link)
50 private HashMap<Integer, Link> reverseLinksMap; // The links to this node (dst Port ID -> Link)
51 private HashMap<Integer, Integer> portsMap; // The ports on this node (Port ID -> )
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070052
53 /**
54 * Node constructor.
55 *
56 * @param nodeId the node ID.
57 */
58 public Node(long nodeId) {
59 this.nodeId = nodeId;
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070060 links = new HashMap<Integer, Link>();
61 reverseLinksMap = new HashMap<Integer, Link>();
62 portsMap = new HashMap<Integer, Integer>();
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070063 }
64
65 /**
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070066 * Get all ports.
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070067 *
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070068 * @return all ports.
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070069 */
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070070 public Map<Integer, Integer> ports() {
71 return portsMap;
72 }
73
74 /**
75 * Get the port for a given Port ID.
76 *
77 * Note: For now the port itself is just the Port ID. In the future
78 * it might contain more information.
79 *
80 * @return the port if found, otherwise null.
81 */
82 public Integer getPort(int portId) {
Yuta HIGUCHIdbc8c442013-10-31 10:15:37 -070083 return portsMap.get(portId);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -070084 }
85
86 /**
87 * Add a port for a given Port ID.
88 *
89 * Note: For now the port itself is just the Port ID. In the future
90 * it might contain more information.
91 *
92 * @param portId the Port ID of the port to add.
93 * @return the added Port.
94 */
95 Integer addPort(int portId) {
96 Integer port = new Integer(portId);
97 portsMap.put(portId, port);
98 return port;
99 }
100
101 /**
102 * Remove a port for a given Port ID.
103 *
104 * NOTE: The outgoing and incoming links using this port are removed as
105 * well.
106 */
107 void removePort(int portId) {
108 // Remove the outgoing link
109 Link link = getLink(portId);
110 if (link != null) {
111 link.neighbor.removeReverseLink(link);
112 removeLink(portId);
113 }
114
115 // Remove the incoming link
116 Link reverseLink = reverseLinksMap.get(portId);
117 if (reverseLink != null) {
118 // NOTE: reverseLink.myPort is the neighbor's outgoing port
119 reverseLink.neighbor.removeLink(reverseLink.myPort);
120 removeReverseLink(reverseLink);
121 }
122
123 portsMap.remove(portId);
124 }
Yuta HIGUCHI63ee5a82013-10-31 10:16:15 -0700125
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700126 /**
127 * Get a link on a port to a neighbor.
128 *
129 * @param myPortId the local port ID for the link to the neighbor.
130 * @return the link if found, otherwise null.
131 */
132 public Link getLink(int myPortId) {
133 return links.get(myPortId);
134 }
135
136 /**
137 * Add a link to a neighbor.
138 *
139 * @param myPortId the local port ID for the link to the neighbor.
140 * @param neighbor the neighbor for the link.
141 * @param neighborPortId the neighbor port ID for the link.
142 * @return the added Link.
143 */
144 public Link addLink(int myPortId, Node neighbor, int neighborPortId) {
145 Link link = new Link(this, neighbor, myPortId, neighborPortId);
146 links.put(myPortId, link);
147 neighbor.addReverseLink(link);
148 return link;
149 }
150
151 /**
152 * Add a reverse link from a neighbor.
153 *
154 * @param link the reverse link from a neighbor to add.
155 */
156 private void addReverseLink(Link link) {
157 // NOTE: link.neghborPort is my port
158 reverseLinksMap.put(link.neighborPort, link);
159 }
160
161 /**
162 * Remove a link to a neighbor.
163 *
164 * @param myPortId the local port ID for the link to the neighbor.
165 */
166 public void removeLink(int myPortId) {
167 links.remove(myPortId);
168 }
169
170 /**
171 * Remove a reverse link from a neighbor.
172 *
173 * @param link the reverse link from a neighbor to remove.
174 */
175 private void removeReverseLink(Link link) {
176 // NOTE: link.neghborPort is my port
177 reverseLinksMap.remove(link.neighborPort);
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700178 }
179};
180
181/**
182 * A class for storing topology information.
183 */
184public class Topology {
185 private Map<Long, Node> nodesMap; // The dpid->Node mapping
186
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700187 /**
188 * Default constructor.
189 */
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700190 public Topology() {
191 nodesMap = new HashMap<Long, Node>();
192 }
193
194 /**
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700195 * Add a topology element to the topology.
196 *
197 * @param topologyElement the topology element to add.
198 * @return true if the topology was modified, otherwise false.
199 */
200 public boolean addTopologyElement(TopologyElement topologyElement) {
201 boolean isModified = false;
202
203 switch (topologyElement.getType()) {
204 case ELEMENT_SWITCH: {
205 // Add the switch
206 Node node = getNode(topologyElement.getSwitch());
207 if (node == null) {
208 node = addNode(topologyElement.getSwitch());
209 isModified = true;
210 }
211 // Add the ports for the switch
212 for (Integer portId : topologyElement.getSwitchPorts().values()) {
213 Integer port = node.getPort(portId);
214 if (port == null) {
215 node.addPort(portId);
216 isModified = true;
217 }
218 }
219 break;
220 }
221 case ELEMENT_PORT: {
222 // Add the switch
223 Node node = getNode(topologyElement.getSwitch());
224 if (node == null) {
225 node = addNode(topologyElement.getSwitch());
226 isModified = true;
227 }
228 // Add the port for the switch
229 Integer port = node.getPort(topologyElement.getSwitchPort());
230 if (port == null) {
231 node.addPort(topologyElement.getSwitchPort());
232 isModified = true;
233 }
234 break;
235 }
236 case ELEMENT_LINK: {
237 // Add the "from" switch
238 Node fromNode = getNode(topologyElement.getFromSwitch());
239 if (fromNode == null) {
240 fromNode = addNode(topologyElement.getFromSwitch());
241 isModified = true;
242 }
243 // Add the "to" switch
244 Node toNode = getNode(topologyElement.getToSwitch());
245 if (toNode == null) {
246 toNode = addNode(topologyElement.getToSwitch());
247 isModified = true;
248 }
249 // Add the "from" port
250 Integer fromPort = fromNode.getPort(topologyElement.getFromPort());
251 if (fromPort == null) {
252 fromNode.addPort(topologyElement.getFromPort());
253 isModified = true;
254 }
255 // Add the "to" port
256 Integer toPort = fromNode.getPort(topologyElement.getToPort());
257 if (toPort == null) {
258 toNode.addPort(topologyElement.getToPort());
259 isModified = true;
260 }
261 Node.Link link = fromNode.getLink(topologyElement.getFromPort());
262 if (link == null) {
263 fromNode.addLink(topologyElement.getFromPort(),
264 toNode,
265 topologyElement.getToPort());
266 isModified = true;
267 }
268
269 break;
270 }
271 }
272
273 return isModified;
274 }
275
276 /**
277 * Remove a topology element from the topology.
278 *
279 * @param topologyElement the topology element to remove.
280 * @return true if the topology was modified, otherwise false.
281 */
282 public boolean removeTopologyElement(TopologyElement topologyElement) {
283 boolean isModified = false;
284
285 switch (topologyElement.getType()) {
286 case ELEMENT_SWITCH: {
287 // Remove the switch
288 Node node = getNode(topologyElement.getSwitch());
289 if (node != null) {
290 removeNode(node);
291 isModified = true;
292 }
293 break;
294 }
295 case ELEMENT_PORT: {
296 // Find the switch
297 Node node = getNode(topologyElement.getSwitch());
298 if (node == null)
299 break;
300 // Remove the port for the switch
301 Integer port = node.getPort(topologyElement.getSwitchPort());
302 if (port != null) {
303 node.removePort(topologyElement.getSwitchPort());
304 isModified = true;
305 }
306 break;
307 }
308 case ELEMENT_LINK: {
309 // Find the "from" switch
310 Node fromNode = getNode(topologyElement.getFromSwitch());
311 if (fromNode == null)
312 break;
313 // Remove the link originating from the "from" port
314 Node.Link link = fromNode.getLink(topologyElement.getFromPort());
315 if (link != null) {
316 fromNode.removeLink(topologyElement.getFromPort());
317 isModified = true;
318 }
319 break;
320 }
321 }
322
323 return isModified;
324 }
325
326 /**
327 * Get a node for a given Node ID.
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700328 *
329 * @param nodeId the Node ID to use.
330 * @return the corresponding Node if found, otherwise null.
331 */
332 Node getNode(long nodeId) {
333 return nodesMap.get(nodeId);
334 }
335
336 /**
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700337 * Add a node for a given Node ID.
338 *
339 * @param nodeId the Node ID to use.
340 * @return the added Node.
341 */
342 Node addNode(long nodeId) {
343 Node node = new Node(nodeId);
344 nodesMap.put(nodeId, node);
345 return node;
346 }
347
348 /**
349 * Remove an existing node.
350 *
351 * @param node the Node to remove.
352 */
353 void removeNode(Node node) {
354 //
355 // Remove all ports one-by-one. This operation will also remove the
356 // incoming links originating from the neighbors.
357 //
Pavlin Radoslavovcfe7b402013-10-30 19:44:22 -0700358 // NOTE: We have to extract all Port IDs in advance, otherwise we
359 // cannot loop over the Ports collection and remove entries at the
360 // same time.
361 // TODO: If there is a large number of ports, the implementation
362 // below can be sub-optimal. It should be refactored as follows:
363 // 1. Modify removePort() to perform all the cleanup, except
364 // removing the Port entry from the portsMap
365 // 2. Call portsMap.clear() at the end of this method
366 // 3. In all other methods: if removePort() is called somewhere else,
367 // add an explicit removal of the Port entry from the portsMap.
368 //
369 List<Integer> allPortIdKeys = new LinkedList<Integer>();
370 allPortIdKeys.addAll(node.ports().keySet());
371 for (Integer portId : allPortIdKeys)
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700372 node.removePort(portId);
373
374 nodesMap.remove(node.nodeId);
375 }
376
377 /**
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700378 * Read topology state from the database.
379 *
380 * @param dbHandler the Graph Database handler to use.
381 */
382 public void readFromDatabase(GraphDBOperation dbHandler) {
383 //
384 // Fetch the relevant info from the Switch and Port vertices
385 // from the Titan Graph.
386 //
387 Iterable<ISwitchObject> activeSwitches = dbHandler.getActiveSwitches();
388 for (ISwitchObject switchObj : activeSwitches) {
389 Vertex nodeVertex = switchObj.asVertex();
390 //
391 // The Switch info
392 //
393 String nodeDpid = nodeVertex.getProperty("dpid").toString();
394 long nodeId = HexString.toLong(nodeDpid);
395 Node me = nodesMap.get(nodeId);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700396 if (me == null)
397 me = addNode(nodeId);
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700398
399 //
400 // The local Port info
401 //
402 for (Vertex myPortVertex : nodeVertex.getVertices(Direction.OUT, "on")) {
403 // Ignore inactive ports
404 if (! myPortVertex.getProperty("state").toString().equals("ACTIVE"))
405 continue;
406
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700407 int myPort = 0;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700408 Object obj = myPortVertex.getProperty("number");
409 if (obj instanceof Short) {
410 myPort = (Short)obj;
411 } else if (obj instanceof Integer) {
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700412 myPort = (Integer)obj;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700413 }
414
415 //
416 // The neighbor Port info
417 //
418 for (Vertex neighborPortVertex : myPortVertex.getVertices(Direction.OUT, "link")) {
419 // Ignore inactive ports
420 if (! neighborPortVertex.getProperty("state").toString().equals("ACTIVE"))
421 continue;
422
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700423 int neighborPort = 0;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700424 obj = neighborPortVertex.getProperty("number");
425 if (obj instanceof Short) {
426 neighborPort = (Short)obj;
427 } else if (obj instanceof Integer) {
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700428 neighborPort = (Integer)obj;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700429 }
430 //
431 // The neighbor Switch info
432 //
433 for (Vertex neighborVertex : neighborPortVertex.getVertices(Direction.IN, "on")) {
434 // Ignore inactive switches
435 String state = neighborVertex.getProperty("state").toString();
436 if (! state.equals(SwitchState.ACTIVE.toString()))
437 continue;
438
439 String neighborDpid = neighborVertex.getProperty("dpid").toString();
440 long neighborId = HexString.toLong(neighborDpid);
441 Node neighbor = nodesMap.get(neighborId);
Pavlin Radoslavova23e5412013-10-27 19:56:40 -0700442 if (neighbor == null)
443 neighbor = addNode(neighborId);
444 me.addLink(myPort, neighbor, neighborPort);
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700445 }
446 }
447 }
448 }
449 dbHandler.commit();
450 }
451}