blob: 2355b0367fdaf970fa1d155c47eea33949b332d4 [file] [log] [blame]
Jonathan Hart062a2e82014-02-03 09:41:57 -08001package net.onrc.onos.ofcontroller.networkgraph;
2
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -08003import java.util.ArrayList;
4import java.util.HashSet;
5import java.util.List;
6import java.util.Set;
7
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -08008import net.onrc.onos.datastore.topology.RCLink;
Jonathan Hart062a2e82014-02-03 09:41:57 -08009import net.onrc.onos.datastore.topology.RCPort;
10import net.onrc.onos.datastore.topology.RCSwitch;
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080011import net.onrc.onos.ofcontroller.networkgraph.PortEvent.SwitchPort;
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080012import net.onrc.onos.ofcontroller.util.Dpid;
Jonathan Hart062a2e82014-02-03 09:41:57 -080013
14import org.slf4j.Logger;
15import org.slf4j.LoggerFactory;
16
17import edu.stanford.ramcloud.JRamCloud.ObjectDoesntExistException;
18
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080019/**
20 * The "NB" read-only Network Map.
21 *
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080022 * - Maintain Invariant/Relationships between Topology Objects.
23 *
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -080024 * TODO To be synchronized based on TopologyEvent Notification.
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080025 *
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080026 * TODO TBD: Caller is expected to maintain parent/child calling order. Parent
27 * Object must exist before adding sub component(Add Switch -> Port). Child
28 * Object need to be removed before removing parent (Delete Port->Switch)
29 *
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080030 * TODO TBD: This class may delay the requested change to handle event
31 * re-ordering. e.g.) Link Add came in, but Switch was not there.
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080032 *
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080033 */
Yuta HIGUCHI928fa682014-02-11 19:07:57 -080034public class NetworkGraphImpl extends AbstractNetworkGraph implements
35 NetworkGraphDiscoveryInterface, NetworkGraphReplicationInterface {
Jonathan Hart062a2e82014-02-03 09:41:57 -080036
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080037 private static final Logger log = LoggerFactory
38 .getLogger(NetworkGraphImpl.class);
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -080039
Jonathan Hart22eb9882014-02-11 15:52:59 -080040 private final NetworkGraphDatastore datastore;
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080041
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080042 public NetworkGraphImpl() {
43 super();
Jonathan Hart22eb9882014-02-11 15:52:59 -080044 datastore = new NetworkGraphDatastore(this);
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080045 }
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -080046
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080047 /**
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080048 * put Switch
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080049 *
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080050 * XXX Internal In-memory object mutation method. Will not write to DB.
51 * Will not fire Notification.
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080052 *
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080053 * @param swEvt
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -080054 */
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080055 void putSwitch(SwitchEvent swEvt) {
56 if (swEvt == null) {
Yuta HIGUCHI80829d12014-02-05 20:16:56 -080057 throw new IllegalArgumentException("Switch cannot be null");
58 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -080059
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080060 Switch sw = switches.get(swEvt.getDpid());
61
62 if (sw == null) {
63 sw = new SwitchImpl(this, swEvt.getDpid());
64 Switch existing = switches.putIfAbsent(swEvt.getDpid(), sw);
65 if (existing != null) {
66 log.warn(
67 "Concurrent putSwitch not expected. Continuing updating {}",
68 existing);
69 sw = existing;
70 }
71 }
72
Yuta HIGUCHId02e9282014-02-12 09:24:41 -080073 // Update when more attributes are added to Event object
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080074 // no attribute to update for now
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -080075
76 // TODO handle child Port event properly for performance
77 for (PortEvent portEvt : swEvt.getPorts() ) {
78 putPort(portEvt);
79 }
80
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080081 }
82
83 /**
84 * remove Switch.
85 *
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -080086 * XXX Internal In-memory object mutation method. Will not write to DB.
87 * Will not fire Notification.
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080088 *
89 * @param swEvt
90 */
91 void removeSwitch(SwitchEvent swEvt) {
92 if (swEvt == null) {
93 throw new IllegalArgumentException("Switch cannot be null");
94 }
95
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -080096 // TODO handle child Port event properly for performance
97 for (PortEvent portEvt : swEvt.getPorts() ) {
98 removePort(portEvt);
99 }
100
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800101 Switch sw = switches.get(swEvt.getDpid());
102
103 if (sw == null) {
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800104 log.warn("Switch {} already removed, ignoring", swEvt);
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800105 return;
106 }
107
108 // Sanity check
109 if (!sw.getPorts().isEmpty()) {
110 log.warn(
111 "Ports on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
112 swEvt);
113 // XXX Should we remove Port?
114 }
115 if (!sw.getDevices().isEmpty()) {
116 log.warn(
117 "Devices on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
118 swEvt);
119 // XXX Should we remove Device to Switch relation?
120 }
121 if (!sw.getIncomingLinks().iterator().hasNext()) {
122 log.warn(
123 "IncomingLinks on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
124 swEvt);
125 // XXX Should we remove Link?
126 }
127 if (!sw.getOutgoingLinks().iterator().hasNext()) {
128 log.warn(
129 "OutgoingLinks on Switch {} should be removed prior to removing Switch. Removing Switch anyways",
130 swEvt);
131 // XXX Should we remove Link?
132 }
133
134 boolean removed = switches.remove(swEvt.getDpid(), sw);
135 if (removed) {
136 log.warn(
137 "Switch instance was replaced concurrently while removing {}. Something is not right.",
138 sw);
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800139 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800140 }
Yuta HIGUCHI181d34d2014-02-05 15:05:46 -0800141
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800142 /**
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800143 * put Port
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800144 *
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800145 * XXX Internal In-memory object mutation method. Will not write to DB.
146 * Will not fire Notification.
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -0800147 *
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800148 * @param portEvt
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800149 */
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800150 void putPort(PortEvent portEvt) {
151 if (portEvt == null) {
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800152 throw new IllegalArgumentException("Port cannot be null");
153 }
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800154 Switch sw = switches.get(portEvt.getDpid());
155 if (sw == null) {
156 throw new BrokenInvariantException(String.format(
157 "Switch with dpid %s did not exist.",
158 new Dpid(portEvt.getDpid())));
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800159 }
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800160 Port p = sw.getPort(portEvt.getNumber());
161 PortImpl port = null;
162 if (p != null) {
163 port = getPortImpl(p);
164 }
165
166 if (port == null) {
167 port = new PortImpl(this, sw, portEvt.getNumber());
168 }
169
170 // TODO update attributes
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800171
172 SwitchImpl s = getSwitchImpl(sw);
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800173 s.addPort(port);
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800174 }
175
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800176 /**
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800177 * remove Port
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800178 *
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800179 * XXX Internal In-memory object mutation method. Will not write to DB.
180 * Will not fire Notification.
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800181 *
182 * @param portEvt
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800183 */
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800184 void removePort(PortEvent portEvt) {
185 if (portEvt == null) {
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800186 throw new IllegalArgumentException("Port cannot be null");
187 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800188
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800189 Switch sw = switches.get(portEvt.getDpid());
190 if (sw == null) {
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800191 log.warn("Parent Switch for Port {} already removed, ignoring", portEvt);
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800192 return;
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800193 }
194
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800195 Port p = sw.getPort(portEvt.getNumber());
196 if (p == null) {
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800197 log.warn("Port {} already removed, ignoring", portEvt);
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800198 return;
199 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800200
201 // check if there is something referring to this Port
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800202
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800203 if (!p.getDevices().iterator().hasNext()) {
204 log.warn(
205 "Devices on Port {} should be removed prior to removing Port. Removing Port anyways",
206 portEvt);
207 // XXX Should we remove Device to Port relation?
208 }
209 if (p.getIncomingLink() != null) {
210 log.warn(
211 "IncomingLinks on Port {} should be removed prior to removing Port. Removing Port anyways",
212 portEvt);
213 // XXX Should we remove Link?
214 }
215 if (p.getOutgoingLink() != null) {
216 log.warn(
217 "OutgoingLinks on Port {} should be removed prior to removing Port. Removing Port anyways",
218 portEvt);
219 // XXX Should we remove Link?
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800220 }
221
222 // remove Port from Switch
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800223 SwitchImpl s = getSwitchImpl(sw);
224 s.removePort(p);
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800225 }
226
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800227 /**
228 * put Link
229 *
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800230 * XXX Internal In-memory object mutation method. Will not write to DB.
231 * Will not fire Notification.
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800232 *
233 * @param linkEvt
234 */
235 void putLink(LinkEvent linkEvt) {
236 if (linkEvt == null) {
237 throw new IllegalArgumentException("Link cannot be null");
238 }
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800239
240 Switch srcSw = switches.get(linkEvt.getSrc().dpid);
241 if (srcSw == null) {
242 throw new BrokenInvariantException(
243 String.format(
244 "Switch with dpid %s did not exist.",
245 new Dpid(linkEvt.getSrc().dpid)));
246 }
247
248 Switch dstSw = switches.get(linkEvt.getDst().dpid);
249 if (dstSw == null) {
250 throw new BrokenInvariantException(
251 String.format(
252 "Switch with dpid %s did not exist.",
253 new Dpid(linkEvt.getDst().dpid)));
254 }
255
256 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
257 if (srcPort == null) {
258 throw new BrokenInvariantException(
259 String.format(
260 "Src Port %s of a Link did not exist.",
261 linkEvt.getSrc() ));
262 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800263
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800264 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
265 if (dstPort == null) {
266 throw new BrokenInvariantException(
267 String.format(
268 "Dst Port %s of a Link did not exist.",
269 linkEvt.getDst() ));
270 }
271
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800272 // getting Link instance from destination port incoming Link
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800273 Link l = dstPort.getIncomingLink();
274 LinkImpl link = null;
275 assert( l == srcPort.getOutgoingLink() );
276 if (l != null) {
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800277 link = getLinkImpl(l);
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800278 }
279
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800280 if (link == null) {
281 link = new LinkImpl(this, srcPort, dstPort);
282 }
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800283
284
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800285 PortImpl dstPortMem = getPortImpl(dstPort);
286 PortImpl srcPortMem = getPortImpl(srcPort);
287
288 // Add Link first to avoid further Device addition
289
290 // add Link to Port
291 dstPortMem.setIncomingLink(link);
292 srcPortMem.setOutgoingLink(link);
293
294 // remove Device Pointing to Port if any
295 for(Device d : dstPortMem.getDevices() ) {
296 log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, dstPort, linkEvt);
297 DeviceImpl dev = getDeviceImpl(d);
298 dev.removeAttachmentPoint(dstPort);
299 // XXX This implies that change is made to Device Object,
300 // which need to be written to DB, how should that be done?
301 // should we write here or ignore and leave DB in inconsistent state?
302 }
303 dstPortMem.removeAllDevice();
304 for(Device d : srcPortMem.getDevices() ) {
305 log.error("Device {} on Port {} should have been removed prior to adding Link {}", d, srcPort, linkEvt);
306 DeviceImpl dev = getDeviceImpl(d);
307 dev.removeAttachmentPoint(srcPort);
308 // XXX This implies that change is made to Device Object,
309 // which need to be written to DB, how should that be done?
310 // should we write here or ignore and leave DB in inconsistent state?
311 }
312 srcPortMem.removeAllDevice();
313
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800314 }
315
316 /**
317 * removeLink
318 *
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800319 * XXX Internal In-memory object mutation method. Will not write to DB.
320 * Will not fire Notification.
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800321 *
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800322 * @param linkEvt
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800323 */
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800324 void removeLink(LinkEvent linkEvt) {
325 if (linkEvt == null) {
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800326 throw new IllegalArgumentException("Link cannot be null");
327 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800328
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800329 Switch srcSw = switches.get(linkEvt.getSrc().dpid);
330 if (srcSw == null) {
331 log.warn("Src Switch for Link {} already removed, ignoring", linkEvt);
332 return;
333 }
334
335 Switch dstSw = switches.get(linkEvt.getDst().dpid);
336 if (dstSw == null) {
337 log.warn("Dst Switch for Link {} already removed, ignoring", linkEvt);
338 return;
339 }
340
341 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
342 if (srcPort == null) {
343 log.warn("Src Port for Link {} already removed, ignoring", linkEvt);
344 return;
345 }
346
347 Port dstPort = dstSw.getPort(linkEvt.getDst().number);
348 if (dstPort == null) {
349 log.warn("Dst Port for Link {} already removed, ignoring", linkEvt);
350 return;
351 }
352
353 Link l = dstPort.getIncomingLink();
354 if ( l == null ) {
355 log.warn("Link {} already removed on destination Port", linkEvt);
356 }
357 l = srcPort.getOutgoingLink();
358 if ( l == null ) {
359 log.warn("Link {} already removed on src Port", linkEvt);
360 }
361
362 getPortImpl(dstPort).setIncomingLink(null);
363 getPortImpl(srcPort).setOutgoingLink(null);
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800364 }
365
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800366 // XXX Need to rework Device related
367 /**
368 * Add new device to DB
369 *
370 * @param device
371 */
Yuta HIGUCHI0be4a662014-02-11 18:01:28 -0800372 void putDevice(DeviceEvent deviceEvt) {
373 if (deviceEvt == null) {
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800374 throw new IllegalArgumentException("Device cannot be null");
375 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800376
377 // for each attachment point
378 /// TODO check if Link exist on that Port
379
380
381
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800382 // TODO Auto-generated method stub
383
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800384 // Device existingDevice =
385 // getDeviceByMac(deviceToUpdate.getMacAddress());
386 // if (existingDevice != deviceToUpdate) {
387 // throw new IllegalArgumentException(
388 // "Must supply Device Object in this NetworkGraph");
389 // }
390 //
391 // DeviceImpl device = getDeviceImpl(deviceToUpdate);
392 //
393 // // Update IP Addr
394 // // uniq
395 // Set<InetAddress> prevAddrs = new HashSet<>(
396 // deviceToUpdate.getIpAddress());
397 // Set<InetAddress> newAddrs = updatedIpAddrs;
398 //
399 // // delta
400 // @SuppressWarnings("unchecked")
401 // Collection<InetAddress> delAddr = CollectionUtils.subtract(newAddrs,
402 // prevAddrs);
403 // @SuppressWarnings("unchecked")
404 // Collection<InetAddress> addAddr = CollectionUtils.subtract(prevAddrs,
405 // newAddrs);
406 //
407 // for (InetAddress addr : delAddr) {
408 // Set<Device> devices = addr2Device.get(addr);
409 // if (devices == null) {
410 // continue;
411 // }
412 // devices.remove(device);
413 // device.removeIpAddress(addr);
414 // }
415 // for (InetAddress addr : addAddr) {
416 // Set<Device> devices = addr2Device.get(addr);
417 // if (devices == null) {
418 // devices = new HashSet<>();
419 // addr2Device.put(addr, devices);
420 // }
421 // devices.add(device);
422 // device.addIpAddress(addr);
423 // }
424 //
425 // // Update Attachment Point
426 // // uniq
427 // Set<Port> prevPorts = new HashSet<>();
428 // CollectionUtils.addAll(prevAddrs,
429 // deviceToUpdate.getAttachmentPoints()
430 // .iterator());
431 // Set<Port> newPorts = updatedAttachmentPoints;
432 // // delta
433 // @SuppressWarnings("unchecked")
434 // Collection<Port> delPorts = CollectionUtils.subtract(newPorts,
435 // prevPorts);
436 // @SuppressWarnings("unchecked")
437 // Collection<Port> addPorts = CollectionUtils.subtract(prevPorts,
438 // newPorts);
439 //
440 // for (Port p : delPorts) {
441 // device.removeAttachmentPoint(p);
442 // getPortImpl(p).removeDevice(device);
443 // }
444 //
445 // for (Port p : addPorts) {
446 // device.addAttachmentPoint(p);
447 // getPortImpl(p).addDevice(device);
448 // }
449
450 // TODO Auto-generated method stub
451
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800452 }
453
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800454 void removeDevice(DeviceEvent device) {
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -0800455 if (device == null) {
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800456 throw new IllegalArgumentException("Device cannot be null");
457 }
458 // TODO Auto-generated method stub
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800459 }
460
461 private SwitchImpl getSwitchImpl(Switch sw) {
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -0800462 if (sw instanceof SwitchImpl) {
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800463 return (SwitchImpl) sw;
464 }
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800465 throw new ClassCastException("SwitchImpl expected, but found: " + sw);
466 }
467
468 private PortImpl getPortImpl(Port p) {
469 if (p instanceof PortImpl) {
470 return (PortImpl) p;
471 }
472 throw new ClassCastException("PortImpl expected, but found: " + p);
473 }
474
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800475 private LinkImpl getLinkImpl(Link l) {
476 if (l instanceof LinkImpl) {
477 return (LinkImpl) l;
478 }
479 throw new ClassCastException("LinkImpl expected, but found: " + l);
480 }
481
Yuta HIGUCHIc0366272014-02-10 21:04:57 -0800482 private DeviceImpl getDeviceImpl(Device d) {
483 if (d instanceof DeviceImpl) {
484 return (DeviceImpl) d;
485 }
486 throw new ClassCastException("DeviceImpl expected, but found: " + d);
487 }
488
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -0800489 public void loadWholeTopologyFromDB() {
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800490 // TODO this method needs to use East-bound API if we still need this
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -0800491 // XXX clear everything first?
492
493 for (RCSwitch sw : RCSwitch.getAllSwitches()) {
494 try {
495 sw.read();
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800496 // TODO if there is going to be inactive Switch in DB, skip
497 // TODO update other attributes if there exist any
498 putSwitch(new SwitchEvent(sw.getDpid()));
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -0800499 } catch (ObjectDoesntExistException e) {
500 log.error("Read Switch Failed, skipping", e);
501 }
502 }
503
504 for (RCPort p : RCPort.getAllPorts()) {
505 try {
506 p.read();
507
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -0800508 Switch sw = this.getSwitch(p.getDpid());
509 if (sw == null) {
510 log.error("Switch {} missing when adding Port {}",
511 new Dpid(p.getDpid()), p);
512 continue;
513 }
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800514 PortEvent portEvent = new PortEvent(p.getDpid(), p.getNumber());
515 // TODO update other attributes if there exist any
516 putPort(portEvent);
Yuta HIGUCHI765cd0d2014-02-06 12:46:41 -0800517 } catch (ObjectDoesntExistException e) {
518 log.error("Read Port Failed, skipping", e);
519 }
520 }
521
522 // TODO Is Device going to be in DB? If so, read from DB.
523 // for (RCDevice d : RCDevice.getAllDevices()) {
524 // try {
525 // d.read();
526 //
527 // } catch (ObjectDoesntExistException e) {
528 // log.debug("Read Device Failed, skipping", e);
529 // }
530 // }
531
532 for (RCLink l : RCLink.getAllLinks()) {
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800533 try {
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800534 l.read();
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800535
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800536 Switch srcSw = this.getSwitch(l.getSrc().dpid);
537 if (srcSw == null) {
538 log.error("Switch {} missing when adding Link {}",
539 new Dpid(l.getSrc().dpid), l);
540 continue;
541 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800542
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800543 Switch dstSw = this.getSwitch(l.getDst().dpid);
544 if (dstSw == null) {
545 log.error("Switch {} missing when adding Link {}",
546 new Dpid(l.getDst().dpid), l);
547 continue;
548 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800549
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800550 LinkEvent linkEvent = new LinkEvent(l.getSrc().dpid,
551 l.getSrc().number, l.getDst().dpid, l.getDst().number);
552 // TODO update other attributes if there exist any
553 putLink(linkEvent);
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800554 } catch (ObjectDoesntExistException e) {
Yuta HIGUCHI4bfdd532014-02-07 13:47:36 -0800555 log.debug("Delete Link Failed", e);
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800556 }
Jonathan Hart062a2e82014-02-03 09:41:57 -0800557 }
Yuta HIGUCHI80829d12014-02-05 20:16:56 -0800558 }
Yuta HIGUCHIcb951982014-02-11 13:31:44 -0800559
560 /**
561 * Exception to be thrown when Modification to the Network Graph cannot be continued due to broken invariant.
562 *
563 * XXX Should this be checked exception or RuntimeException
564 */
565 public static class BrokenInvariantException extends RuntimeException {
566 private static final long serialVersionUID = 1L;
567
568 public BrokenInvariantException() {
569 super();
570 }
571
572 public BrokenInvariantException(String message) {
573 super(message);
574 }
575 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800576
577 /* ******************************
578 * NetworkGraphDiscoveryInterface methods
579 * ******************************/
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800580
Jonathan Hart22eb9882014-02-11 15:52:59 -0800581 @Override
582 public void putSwitchEvent(SwitchEvent switchEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800583 if (prepareForAddSwitchEvent(switchEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800584 datastore.addSwitch(switchEvent);
585 putSwitch(switchEvent);
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800586 // TODO send out notification
Jonathan Hart22eb9882014-02-11 15:52:59 -0800587 }
588 // TODO handle invariant violation
589 }
590
591 @Override
592 public void removeSwitchEvent(SwitchEvent switchEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800593 if (prepareForRemoveSwitchEvent(switchEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800594 datastore.deactivateSwitch(switchEvent);
595 removeSwitch(switchEvent);
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800596 // TODO send out notification
Jonathan Hart22eb9882014-02-11 15:52:59 -0800597 }
598 // TODO handle invariant violation
599 }
600
601 @Override
602 public void putPortEvent(PortEvent portEvent) {
603 // TODO Auto-generated method stub
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800604
Jonathan Hart22eb9882014-02-11 15:52:59 -0800605 }
606
607 @Override
608 public void removePortEvent(PortEvent portEvent) {
609 // TODO Auto-generated method stub
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800610
Jonathan Hart22eb9882014-02-11 15:52:59 -0800611 }
612
613 @Override
614 public void putLinkEvent(LinkEvent linkEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800615 if (prepareForAddLinkEvent(linkEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800616 datastore.addLink(linkEvent);
617 putLink(linkEvent);
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800618 // TODO send out notification
Jonathan Hart22eb9882014-02-11 15:52:59 -0800619 }
620 // TODO handle invariant violation
621 }
622
623 @Override
624 public void removeLinkEvent(LinkEvent linkEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800625 if (prepareForRemoveLinkEvent(linkEvent)) {
Jonathan Hart22eb9882014-02-11 15:52:59 -0800626 datastore.removeLink(linkEvent);
627 removeLink(linkEvent);
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800628 // TODO send out notification
Jonathan Hart22eb9882014-02-11 15:52:59 -0800629 }
630 // TODO handle invariant violation
631 }
632
633 @Override
Yuta HIGUCHI0be4a662014-02-11 18:01:28 -0800634 public void putDeviceEvent(DeviceEvent device) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800635 // XXX if prepareFor~ method returned false, event should be dropped
Jonathan Hart22eb9882014-02-11 15:52:59 -0800636 // TODO Auto-generated method stub
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800637
Jonathan Hart22eb9882014-02-11 15:52:59 -0800638 }
639
640 @Override
641 public void removeDeviceEvent(DeviceEvent deviceEvent) {
642 // TODO Auto-generated method stub
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800643
Jonathan Hart22eb9882014-02-11 15:52:59 -0800644 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800645
Jonathan Hart22eb9882014-02-11 15:52:59 -0800646 /* *****************
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800647 * Internal methods to maintain invariants of the network graph
Jonathan Hart22eb9882014-02-11 15:52:59 -0800648 * *****************/
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800649
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800650 /**
651 *
652 * @param swEvt
653 * @return true if ready to accept event.
654 */
655 private boolean prepareForAddSwitchEvent(SwitchEvent swEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800656 // No show stopping precondition?
657 // Prep: remove(deactivate) Ports on Switch, which is not on event
658 removePortsNotOnEvent(swEvt);
659 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800660 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800661
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800662 private boolean prepareForRemoveSwitchEvent(SwitchEvent swEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800663 // No show stopping precondition?
664 // Prep: remove(deactivate) Ports on Switch, which is not on event
665 // XXX may be remove switch should imply wipe all ports
666 removePortsNotOnEvent(swEvt);
667 return true;
668 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800669
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800670 private void removePortsNotOnEvent(SwitchEvent swEvt) {
671 Switch sw = switches.get( swEvt.getDpid() );
672 if ( sw != null ) {
673 Set<Long> port_noOnEvent = new HashSet<>();
674 for( PortEvent portEvent : swEvt.getPorts()) {
675 port_noOnEvent.add(portEvent.getNumber());
676 }
677 // Existing ports not on event should be removed.
678 // TODO Should batch eventually for performance?
679 for( Port p : sw.getPorts() ) {
680 if ( !port_noOnEvent.contains(p.getNumber()) ) {
681 PortEvent rmEvent = new PortEvent(p.getSwitch().getDpid(), p.getNumber());
682 // calling Discovery removePort() API to wipe from DB, etc.
683 removePortEvent(rmEvent);
684 }
685 }
686 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800687 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800688
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800689 private boolean prepareForAddPortEvent(PortEvent portEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800690 // Parent Switch must exist
691 if ( getSwitch(portEvt.getDpid()) == null) {
692 return false;
693 }
694 // Prep: None
Jonathan Hart22eb9882014-02-11 15:52:59 -0800695 return true;
696 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800697
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800698 private boolean prepareForRemovePortEvent(PortEvent portEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800699 // Parent Switch must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800700 Switch sw = getSwitch(portEvt.getDpid());
701 if ( sw == null ) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800702 return false;
703 }
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800704 Port port = sw.getPort(portEvt.getNumber());
705 if ( port == null ) {
706 log.debug("Port already removed? {}", portEvt);
707 // let it pass
708 return true;
709 }
710
711 // Prep: Remove Link and Device Attachment
712 for (Device device : port.getDevices()) {
713 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
714 devEvt.addAttachmentPoint(new SwitchPort(port.getSwitch().getDpid(), port.getNumber()));
715 // calling Discovery API to wipe from DB, etc.
716 removeDeviceEvent(devEvt);
717 }
718 Set<Link> links = new HashSet<>();
719 links.add(port.getOutgoingLink());
720 links.add(port.getIncomingLink());
721 for ( Link link : links) {
722 if (link == null ) {
723 continue;
724 }
725 LinkEvent linkEvent = new LinkEvent(link.getSourceSwitchDpid(), link.getSourcePortNumber(), link.getDestinationSwitchDpid(), link.getDestinationPortNumber());
726 // calling Discovery API to wipe from DB, etc.
727 removeLinkEvent(linkEvent);
728 }
Jonathan Hart22eb9882014-02-11 15:52:59 -0800729 return true;
730 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800731
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800732 private boolean prepareForAddLinkEvent(LinkEvent linkEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800733 // Src/Dst Switch must exist
734 Switch srcSw = getSwitch(linkEvt.getSrc().dpid);
735 Switch dstSw = getSwitch(linkEvt.getDst().dpid);
736 if ( srcSw == null || dstSw == null ) {
737 return false;
738 }
739 // Src/Dst Port must exist
740 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
741 Port dstPort = srcSw.getPort(linkEvt.getDst().number);
742 if ( srcPort == null || dstPort == null ) {
743 return false;
744 }
745
746 // Prep: remove Device attachment on both Ports
747 for (Device device : srcPort.getDevices()) {
748 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
749 devEvt.addAttachmentPoint(new SwitchPort(srcPort.getSwitch().getDpid(), srcPort.getNumber()));
750 // calling Discovery API to wipe from DB, etc.
751 removeDeviceEvent(devEvt);
752 }
753 for (Device device : dstPort.getDevices()) {
754 DeviceEvent devEvt = new DeviceEvent(device.getMacAddress());
755 devEvt.addAttachmentPoint(new SwitchPort(dstPort.getSwitch().getDpid(), dstPort.getNumber()));
756 // calling Discovery API to wipe from DB, etc.
757 removeDeviceEvent(devEvt);
758 }
759
760 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800761 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800762
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800763 private boolean prepareForRemoveLinkEvent(LinkEvent linkEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800764 // Src/Dst Switch must exist
765 Switch srcSw = getSwitch(linkEvt.getSrc().dpid);
766 Switch dstSw = getSwitch(linkEvt.getDst().dpid);
767 if ( srcSw == null || dstSw == null ) {
768 return false;
769 }
770 // Src/Dst Port must exist
771 Port srcPort = srcSw.getPort(linkEvt.getSrc().number);
772 Port dstPort = srcSw.getPort(linkEvt.getDst().number);
773 if ( srcPort == null || dstPort == null ) {
774 return false;
775 }
776
777 // Prep: None
778 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800779 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800780
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800781 /**
782 *
783 * @param deviceEvt Event will be modified to remove inapplicable attachemntPoints/ipAddress
784 * @return false if this event should be dropped.
785 */
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800786 private boolean prepareForAddDeviceEvent(DeviceEvent deviceEvt) {
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800787 boolean preconditionBroken = false;
788 ArrayList<PortEvent.SwitchPort> failedSwitchPort = new ArrayList<>();
789 for ( PortEvent.SwitchPort swp : deviceEvt.getAttachmentPoints() ) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800790 // Attached Ports' Parent Switch must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800791 Switch sw = getSwitch(swp.dpid);
792 if ( sw == null ) {
793 preconditionBroken = true;
794 failedSwitchPort.add(swp);
795 continue;
796 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800797 // Attached Ports must exist
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800798 Port port = sw.getPort(swp.number);
799 if ( port == null ) {
800 preconditionBroken = true;
801 failedSwitchPort.add(swp);
802 continue;
803 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800804 // Attached Ports must not have Link
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800805 if ( port.getOutgoingLink() != null || port.getIncomingLink() != null ) {
806 preconditionBroken = true;
807 failedSwitchPort.add(swp);
808 continue;
809 }
810 }
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800811
Yuta HIGUCHI8d762e92014-02-12 14:10:25 -0800812 // Rewriting event to exclude failed attachmentPoint
813 // XXX Assumption behind this is that inapplicable device event should
814 // be dropped, not deferred. If we decide to defer Device event,
815 // rewriting can become a problem
816 List<SwitchPort> attachmentPoints = deviceEvt.getAttachmentPoints();
817 attachmentPoints.removeAll(failedSwitchPort);
818 deviceEvt.setAttachmentPoints(attachmentPoints);
819
820 if ( deviceEvt.getAttachmentPoints().isEmpty() && deviceEvt.getIpAddresses().isEmpty() ) {
821 // XXX return false to represent: Nothing left to do for this event. Caller should drop event
822 return false;
823 }
824
825 // Should we return false to tell caller that the event was trimmed?
826 // if ( preconditionBroken ) {
827 // return false;
828 // }
829
830 return true;
Jonathan Hart22eb9882014-02-11 15:52:59 -0800831 }
Yuta HIGUCHIcd922f42014-02-11 18:59:11 -0800832
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800833 private boolean prepareForRemoveDeviceEvent(DeviceEvent deviceEvt) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800834 // No show stopping precondition?
835 // Prep: none
Jonathan Hart22eb9882014-02-11 15:52:59 -0800836 return true;
837 }
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800838
839 @Override
840 public void putSwitchReplicationEvent(SwitchEvent switchEvent) {
Yuta HIGUCHId02e9282014-02-12 09:24:41 -0800841 if (prepareForAddSwitchEvent(switchEvent)) {
Yuta HIGUCHI928fa682014-02-11 19:07:57 -0800842 putSwitch(switchEvent);
843 }
844 // TODO handle invariant violation
845 }
846
847 @Override
848 public void removeSwitchReplicationEvent(SwitchEvent switchEvent) {
849 // TODO Auto-generated method stub
850
851 }
852
853 @Override
854 public void putPortReplicationEvent(PortEvent portEvent) {
855 // TODO Auto-generated method stub
856
857 }
858
859 @Override
860 public void removePortReplicationEvent(PortEvent portEvent) {
861 // TODO Auto-generated method stub
862
863 }
864
865 @Override
866 public void putLinkReplicationEvent(LinkEvent linkEvent) {
867 // TODO Auto-generated method stub
868
869 }
870
871 @Override
872 public void removeLinkReplicationEvent(LinkEvent linkEvent) {
873 // TODO Auto-generated method stub
874
875 }
876
877 @Override
878 public void putDeviceReplicationEvent(DeviceEvent deviceEvent) {
879 // TODO Auto-generated method stub
880
881 }
882
883 @Override
884 public void removeDeviceReplicationEvent(DeviceEvent deviceEvent) {
885 // TODO Auto-generated method stub
886
887 }
Jonathan Hart062a2e82014-02-03 09:41:57 -0800888}