blob: 14dfd6499c8f1dab024f9042432eb73ba2726c45 [file] [log] [blame]
Jonathan Hart062a2e82014-02-03 09:41:57 -08001package net.onrc.onos.ofcontroller.networkgraph;
2
Yuta HIGUCHIcb951982014-02-11 13:31:44 -08003import java.net.InetAddress;
4import java.util.Set;
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -08005
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -08006import net.onrc.onos.datastore.topology.RCLink;
Jonathan Hart062a2e82014-02-03 09:41:57 -08007import net.onrc.onos.datastore.topology.RCPort;
8import net.onrc.onos.datastore.topology.RCSwitch;
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -08009import net.onrc.onos.ofcontroller.util.Dpid;
Jonathan Hart062a2e82014-02-03 09:41:57 -080010
11import org.slf4j.Logger;
12import org.slf4j.LoggerFactory;
13
14import edu.stanford.ramcloud.JRamCloud.ObjectDoesntExistException;
15
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080016/**
17 * The "NB" read-only Network Map.
18 *
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080019 * - Maintain Invariant/Relationships between Topology Objects.
20 *
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080021 * TODO To be synchronized based on TopologyEvent Notification.
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080022 *
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080023 * TODO TBD: Caller is expected to maintain parent/child calling order. Parent
24 * Object must exist before adding sub component(Add Switch -> Port). Child
25 * Object need to be removed before removing parent (Delete Port->Switch)
26 *
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080027 * TODO TBD: This class may delay the requested change to handle event
28 * re-ordering. e.g.) Link Add came in, but Switch was not there.
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080029 *
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080030 */
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080031public class NetworkGraphImpl extends AbstractNetworkGraph {
Jonathan Hart062a2e82014-02-03 09:41:57 -080032
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080033 private static final Logger log = LoggerFactory
34 .getLogger(NetworkGraphImpl.class);
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080035
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080036 public NetworkGraphImpl() {
37 super();
38 }
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080039
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080040 /**
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080041 * put Switch
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080042 *
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080043 * XXX Internal Invariant-maintenance method. Will not write to DB. Will not
44 * fire Notification.
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080045 *
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080046 * @param swEvt
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080047 */
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080048 void putSwitch(SwitchEvent swEvt) {
49 if (swEvt == null) {
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080050 throw new IllegalArgumentException("Switch cannot be null");
51 }
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080052 Switch sw = switches.get(swEvt.getDpid());
53
54 if (sw == null) {
55 sw = new SwitchImpl(this, swEvt.getDpid());
56 Switch existing = switches.putIfAbsent(swEvt.getDpid(), sw);
57 if (existing != null) {
58 log.warn(
59 "Concurrent putSwitch not expected. Continuing updating {}",
60 existing);
61 sw = existing;
62 }
63 }
64
65 // Add upate when more attributes are added to Event object
66 // no attribute to update for now
67 }
68
69 /**
70 * remove Switch.
71 *
72 * XXX Internal Invariant-maintenance method. Will not write to DB. Will not
73 * fire Notification.
74 *
75 * @param swEvt
76 */
77 void removeSwitch(SwitchEvent swEvt) {
78 if (swEvt == null) {
79 throw new IllegalArgumentException("Switch cannot be null");
80 }
81
82 Switch sw = switches.get(swEvt.getDpid());
83
84 if (sw == null) {
85 log.warn("Switch {} already removed, ignoreing", swEvt);
86 return;
87 }
88
89 // Sanity check
90 if (!sw.getPorts().isEmpty()) {
91 log.warn(
92 "Ports on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
93 swEvt);
94 // XXX Should we remove Port?
95 }
96 if (!sw.getDevices().isEmpty()) {
97 log.warn(
98 "Devices on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
99 swEvt);
100 // XXX Should we remove Device to Switch relation?
101 }
102 if (!sw.getIncomingLinks().iterator().hasNext()) {
103 log.warn(
104 "IncomingLinks on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
105 swEvt);
106 // XXX Should we remove Link?
107 }
108 if (!sw.getOutgoingLinks().iterator().hasNext()) {
109 log.warn(
110 "OutgoingLinks on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
111 swEvt);
112 // XXX Should we remove Link?
113 }
114
115 boolean removed = switches.remove(swEvt.getDpid(), sw);
116 if (removed) {
117 log.warn(
118 "Switch instance was replaced concurrently while removing {}. Something is not right.",
119 sw);
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800120 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800121 }
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -0800122
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800123 /**
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800124 * put Port
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800125 *
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800126 * XXX Internal Invariant-maintenance method. Will not write to DB. Will not
127 * fire Notification.
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -0800128 *
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800129 * @param portEvt
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800130 */
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800131 void putPort(PortEvent portEvt) {
132 if (portEvt == null) {
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800133 throw new IllegalArgumentException("Port cannot be null");
134 }
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800135 Switch sw = switches.get(portEvt.getDpid());
136 if (sw == null) {
137 throw new BrokenInvariantException(String.format(
138 "Switch with dpid %s did not exist.",
139 new Dpid(portEvt.getDpid())));
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800140 }
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800141 Port p = sw.getPort(portEvt.getNumber());
142 PortImpl port = null;
143 if (p != null) {
144 port = getPortImpl(p);
145 }
146
147 if (port == null) {
148 port = new PortImpl(this, sw, portEvt.getNumber());
149 }
150
151 // TODO update attributes
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800152
153 SwitchImpl s = getSwitchImpl(sw);
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800154 s.addPort(port);
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800155 }
156
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800157 /**
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800158 * remove Port
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800159 *
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800160 * XXX Internal Invariant-maintenance method. Will not write to DB. Will not
161 * fire Notification.
162 *
163 * @param portEvt
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800164 */
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800165 void removePort(PortEvent portEvt) {
166 if (portEvt == null) {
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800167 throw new IllegalArgumentException("Port cannot be null");
168 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800169
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800170 Switch sw = switches.get(portEvt.getDpid());
171 if (sw == null) {
172 log.warn("Parent Switch for Port {} already removed, ignoreing", portEvt);
173 return;
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800174 }
175
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800176 Port p = sw.getPort(portEvt.getNumber());
177 if (p == null) {
178 log.warn("Port {} already removed, ignoreing", portEvt);
179 return;
180 }
181 // null check
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800182
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800183 if (!p.getDevices().iterator().hasNext()) {
184 log.warn(
185 "Devices on Port {} should be removed prior to removing Port. Removing Port anyways",
186 portEvt);
187 // XXX Should we remove Device to Port relation?
188 }
189 if (p.getIncomingLink() != null) {
190 log.warn(
191 "IncomingLinks on Port {} should be removed prior to removing Port. Removing Port anyways",
192 portEvt);
193 // XXX Should we remove Link?
194 }
195 if (p.getOutgoingLink() != null) {
196 log.warn(
197 "OutgoingLinks on Port {} should be removed prior to removing Port. Removing Port anyways",
198 portEvt);
199 // XXX Should we remove Link?
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800200 }
201
202 // remove Port from Switch
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800203 SwitchImpl s = getSwitchImpl(sw);
204 s.removePort(p);
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800205 }
206
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800207 /**
208 * put Link
209 *
210 * XXX Internal Invariant-maintenance method. Will not write to DB. Will not
211 * fire Notification.
212 *
213 * @param linkEvt
214 */
215 void putLink(LinkEvent linkEvt) {
216 if (linkEvt == null) {
217 throw new IllegalArgumentException("Link cannot be null");
218 }
219 // TODO Auto-generated method stub
220
221 Switch srcSw = switches.get(linkEvt.getSrc().dpid);
222 if (srcSw == null) {
223 throw new BrokenInvariantException(
224 String.format(
225 "Switch with dpid %s did not exist.",
226 new Dpid(linkEvt.getSrc().dpid)));
227 }
228
229 Switch dstSw = switches.get(linkEvt.getDst().dpid);
230 if (dstSw == null) {
231 throw new BrokenInvariantException(
232 String.format(
233 "Switch with dpid %s did not exist.",
234 new Dpid(linkEvt.getDst().dpid)));
235 }
236
237 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
238 if (srcPort == null) {
239 throw new BrokenInvariantException(
240 String.format(
241 "Src Port %s of a Link did not exist.",
242 linkEvt.getSrc() ));
243 }
244 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
245 if (dstPort == null) {
246 throw new BrokenInvariantException(
247 String.format(
248 "Dst Port %s of a Link did not exist.",
249 linkEvt.getDst() ));
250 }
251
252 Link l = dstPort.getIncomingLink();
253 LinkImpl link = null;
254 assert( l == srcPort.getOutgoingLink() );
255 if (l != null) {
256// link = getLink
257 }
258
259 // TODO update Switch
260 // TODO update Link
261
262
263 // XXX check Existing Link first?
264// srcPort.setOutgoingLink(link);
265// dstPort.setIncomingLink(link);
266 }
267
268 /**
269 * removeLink
270 *
271 * XXX Internal Invariant-maintenance method. Will not write to DB. Will not
272 * fire Notification.
273 *
274 * @param link
275 */
276 void removeLink(LinkEvent link) {
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -0800277 if (link == null) {
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800278 throw new IllegalArgumentException("Link cannot be null");
279 }
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800280 // TODO Auto-generated method stub
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800281
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800282 // Switch srcSw = link.getSourceSwitch();
283 // if (!isSwitchInstanceInTopology(srcSw)) {
284 // // XXX Define or choose more appropriate Exception.
285 // throw new RuntimeException(
286 // String.format(
287 // "Switch with dpid %s did not exist or different instance registered.",
288 // new Dpid(srcSw.getDpid())));
289 // }
290 //
291 // Switch dstSw = link.getDestinationSwitch();
292 // if (!isSwitchInstanceInTopology(dstSw)) {
293 // // XXX Define or choose more appropriate Exception.
294 // throw new RuntimeException(
295 // String.format(
296 // "Switch with dpid %s did not exist or different instance registered.",
297 // new Dpid(dstSw.getDpid())));
298 // }
299 //
300 // PortImpl srcPort = getPortImpl(link.getSourcePort());
301 // PortImpl dstPort = getPortImpl(link.getDestinationPort());
302 //
303 // // XXX check Existing Link first?
304 // if (srcPort.getOutgoingLink() != link
305 // || dstPort.getIncomingLink() != link) {
306 // // XXX Define or choose more appropriate Exception.
307 // throw new RuntimeException(String.format(
308 // "Link %s did not belong to Topology", link.toString()));
309 // }
310 // // remove Link
311 // srcPort.setOutgoingLink(null);
312 // dstPort.setIncomingLink(null);
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800313 }
314
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800315 // XXX Need to rework Device related
316 /**
317 * Add new device to DB
318 *
319 * @param device
320 */
321 void updateDevice(DeviceEvent deviceToUpdate,
322 Set<InetAddress> updatedIpAddrs, Set<Port> updatedAttachmentPoints) {
323 if (deviceToUpdate == null) {
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800324 throw new IllegalArgumentException("Device cannot be null");
325 }
326 // TODO Auto-generated method stub
327
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800328 // Device existingDevice =
329 // getDeviceByMac(deviceToUpdate.getMacAddress());
330 // if (existingDevice != deviceToUpdate) {
331 // throw new IllegalArgumentException(
332 // "Must supply Device Object in this NetworkGraph");
333 // }
334 //
335 // DeviceImpl device = getDeviceImpl(deviceToUpdate);
336 //
337 // // Update IP Addr
338 // // uniq
339 // Set<InetAddress> prevAddrs = new HashSet<>(
340 // deviceToUpdate.getIpAddress());
341 // Set<InetAddress> newAddrs = updatedIpAddrs;
342 //
343 // // delta
344 // @SuppressWarnings("unchecked")
345 // Collection<InetAddress> delAddr = CollectionUtils.subtract(newAddrs,
346 // prevAddrs);
347 // @SuppressWarnings("unchecked")
348 // Collection<InetAddress> addAddr = CollectionUtils.subtract(prevAddrs,
349 // newAddrs);
350 //
351 // for (InetAddress addr : delAddr) {
352 // Set<Device> devices = addr2Device.get(addr);
353 // if (devices == null) {
354 // continue;
355 // }
356 // devices.remove(device);
357 // device.removeIpAddress(addr);
358 // }
359 // for (InetAddress addr : addAddr) {
360 // Set<Device> devices = addr2Device.get(addr);
361 // if (devices == null) {
362 // devices = new HashSet<>();
363 // addr2Device.put(addr, devices);
364 // }
365 // devices.add(device);
366 // device.addIpAddress(addr);
367 // }
368 //
369 // // Update Attachment Point
370 // // uniq
371 // Set<Port> prevPorts = new HashSet<>();
372 // CollectionUtils.addAll(prevAddrs,
373 // deviceToUpdate.getAttachmentPoints()
374 // .iterator());
375 // Set<Port> newPorts = updatedAttachmentPoints;
376 // // delta
377 // @SuppressWarnings("unchecked")
378 // Collection<Port> delPorts = CollectionUtils.subtract(newPorts,
379 // prevPorts);
380 // @SuppressWarnings("unchecked")
381 // Collection<Port> addPorts = CollectionUtils.subtract(prevPorts,
382 // newPorts);
383 //
384 // for (Port p : delPorts) {
385 // device.removeAttachmentPoint(p);
386 // getPortImpl(p).removeDevice(device);
387 // }
388 //
389 // for (Port p : addPorts) {
390 // device.addAttachmentPoint(p);
391 // getPortImpl(p).addDevice(device);
392 // }
393
394 // TODO Auto-generated method stub
395
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800396 }
397
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800398 void removeDevice(DeviceEvent device) {
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -0800399 if (device == null) {
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800400 throw new IllegalArgumentException("Device cannot be null");
401 }
402 // TODO Auto-generated method stub
403
404 }
405
406 private SwitchImpl getSwitchImpl(Switch sw) {
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -0800407 if (sw instanceof SwitchImpl) {
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800408 return (SwitchImpl) sw;
409 }
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800410 throw new ClassCastException("SwitchImpl expected, but found: " + sw);
411 }
412
413 private PortImpl getPortImpl(Port p) {
414 if (p instanceof PortImpl) {
415 return (PortImpl) p;
416 }
417 throw new ClassCastException("PortImpl expected, but found: " + p);
418 }
419
Yuta HIGUCHIc0366272014-02-10 21:04:57 -0800420 private DeviceImpl getDeviceImpl(Device d) {
421 if (d instanceof DeviceImpl) {
422 return (DeviceImpl) d;
423 }
424 throw new ClassCastException("DeviceImpl expected, but found: " + d);
425 }
426
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800427 public boolean isSwitchInstanceInTopology(Switch sw) {
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800428 // check if the sw instance is valid in Topology
429 if (sw != switches.get(sw.getDpid())) {
430 return false;
431 }
432 return true;
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -0800433 }
434
435 public void loadWholeTopologyFromDB() {
436 // XXX clear everything first?
437
438 for (RCSwitch sw : RCSwitch.getAllSwitches()) {
439 try {
440 sw.read();
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800441 // TODO if there is going to be inactive Switch in DB, skip
442 // TODO update other attributes if there exist any
443 putSwitch(new SwitchEvent(sw.getDpid()));
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -0800444 } catch (ObjectDoesntExistException e) {
445 log.error("Read Switch Failed, skipping", e);
446 }
447 }
448
449 for (RCPort p : RCPort.getAllPorts()) {
450 try {
451 p.read();
452
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -0800453 Switch sw = this.getSwitch(p.getDpid());
454 if (sw == null) {
455 log.error("Switch {} missing when adding Port {}",
456 new Dpid(p.getDpid()), p);
457 continue;
458 }
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800459 PortEvent portEvent = new PortEvent(p.getDpid(), p.getNumber());
460 // TODO update other attributes if there exist any
461 putPort(portEvent);
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -0800462 } catch (ObjectDoesntExistException e) {
463 log.error("Read Port Failed, skipping", e);
464 }
465 }
466
467 // TODO Is Device going to be in DB? If so, read from DB.
468 // for (RCDevice d : RCDevice.getAllDevices()) {
469 // try {
470 // d.read();
471 //
472 // } catch (ObjectDoesntExistException e) {
473 // log.debug("Read Device Failed, skipping", e);
474 // }
475 // }
476
477 for (RCLink l : RCLink.getAllLinks()) {
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800478 try {
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800479 l.read();
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800480
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800481 Switch srcSw = this.getSwitch(l.getSrc().dpid);
482 if (srcSw == null) {
483 log.error("Switch {} missing when adding Link {}",
484 new Dpid(l.getSrc().dpid), l);
485 continue;
486 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800487
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800488 Switch dstSw = this.getSwitch(l.getDst().dpid);
489 if (dstSw == null) {
490 log.error("Switch {} missing when adding Link {}",
491 new Dpid(l.getDst().dpid), l);
492 continue;
493 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800494
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800495 LinkEvent linkEvent = new LinkEvent(l.getSrc().dpid,
496 l.getSrc().number, l.getDst().dpid, l.getDst().number);
497 // TODO update other attributes if there exist any
498 putLink(linkEvent);
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800499 } catch (ObjectDoesntExistException e) {
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800500 log.debug("Delete Link Failed", e);
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800501 }
Jonathan Hart062a2e82014-02-03 09:41:57 -0800502 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800503 }
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800504
505 /**
506 * Exception to be thrown when Modification to the Network Graph cannot be continued due to broken invariant.
507 *
508 * XXX Should this be checked exception or RuntimeException
509 */
510 public static class BrokenInvariantException extends RuntimeException {
511 private static final long serialVersionUID = 1L;
512
513 public BrokenInvariantException() {
514 super();
515 }
516
517 public BrokenInvariantException(String message) {
518 super(message);
519 }
520 }
Jonathan Hart062a2e82014-02-03 09:41:57 -0800521}